Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-scene collections #362

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open

Multi-scene collections #362

wants to merge 21 commits into from

Conversation

frasercl
Copy link
Contributor

@frasercl frasercl commented Feb 13, 2025

Review time: medium (~20-30min)

Problem

Scientists want a way to view multiple images collected along a "scenes" dimension. This PR gets us to basic support for that.

Resolves #351: adds a new "Scene" slider to the clipping panel.

Additionally, resolves allen-cell-animated/vole-core#275. Most of the work on this ticket was finished in allen-cell-animated/vole-core#279 — that PR described the remaining work as creating a new data structure or framework to gather multiple data sources into a single multi-scene collection. This PR includes that: the SceneStore class, described below.

Solution

  • Add a new SceneStore class, which manages creating and swapping out loaders for different scenes, and which replaces the single loader that the App component used to hold onto.
  • Add new semantics for App props to support describing multi-scene collections, and new semantics to URL parameters to parse out those props
  • Add a scene slider to the clipping panel, which appears when viewing a multi-scene collection. Because the clipping panel is too short by default to contain an X, Y, Z, time, and scene slider all at once, the panel now grows taller when all these sliders are present.

Remaining work

This implementation deliberately performs minimal validation. For example, it will fall over when successive scenes have a different number of channels. We consider this acceptable while we're demoing this feature to scientists, since this feature isn't exposed to users in any prominent way. This remaining work is captured in allen-cell-animated/vole-core#277.

Steps to verify

Screenshot

image

Copy link

github-actions bot commented Feb 13, 2025

PR Preview Action v1.4.8
🚀 Deployed preview to https://allen-cell-animated.github.io/vole-app/pr-preview/pr-362/
on branch gh-pages at 2025-03-11 01:11 UTC

@frasercl frasercl marked this pull request as ready for review February 17, 2025 17:48
@frasercl frasercl requested a review from a team as a code owner February 17, 2025 17:48
@frasercl frasercl requested review from toloudis and ShrimpCryptid and removed request for a team February 17, 2025 17:48
const [image, setImage] = useState<Volume | null>(null);
const imageUrlRef = useRef<string | string[]>("");
const imageUrlRef = useRef<string | (string | string[])[]>("");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this T | (T | T[])[] i see used a couple of places. Wondering about some readable alias like "valueOrArrayOrArray2D". even T | T[] | T[][] looks simpler to read

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I even wonder if there's a way to formalize it with a simple construct like

type Scene {
  sources: string[];
}

instead of carrying these weird arrays around.
Then the url parsing can just fill an array of Scenes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did roughly the second thing above

const imageUrls = tryDecodeURLList(params.url) ?? decodeURL(params.url);
const firstUrl = Array.isArray(imageUrls) ? imageUrls[0] : imageUrls;
const sceneUrls = tryDecodeURLList(params.url, " ") ?? [params.url];
const sourceUrls = sceneUrls.map((scene) => tryDecodeURLList(scene) ?? [decodeURL(scene)]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this supposed to give you every source url of every scene? I guess I don't know what tryDecodeUrlList can return . I assume decodeURL returns a single string?


const firstScene = sourceUrls[0];
const firstUrl = Array.isArray(firstScene) ? firstScene[0] : firstScene;
const imageUrls = sourceUrls.length === 1 ? (sourceUrls[0].length === 1 ? firstScene[0] : firstScene) : sourceUrls;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it has become too hard to parse these 5 lines. I think types on the variable declarations would help to understand. And maybe rename imageUrls and firstUrl to be imageUrlsOfFirstScene and firstUrlOfFirstScene? if that's even accurate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My little refactor didn't make this much better, but I did add some docs and a type signature. Let me know if there's more I can do?

props;
const clippingPanelTall = numTimesteps > 1 && numScenes > 1 && viewMode === ViewMode.threeD;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check happens in two places... For DRY, should it just be a single flag that's passed in as a prop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thought here was that, since this property is derivable from other passed properties, it was better not to pass it in explicitly and risk an "invalid" value. Though this value has less of a strong notion of "invalid" than, say, a string along with an isAllCaps: boolean value. So maybe it would be better?

@frasercl frasercl requested a review from toloudis March 11, 2025 01:11
@frasercl frasercl requested a review from ShrimpCryptid March 11, 2025 01:11
Copy link
Contributor

@ShrimpCryptid ShrimpCryptid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some final questions but I like the new way of representing multiscenes.

Comment on lines +257 to +259
const urls = (appProps.imageUrl as MultisceneUrls).scenes ?? [appProps.imageUrl];
const sceneUrlsUnencoded = urls.map((scene) => (Array.isArray(scene) ? scene.join(",") : scene));
navigation(`/viewer?url=${encodeURIComponent(sceneUrlsUnencoded.join(" "))}`, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this code is copied with AppWrapper maybe it's worth putting in a function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Multiscene UI Multiscene loading
3 participants