Skip to content

feat: update state representation of seg layer for skeletons#145

Merged
afonsobspinto merged 14 commits intofeature/edit-modefrom
feat/NA-641
May 5, 2026
Merged

feat: update state representation of seg layer for skeletons#145
afonsobspinto merged 14 commits intofeature/edit-modefrom
feat/NA-641

Conversation

@seankmartin
Copy link
Copy Markdown

@seankmartin seankmartin commented May 1, 2026

The primary goal of this is to remove a decent portion of what was stored in the JSON state previously for spatial skeletons. The first part of this is to remove the inferred values that were serialized in the JSON state. The user can only directly change the 2D and 3D grid level targets from the UI. All other values around this, such as the LOD and actual chosen grid level are inferred, and should not be stored in the JSON state. Because the user can now only change these targets (they could previously change the other values in the state, even if not in the UI) we can simplify the restoration and handling of these values as there is a clearer and easier to handle flow of information.

The second part of removing what was stored in the state is to remove the relative/non-relative checkbox state. This is instead going to be inferred from the zoom-relative setting on panels by using information about the near-far plane distance. Fixing this has not been included in this PR, just removing the relative handling. New relative handling will come later, likely alongside changes to what the target value units are (likely px).

Removing this state lead to some knock on changes for parts of the code that appear to have been setup to support these settings. I've commented a few places in github about what was removed. But in summary:

  1. The render scale widget subclass for spatial skeletons can be simplified. We don't need a lot of the custom functionality or styling. This also means we don't need the chunk tracking that was in place previously for informing the render scale widget (at least as far as I can tell - we can restore some of this if needed for a different purpose). We can track this via the regular method of the render scale histogram and the chunk stats.
  2. The serializing and restoration of state for spatial skeletons is much more minimal and can be kept inline instead of needing custom functions and module for this.
  3. With these changes, the draw method on some of the new layer types becomes a stub. Before this PR had already been exploring consolidating these in claude generated: experiment with consolidating layers #147 but this might make that more tenable.

will need to update the logic after this, but this moves to the version of the state
where the user controlled value is the only thing stored in the state, and everything
else needed for the computation is derived from this single control

this will require updates in segmentation/index.ts further and then in
skeleton/frontend.ts as some of the old things there won't be used
the old was adding custom css and behaviour but we can rely on the base instead for
simplicity
on simplifing the render scale widget, I believe there is a good chunk of dead code. I
don't think we need this as it should be handled separately.
Copy link
Copy Markdown
Author

@seankmartin seankmartin left a comment

Choose a reason for hiding this comment

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

I wanted to make some pointers about this. I also wanted to note that the reason this touches so much in the frontend code is that when the chunk stats are not passed to the render scale widget, they appear to be fully unusued.

So removing the state, meant the render scale widget didn't need customisation. And I didn't want to leave around the now seemingly dead code for the stats after that (though it's possible there is still some or I'm missing a different way it is used).

}));
}

function findClosestSpatialSkeletonGridLevel(
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

removed in favor of always finding by spacing

this.spatialSkeletonGridResolutionTarget3dExplicit = true;
this.applySpatialSkeletonGridResolutionTarget("3d");
});
this.spatialSkeletonGridResolutionRelative2d.changed.add(() => {
Copy link
Copy Markdown
Author

@seankmartin seankmartin May 4, 2026

Choose a reason for hiding this comment

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

Removed these listeners in general as relative removed, both 2d and 3d

Comment on lines -865 to -891
this.spatialSkeletonGridPixelSize2d.changed.add(() => {
if (this.spatialSkeletonGridResolutionRelative2d.value) {
this.applySpatialSkeletonGridResolutionTarget("2d");
}
});
this.spatialSkeletonGridPixelSize3d.changed.add(() => {
if (this.spatialSkeletonGridResolutionRelative3d.value) {
this.applySpatialSkeletonGridResolutionTarget("3d");
}
});
this.spatialSkeletonGridLevel2d.changed.add(() => {
if (this.suppressSpatialSkeletonGridLevel2d) return;
if (this.spatialSkeletonGridLevels.value.length === 0) return;
this.setSpatialSkeletonGridLevel(
"2d",
this.spatialSkeletonGridLevel2d.value,
true,
);
});
this.spatialSkeletonGridLevel3d.changed.add(() => {
if (this.suppressSpatialSkeletonGridLevel3d) return;
if (this.spatialSkeletonGridLevels.value.length === 0) return;
this.setSpatialSkeletonGridLevel(
"3d",
this.spatialSkeletonGridLevel3d.value,
true,
);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

removed as no longer changable by user, only 2d and 3d targets are

Comment on lines -935 to -942
spatialSkeletonGridChunkStats2d = new WatchableValue({
presentCount: 0,
totalCount: 0,
});
spatialSkeletonGridChunkStats3d = new WatchableValue({
presentCount: 0,
totalCount: 0,
});
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Updating how these chunk stats work, I think we can be more integrated with neuroglancer. Still ensuring I've done this right to be honest.

Comment on lines -953 to -956
private spatialSkeletonGridLevel2dExplicit = false;
private spatialSkeletonGridLevel3dExplicit = false;
private suppressSpatialSkeletonGridLevel2d = false;
private suppressSpatialSkeletonGridLevel3d = false;
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

our logic can be simpler now that we only have two possible user controls.

Comment on lines +2176 to +2181
x[json_keys.HIDDEN_OPACITY_3D_JSON_KEY] =
this.displayState.hiddenObjectAlpha.toJSON();
x[json_keys.SKELETON_CROSS_SECTION_RENDER_SCALE_JSON_KEY] =
this.displayState.spatialSkeletonGridResolutionTarget2d.toJSON();
x[json_keys.SKELETON_PERSPECTIVE_RENDER_SCALE_JSON_KEY] =
this.displayState.spatialSkeletonGridResolutionTarget3d.toJSON();
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

since we serialize a lot less now, I don't think it needs its own module or tests or custom fns

Comment thread src/skeleton/frontend.ts
| undefined;
const spatialDisplayState = displayState as SegmentationDisplayState &
SpatialSkeletonDisplayState;
const anyDisplayState = displayState as any;
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

later aim to fix this, but for now at least the cast happens once

Comment thread src/skeleton/frontend.ts
);
}

private updateChunkStatsWatchable() {
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Tried to remove a lot of code related to the histogram updates, I think this is more broadly handled. Related to previous comment, still verifying

Comment thread src/skeleton/frontend.ts
),
);
}
draw(_renderContext: SliceViewRenderContext) {}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Without updating chunk stats, these draw methods become stubs. It's possible some level of consolidation between layers could happen. That was briefly explored in #147 to see if it caused any major bugs but hit the token limit. can try to continue that experiment another time.

this.logScaleBinSize = this.histogram.logScaleBinSize;
}

constructor(
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

We don't need a lot of this custom functionality after removing the relative checkbox and trying to use the histogram more directly instead of the chunk stats.

@seankmartin
Copy link
Copy Markdown
Author

The one part of this which is a bit awkward is that you can now have something off the scale. However, I believe the real fix for that will be us changing the target value to something in pixels, and then won't need

  setSpatialSkeletonGridSizes(gridSizes: SpatialSkeletonGridSize[]) {
    const sortedSizes = [...gridSizes].sort(
      (a, b) => Math.min(b.x, b.y, b.z) - Math.min(a.x, a.y, a.z),
    );
    const levels = buildSpatialSkeletonGridLevels(sortedSizes);
    const { origin: histogramOrigin, binSize: histogramBinSize } =
      getSpatialSkeletonGridHistogramConfig(levels);
    if (
      this.spatialSkeletonGridRenderScaleHistogram2d.logScaleOrigin !==
        histogramOrigin ||
      this.spatialSkeletonGridRenderScaleHistogram2d.logScaleBinSize !==
        histogramBinSize
    ) {
      this.spatialSkeletonGridRenderScaleHistogram2d.logScaleOrigin =
        histogramOrigin;
      this.spatialSkeletonGridRenderScaleHistogram2d.logScaleBinSize =
        histogramBinSize;
      this.spatialSkeletonGridRenderScaleHistogram2d.changed.dispatch();
    }
    if (
      this.spatialSkeletonGridRenderScaleHistogram3d.logScaleOrigin !==
        histogramOrigin ||
      this.spatialSkeletonGridRenderScaleHistogram3d.logScaleBinSize !==
        histogramBinSize
    ) {
      this.spatialSkeletonGridRenderScaleHistogram3d.logScaleOrigin =
        histogramOrigin;
      this.spatialSkeletonGridRenderScaleHistogram3d.logScaleBinSize =
        histogramBinSize;
      this.spatialSkeletonGridRenderScaleHistogram3d.changed.dispatch();
    }
    this.spatialSkeletonGridLevels.value = levels;

because our histogram will be in an expected range

@seankmartin seankmartin requested a review from afonsobspinto May 5, 2026 08:07
@seankmartin seankmartin marked this pull request as ready for review May 5, 2026 08:07
@afonsobspinto afonsobspinto merged commit b662b52 into feature/edit-mode May 5, 2026
1 check passed
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.

2 participants