Giter Club home page Giter Club logo

viv's Introduction

Viv npm version package documenation

A WebGL-powered toolkit for interactive visualization of high-resolution, multiplexed bioimaging datasets.

Interactive volumetric view in web browser; sliders control visible planes. Multi-channel rendering of high-resolution microscopy dataset

About

Viv is a JavaScript library for rendering OME-TIFF and OME-NGFF (Zarr) directly in the browser. The rendering components of Viv are packaged as deck.gl layers, making it easy to compose with existing layers to create rich interactive visualizations.

More details and related work can be found in our paper and original preprint. Please cite our paper in your research:

Trevor Manz, Ilan Gold, Nathan Heath Patterson, Chuck McCallum, Mark S Keller, Bruce W Herr II, Katy BΓΆrner, Jeffrey M Spraggins, Nils Gehlenborg, "Viv: multiscale visualization of high-resolution multiplexed bioimaging data on the web." Nature Methods (2022), doi:10.31219/10.1038/s41592-022-01482-7

πŸ’» Related Software

Screenshot Description
Avivator viewer running in Chrome Avivator
A lightweight viewer for local and remote datasets. The source code is include in this repository under avivator/. See our πŸŽ₯ video tutorial to learn more.
Vizarr viewer running in Jupyter Notebook Vizarr
A minimal, purely client-side program for viewing OME-NGFF and other Zarr-based images. Vizarr supports a Python backend using the imjoy-rpc, allowing it to not only function as a standalone application but also directly embed in Jupyter or Google Colab Notebooks.

πŸ’₯ In Action

πŸ’Ύ Supported Data Formats

Viv's data loaders support OME-NGFF (Zarr), OME-TIFF, and Indexed OME-TIFF*. We recommend converting proprietrary file formats to open standard formats via the bioformats2raw + raw2ometiff pipeline. Non-pyramidal datasets are also supported provided the individual texture can be uploaded to the GPU (< 4096 x 4096 in pixel size).

Please see the tutorial for more information.

*We describe Indexed OME-TIFF in our paper as an optional enhancement to provide efficient random chunk access for OME-TIFF. Our approach substantially improves chunk load times for OME-TIFF datasets with large Z, C, or T dimensions that otherwise may incur long latencies due to seeking. More information on generating an IFD index (JSON) can be found in our tutorial or documentation.

πŸ’½ Installation

$ npm install @hms-dbmi/viv

You will also need to install deck.gl and other peerDependencies manually. This step prevent users from installing multiple versions of deck.gl in their projects.

$ npm install deck.gl @luma.gl/core

Breaking changes may happen on the minor version update. Please see the changelog for information.

πŸ“– Documentation

Detailed API information and example sippets can be found in our documentation.

πŸ—οΈ Development

This repo is a monorepo using pnpm workspaces. The package manager used to install and link dependencies must be pnpm.

Each folder under packages/ are a published as a separate packages on npm under the @vivjs scope. The top-level package @hms-dbmi/viv exports from these dependencies.

To develop and test the @hms-dbmi/viv package:

  1. Run pnpm install in viv root folder
  2. Run pnpm dev to start a development server
  3. Run pnpm test to run all tests (or specific, e.g., pnpm test --filter=@vivjs/layers)

πŸ› οΈ Build

To build viv's documentation and the Avivator website (under sites/), run:

pnpm build # all packages, avivator, and documentation
pnpm -r build --filter=avivator # build a specific package or site

πŸ“„ Sending PRs and making releases

For changes to be reflected in package changelogs, run npx changeset and follow the prompts.

Note not every PR requires a changeset. Since changesets are focused on releases and changelogs, changes to the repository that don't effect these won't need a changeset (e.g., documentation, tests).

The Changesets GitHub Action will create and update a PR that applies changesets versions of @vivjs/ packages to NPM.

🌎 Browser Support

Viv supports both WebGL1 and WebGL2 contexts, to provides coverage across Safari, Firefox, Chrome, and Edge. Please file an issue if you find a browser in which Viv does not work.

viv's People

Contributors

andreasg123 avatar anton-slashm avatar dependabot[bot] avatar ericmoerthvis avatar github-actions[bot] avatar hkmoon avatar ilan-gold avatar keller-mark avatar manzt avatar mccalluc avatar ndrezn avatar ngehlenborg avatar nickakhmetov avatar oeway avatar rj3d avatar rogertrullo avatar s-n-i avatar sunyi000 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

