Add CSV export to NX Line (and other export improvements)#1763
Conversation
|
/approve |
loichuder
left a comment
There was a problem hiding this comment.
That looks quite good!
There are a few things that bother me a bit:
- The implicit coupling between the
formatsand the record of built-in exporters passed touseExportEntries - Depending on where you look in the code, it can be difficult to know the priority between
getExportURL,_getExportURLand the built-in exporter.
But all and all, the fact that this PR addresses several long-standing and difficult issues at once is a testimony of its relevance.
8099bd0 to
1350e7f
Compare
1350e7f to
536c8ad
Compare
|
I've updated the documentation of the
Agreed, not perfect, but the types ensure that the exporter record cannot contain formats that are not in the
Totally agree as well, it gets quite confusing. This actually prompted me to update the documentation of the Eventually I'm hoping to at least remove the However, simply adding an |
b886444 to
32dc759
Compare
CSV export for NX Line
The following columns are exported, in order, when the corresponding datasets are present in the
NXdatagroup: values, abscissas, errors, aux1, aux1 errors, aux2, aux2 errors, ... For instance, with mock dataset/nexus_entry/spectrum_with_aux, the CSV file looks like this:Additional improvements
Built-in, provider-agnostic CSV and JSON exports
CSV and JSON exports are now built into the viewer, which means that consumer applications (VS Code, myHDF5, etc.) no longer have to implement them themselves. All that's needed is for providers to include a very basic implementation of the
getExportURLmethod internally.Thanks to this, the four provider demos (h5grove, h5wasm, HSDS and mock) now all support exporting to CSV/JSON and do so in a consistent way — i.e. the CSV is always generated locally (it used to be generated remotely in the h5grove demo).
Export compound scalar/array datasets to CSV
Respect transposition when exporting 2D dataset to CSV in Matrix vis
Summary
The tables below summarise export capabilities out of the box before/after this PR for every visualization/format/provider combination. "Out of the box" means without any consumer-provided export implementation.
BEFORE
H5GroveProviderH5WasmProviderHsdsProviderMockProviderAFTER
H5GroveProviderH5WasmProviderHsdsProviderMockProviderImplementation
Challenges and early attempts
Providers shouldn't know about NeXus, so I discarded the following solutions quickly:
getExportURL) along with the main dataset'svalue;NXdatametadata and letting the provider get the values again internally.👉 NeXus exports have to be generated in the viewer (well, at least the export generation functions have to be prepared in the viewer...)
Currently, providers all accept a
getExportURLprop, which enables a lot of different scenarios: it allows consumers to generate the exports themselves, to generate one-time download links, etc. It's also what allows exports to work in the VS Code extension, as the webview has to generate the export payload and send it to the extension host so it can be saved to disk.Being able to implement NPY and TIFF exports in the viewer to get rid of
getExportURLentirely would have made things a lot easier. After all, we already retrieve the data from the providers, so in a way, they've already done their job. I would then have provided another kind of API to allow consumers of theAppcomponent to customise the exports and hook onto the exports process — providers would no longer have had anything to do with exports... Of course I discarded this option as well, as generating NPY and TIFF in JS is not trivial, and it's not really something we want to maintain long-term.So there wasn't really any other option than to find a way to mix both viewer-side generation and provider-side generation, while continuing to provide flexibility for consumers.
I tried generating export entries both in the providers and in the viewers and then merging them, but this made it really hard to comprehend which exports would end up available in each visualization.
Proposed solution
In the end, I settled on a solution that involves passing an "exporter" function to
getExportURLinstead of the rawvaluearray.I introduce a hook called
useExportEntriesthat I call from the mapped components. Internally, it callsgetExportURL, passing the exporter for the given format if any:In the providers, I then make sure to return an
ExportURLfunction that callsbuiltInExporterif it's defined: