Skip to content

Commit

Permalink
Merge pull request #1738 from girder/jupyter-frame-selector
Browse files Browse the repository at this point in the history
Jupyter Frame Selector component
  • Loading branch information
annehaley authored Jan 28, 2025
2 parents 4b2b390 + 65596a4 commit 489dbb9
Show file tree
Hide file tree
Showing 23 changed files with 712 additions and 504 deletions.
4 changes: 2 additions & 2 deletions girder/girder_large_image/web_client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"jsonlint-mod": "^1.7.6",
"sinon": "^2.1.0",
"vue": "~2.6.14",
"vue-color": "^2.8.1",
"vue-loader": "~15.9.8",
"vue-template-compiler": "~2.6.14",
"webpack": "^3",
Expand Down Expand Up @@ -67,7 +66,8 @@
"promise/no-return-in-finally": "error",
"promise/no-return-wrap": "error",
"vue/require-prop-types": "off",
"vue/multiline-html-element-content-newline": "off"
"vue/multiline-html-element-content-newline": "off",
"vue/html-self-closing": "off"
},
"root": true
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import $ from 'jquery';
import _ from 'underscore';
import Vue from 'vue';

import {wrap} from '@girder/core/utilities/PluginUtils';
import eventStream from '@girder/core/utilities/EventStream';
import ItemView from '@girder/core/views/body/ItemView';
import View from '@girder/core/views/View';

import {restRequest} from '@girder/core/rest';

import largeImageConfig from './configView';
import * as viewers from './imageViewerWidget';

import imageViewerSelectWidget from '../templates/imageViewerSelectWidget.pug';
import '../stylesheets/imageViewerSelectWidget.styl';
import FrameSelector from '../vue/components/FrameSelector.vue';

import FrameSelector from '../widgets/FrameSelector.vue';
import DualInput from '../widgets/DualInput.vue';
import CompositeLayers from '../widgets/CompositeLayers.vue';
import HistogramEditor from '../widgets/HistogramEditor.vue';
import colors from '../widgets/colors.json';
import PresetsMenu from '../vue/components/PresetsMenu.vue';