viv's Issues

Investigate for-loop array access

Through my tinkering, I have noticed that accessing an uniform array (i.e provided from the program) in the fragment shader's for-loop is quite expensive (my computer's fan really kicks in). We should ideally figure out why this is happening and if it can be worked around as arrays are far more pleasant to look at/read than what we have now. This will also allow us to scale much better. Potential options that I have done no real digging into include:

  • dynamically creating the shader code so we don't need arrays (I have my suspicions)
  • fixing the potential underlying problem (a parameter we don't know of? a different way of structuring data?)
  • creating an array of structs that have color, texture, and slider values(is this any better?)
  • Punting, and accepting that we will have a fixed number of channels, which could be very high though - (repeated) code is cheap!
  • something else entirely

Warnings from `build-component`

Package may or may not work, but it would be good to clear up warnings, regardless:

$ npm run-script build-component

> @hubmap/[email protected] build-component /Users/chuck/github/hubmap/vitessce-image-viewer
> rm -r dist && rollup -c


src/index.js β†’ dist/index.js, dist/index.es.js...
(!) Plugin node-resolve: preferring built-in module 'fs' over local alternative at 'fs', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning
(!) Plugin node-resolve: preferring built-in module 'util' over local alternative at '/Users/chuck/github/hubmap/vitessce-image-viewer/node_modules/util/util.js', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning
(!) Plugin node-resolve: preferring built-in module 'module' over local alternative at 'module', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning
(!) Plugin node-resolve: preferring built-in module 'path' over local alternative at 'path', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning
(!) Circular dependencies
node_modules/@loaders.gl/core/dist/esm/lib/parse.js -> node_modules/@loaders.gl/core/dist/esm/lib/loader-utils/parse-with-worker.js -> node_modules/@loaders.gl/core/dist/esm/lib/parse.js
node_modules/@luma.gl/gltools/dist/esm/state-tracker/unified-parameter-api.js -> node_modules/@luma.gl/gltools/dist/esm/state-tracker/track-context-state.js -> node_modules/@luma.gl/gltools/dist/esm/state-tracker/unified-parameter-api.js
node_modules/@luma.gl/webgl/dist/esm/webgl-utils/texture-utils.js -> node_modules/@luma.gl/webgl/dist/esm/classes/texture-2d.js -> node_modules/@luma.gl/webgl/dist/esm/classes/texture.js -> node_modules/@luma.gl/webgl/dist/esm/classes/resource.js -> node_modules/@luma.gl/webgl/dist/esm/webgl-utils/index.js -> node_modules/@luma.gl/webgl/dist/esm/webgl-utils/texture-utils.js
...and 5 more
(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
fs (imported by node_modules/@loaders.gl/core/dist/esm/node/read-file-sync.node.js, node_modules/@loaders.gl/core/dist/esm/node/write-file.node.js)
util (imported by node_modules/@loaders.gl/core/dist/esm/node/write-file.node.js)
module (imported by node_modules/@loaders.gl/loader-utils/dist/esm/lib/library-utils/require-utils.node.js)
path (imported by node_modules/@loaders.gl/loader-utils/dist/esm/lib/library-utils/require-utils.node.js)
(!) Import of non-existent export
node_modules/@math.gl/culling/dist/esm/lib/plane.js
1: import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
2: import _createClass from "@babel/runtime/helpers/esm/createClass";
3: import { Vector3, equals as _equals, assert, MathUtils } from 'math.gl';
                                                ^
4: var scratchPosition = new Vector3();
5: var scratchNormal = new Vector3();
created dist/index.js, dist/index.es.js in 6s

Resolve Image Wrapping in TIFF

The image appears to wrap when using TIFF. My hunch (based on some investigation) is that the geotiff.js library is requesting too much data, which means we might need to make a PR into their repo.

Screen Shot 2020-02-18 at 10 22 15 AM

Create color range mappings

User story
We need a way to map n colors to n separate 0 - (1 - 2^b) (where b is number of bits per channel) ranges and vice-versa to allow for many color channels. This will require some research into color mappings and glsl.

Add background image

This will make panning look better as well as zooming until we change the cache to rely on rendering instead of loading the data.

Add in a scale bar

Take scale from metadata and render it as a little yard-stick in the viewer

Clean up the vertex shader

The vertex shader is essentially a clean pull from deckgl's BitmapLayer and I don't think all of it is necessary.

Add heuristic logic for different zarr pyramids

Originally posted by @mccalluc in #81

Currently all channels of the pyramid for the zarr example are stored as [4, 512, 512] "tiles", where the first dimension is the channel. This makes for fewer requests, but we want to add some logic for determining how to initialize the zarr connections if these are separate pyramids (similiar to the Tiff example).

We assume that the chunking is this way at the moment, but it should be simple to add some logic. If the urls in the config for the incoming sourceChannels are all the same, assume same pyramid and respect the ordering of the channels. If sourceChannels have different urls, initialize separate pyramids.

add a blurb to demo

When the demo is pushed out, we need a little bit of information about what you're seeing on the page, perhaps above the controls? Something like:

vitessce-image-viewer ("Viv")

A viewer for high bit depth, high resolution, multi-channel images using DeckGL over the hood and WebGL under the hood. More information and documentation on github.

Update Channel Metadata/Switching

  • We want the names of channels to be determined by what is in source-info.js i.e the keys of the url.
  • Also We want to be able to turn channels on/off (by passing down a [0,0,0] color to its color).

I'm lumping these together because they are conceptually similar.

single_channel_pyramid doesn't work?

When I swap the commenting in source-info.js, I just get an error from geotiff.bundle.min.js. Is this a regression, or is there some other change I need to make at the same time?

Linting

Eslint has worked for me... but if you find something newer and better, great. (Strongly prefer CI checks to just relying on pre-commit hooks, but they could be complementary.)

Bundle a TIFF accessor function

At the minimum, bundle with a non-tiling GeoTIFF accessor function. Optimally, we would get tiling working, but the leap to that isn't going to be much more.

UseCamelCaseIfTheFileJustHasOneExport.js

  • Makes it easy to identify where something comes from.
  • Distinguish single-export files from utils.
  • Typically, we'll be using default exports, so being out of sync isn't an issue... but it will be nice to know what we should name it on import.

@ilan-gold : Is this ok with you?

Do we need both webpack and rollup?

I understand that webpack is doing the demo and rollup is doing the packaging... but it feels like we should be able to use one build tool, even if two separate configs are necessary? I'm guessing webpack came from the CRA, but rollup is easier to configure for packaging?

My mental model is that both tools are pretty much in the same space? Scenarios I'd worry about: β€’ Someone needs to fix the build, and they end up in the wrong config file, and none of their changes seem to make a difference.
β€’ We need new language features, and we have to figure out how to get them working in both tools.

Bundle should not include src

And maybe it should be rooted at dist, and not just include it?

$ npm publish --access public
npm notice
npm notice πŸ“¦  @hubmap/[email protected]
npm notice === Tarball Contents ===
npm notice 1.1kB LICENSE
npm notice 1.6MB dist/index.es.js
npm notice 1.6MB dist/index.js
npm notice 56B   src/data-utils/index.js
npm notice 214B  src/index.js
npm notice 38B   src/XRLayer/index.js
npm notice 1.6kB src/microscopy-viewer-layer.js
npm notice 2.2kB src/microscopy-viewer.js
npm notice 2.0kB src/tiling-utils.js
npm notice 2.3kB src/XRLayer/xr-layer-fragment.js
npm notice 493B  src/XRLayer/xr-layer-vertex.js
npm notice 5.1kB src/XRLayer/xr-layer.js
npm notice 1.6kB src/data-utils/zarr-utils.js
npm notice 2.1kB package.json
npm notice 3.5MB dist/index.es.js.map
npm notice 3.5MB dist/index.js.map
npm notice 3.2kB README.md
npm notice === Tarball Details ===
npm notice name:          @hubmap/vitessce-image-viewer
npm notice version:       0.0.1
npm notice package size:  1.8 MB
npm notice unpacked size: 10.1 MB
npm notice shasum:        c830bc13561b98a788939e51a0bcdd5646f656b6
npm notice integrity:     sha512-8YsHUvxnrF7bL[...]wZch5rTj9GnYQ==
npm notice total files:   17
npm notice
+ @hubmap/[email protected]

Compiling/Building Shaders with GLSL

User story
Through my journey, I have noticed there is more than one way of bringing shaders into your project. This should be thoroughly investigated and a solution settled on that makes the most sense with our needs.
Preferred solution

Possible alternatives

Some tests

Rather than a really high degree of coverage, I would suggest getting at least a few simple tests in at different levels. If bugs are fixed in the future, we don't want the bug-fixer to also have the responsibility for setting up the test infrastructure in the first place.

  • unit tests for math
  • cypress, maybe?
  • something in between

Improve zarr/tiff connection caching

Both zarr.js and geotiff.js rely on a metadata-like object (fetched) to give the necessary information for fetching the underlying data. We should write something to cache this data as it only needs to really be fetched once.

Demo

The Vitessce approach of demo versions unconnected to NPM versions is not something to emulate. On the other hand, Alex with 4DN has put demos into the NPM release, and you can view it via unpkg, ie: https://unpkg.com/@hms-dbmi-bgm/[email protected]/index.html

Serving gh-pages from a docs directory, which in turn references unpkg and npm is another option.

It would be good if the same demo code that gets built and deployed could also be used for local development.

In demo, reverse direction of sliders?

I'm expecting the picture to get brighter as the sliders go up (and the thick part of the slider gets longer). I'm also not sure that the numbers in the control are useful... but maybe they are during development?

Should Deck.gl be a peer dependency?

mccalluc

Do we want to move @deck.gl/* into peer dependencies? Vitessce itself will have these, and if the versions do diverge, I don’t want to be bundling multiple versions of a big dependency.
but not a blocker now.

Ilan Gold

I don't think so. We want the package to be usable without a @deck.gl component already existing. I don't think people look at peerDependency warnings but I might have that wrong.
I suppose we could just make it clear in the docs that you absolutely need to install your own @deck.gl to use the standalone version.

Switch to 512x512 size tiles

Try converting to 512x512 size tiles. Mapbox switched to 512x512 tiles a while back and said it improved performance.

More object-oriented data utilities

Right now we support tiff and zarr as formats, but in the future others could have data in a different format and we should expose the ability to create custom getters for the data. I think we should standardize how these data utilities work and what they must implement to plugin with the viewer. We shouldn't be dumping everything in state in React if these aren't going to change for a layer.

PR #81 puts a foot forward in this direction but I would ultimately like to see this implemented as a class. I'm a bit tired so maybe I'm thinking about this wrong; any feedback is appreciated!

class ImageLoader {
  constructor(connections, minZoom, imageWidth, imageHeight, tileSize, channels) {
    // required state for zarr
    this.connections = connections;
    this.minZoom = minZoom;
    this.imageWidth = imageWidth;
    this.imageHeight = imageHeight;
    this.tileSize = tileSize;
    this.channels = channels;
  }

  async initilize() {
    // Perform work to get connections, minZoom, imageWidth, imageHeight, tileSize
    throw Error("Need to implement .initilize method");
  }

  async getTile() {
    // Perform logic to get tile from data-specific connections
    throw Error("Need to implement .getTile method");
  }
}

class ZarrLoader extends ImageLoader {
  async initilize({ channelSources }) {
    // carry out logic for creating array, getting connections, etc...

    // returns Promise for that loader
    // We just have React manage the Loader instance, rather than passing around these params.
    return new ZarrLoader(connections, minZoom, imageWidth, imageHeight, tileSize, channels)
  }
  async getTile({ x, y, z }) {
    // e.g
    const tiles = []
    for (let i = 0; i < this.channels.length; i++) {
      const tile = this.connections[z].getRawChunk([0, y, x]);
      tiles.push(tile);
    }
    const resolved = await Promise.all(tiles);
    return resolved;
  }
}

That way in microscopy-base-layer we can use:

ZarrLoader.intilize({...props}).then(loader => this.setState({loader}));

Why do we get peer dependency warnings in development?

To take the first one off the list:

npm WARN @deck.gl/[email protected] requires a peer of @deck.gl/core@^8.0.0 but none is installed. You must install peer dependencies yourself.

Why does this happen? It seems to be in place:

grep version 'node_modules/@deck.gl/core/package.json'
  "version": "8.1.0-alpha.1"

And in any event, it seems to be working?

Toggling one channel lowers brightness of other channels

  • Load the demo with the default zarr.
  • The image has a greenish cast, with blue dots
  • Toggle off DAPI (blue).

I would expect the green areas to stay the same, but instead it goes to all black. If I lower the right end of the green slider to 3500 I start to get back to something like the original, but the color scale is more abrupt: The darker areas are darker than in the original, while the brights are brighter.

Upgrade DeckGL to 8.1

We are currently on an alpha branch and will need to upgrade DeckGL off that once it is no longer needed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.