wrap(ItemView, 'render', function (render) {
// ItemView is a special case in which rendering is done asynchronously,
Expand Down Expand Up @@ -73,13 +82,32 @@ var ImageViewerSelectWidget = View.extend({

_createVue(imageMetadata, frameUpdate) {
const el = this.$('#vue-container').get(0);
const vm = new FrameSelector({
const getFrameHistogram = (params) => {
restRequest({
type: 'GET',
url: 'item/' + this.itemId + '/tiles/histogram',
data: params
}).then((response) => {
const frameHistograms = this.vueApp._props.frameHistograms || {};
frameHistograms[params.frame] = response;
this.vueApp._props.frameHistograms = Object.assign({}, frameHistograms);
return undefined;
});
};
CompositeLayers.components = {HistogramEditor};
FrameSelector.components = {DualInput, CompositeLayers, HistogramEditor, PresetsMenu};
const Component = Vue.extend(FrameSelector);
const vm = new Component({
el,
propsData: {
currentFrame: 0,
itemId: this.itemId,
imageMetadata: imageMetadata,
frameUpdate: frameUpdate,
liConfig: this._liConfig
frameUpdate,
liConfig: this._liConfig,
frameHistograms: undefined,
getFrameHistogram,
colors
}
});
this.vueApp = vm;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ var GeojsImageViewerWidget = ImageViewerWidget.extend({
_postRender: function () {
},

frameUpdate: function (frame, style) {
frameUpdate: function ({frame, style}) {
if (this._frame === undefined) {
// don't set up layers until the we access the first non-zero frame
if (frame === 0 && style === undefined) {
Expand Down Expand Up @@ -242,8 +242,8 @@ var GeojsImageViewerWidget = ImageViewerWidget.extend({
this._layer2 = ltemp;
this._updating = false;
this.trigger('g:imageFrameChanged', this, frame);
if (frame !== this._nextframe || style !== this._nextstyle) {
this.frameUpdate(this._nextframe, this._nextstyle);
if (frame !== this._nextframe || JSON.stringify(style) !== JSON.stringify(this._nextstyle)) {
this.frameUpdate({frame: this._nextframe, style: this._nextstyle});
}
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export default {
},
styleToAutoRange(band) {
band = Object.assign({}, band); // new reference
if (band.min && band.min.includes('min:')) {
if (band.min && band.min.toString().includes('min:')) {
band.autoRange = parseFloat(band.min.replace('min:', '')) * 100;
delete band.min;
delete band.max;
Expand Down
3 changes: 0 additions & 3 deletions girder/girder_large_image/web_client/vue/utils/clamp.js

This file was deleted.

86 changes: 0 additions & 86 deletions girder/girder_large_image/web_client/vue/utils/colors.js

This file was deleted.

62 changes: 0 additions & 62 deletions girder/girder_large_image/web_client/vue/utils/drag.js

This file was deleted.

1 change: 1 addition & 0 deletions girder/girder_large_image/web_client/widgets
23 changes: 12 additions & 11 deletions large_image/tilesource/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ def __rich_repr__(self) -> Iterator[Any]:
def geospatial(self) -> bool:
return False

@property
def _unstyled(self) -> 'TileSource':
return getattr(self, '_unstyledInstance', self)

def _setStyle(self, style: Any) -> None:
"""
Check and set the specified style from a json string or a dictionary.
Expand Down Expand Up @@ -304,13 +308,11 @@ def dtype(self) -> np.dtype:
with self._sourceLock:
if not self._dtype:
self._dtype = 'check'
sample, _ = cast(Tuple[np.ndarray, Any], getattr(
self, '_unstyledInstance', self).getRegion(
region=dict(left=0, top=0, width=1, height=1),
format=TILE_FORMAT_NUMPY))
sample, _ = cast(Tuple[np.ndarray, Any], self._unstyled.getRegion(
region=dict(left=0, top=0, width=1, height=1),
format=TILE_FORMAT_NUMPY))
self._dtype = np.dtype(sample.dtype)
self._bandCount = len(
getattr(getattr(self, '_unstyledInstance', self), '_bandInfo', []))
self._bandCount = len(getattr(self._unstyled, '_bandInfo', []))
if not self._bandCount:
self._bandCount = sample.shape[-1] if len(sample.shape) == 3 else 1
return cast(np.dtype, self._dtype)
Expand Down Expand Up @@ -706,7 +708,7 @@ def _scanForMinMax(
:param onlyMinMax: if True, only find the min and max. If False, get
the entire histogram.
"""
self._bandRanges[frame] = getattr(self, '_unstyledInstance', self).histogram(
self._bandRanges[frame] = self._unstyled.histogram(
dtype=dtype,
onlyMinMax=onlyMinMax,
output={'maxWidth': min(self.sizeX, analysisSize),
Expand Down Expand Up @@ -1043,8 +1045,7 @@ def _applyStyle( # noqa
else:
frame = entry['frame'] if entry.get('frame') is not None else (
sc.mainFrame + entry['framedelta'])
image = getattr(self, '_unstyledInstance', self).getTile(
x, y, z, frame=frame, numpyAllowed=True)
image = self._unstyled.getTile(x, y, z, frame=frame, numpyAllowed=True)
image = image[:sc.mainImage.shape[0],
:sc.mainImage.shape[1],
:sc.mainImage.shape[2]]
Expand Down Expand Up @@ -1625,7 +1626,7 @@ def _getTileFromEmptyLevel(self, x: int, y: int, z: int, **kwargs) -> Tuple[
'Compositing tile from higher resolution tiles x=%d y=%d z=%d',
x * scale + newX, y * scale + newY, z)
lastlog = time.time()
subtile = getattr(self, '_unstyledInstance', self).getTile(
subtile = self._unstyled.getTile(
x * scale + newX, y * scale + newY, z,
pilImageAllowed=False, numpyAllowed='always',
sparseFallback=True, edge=False, frame=kwargs.get('frame'))
Expand All @@ -1649,7 +1650,7 @@ def _getTileFromEmptyLevel(self, x: int, y: int, z: int, **kwargs) -> Tuple[
'Compositing tile from higher resolution tiles x=%d y=%d z=%d',
x * scale + newX, y * scale + newY, z)
lastlog = time.time()
subtile = getattr(self, '_unstyledInstance', self).getTile(
subtile = self._unstyled.getTile(
x * scale + newX, y * scale + newY, z,
pilImageAllowed=True, numpyAllowed=False,
sparseFallback=True, edge=False, frame=kwargs.get('frame'))
Expand Down
Loading

0 comments on commit 489dbb9

Please sign in to comment.