@aics/vole-app 2.13.3 → 2.13.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/es/aics-image-viewer/components/TfEditor/index.js +28 -44
- package/es/aics-image-viewer/shared/utils/controlPointsToLut.js +17 -8
- package/package.json +2 -2
- package/type-declarations/aics-image-viewer/shared/utils/controlPointsToLut.d.ts +13 -8
- package/type-declarations/aics-image-viewer/shared/utils/viewerChannelSettings.d.ts +2 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ The volume shader itself is a heavily modified version of one that has distant o
|
|
|
15
15
|
## to use
|
|
16
16
|
|
|
17
17
|
- `https://vole.allencell.org/?url=path/to/ZARR`
|
|
18
|
-
- for more url parameters, see [`URL_SPEC.md`](documentation
|
|
18
|
+
- for more url parameters, see [`URL_SPEC.md`](documentation/URL_SPEC.md)
|
|
19
19
|
|
|
20
20
|
or as React component:
|
|
21
21
|
|
|
@@ -108,17 +108,17 @@ var sliderHandleSymbol = {
|
|
|
108
108
|
context.closePath();
|
|
109
109
|
}
|
|
110
110
|
};
|
|
111
|
-
function
|
|
112
|
-
return
|
|
111
|
+
function binToAbsolute(value, histogram) {
|
|
112
|
+
return histogram.getValueFromBinIndex(value);
|
|
113
113
|
}
|
|
114
|
-
function
|
|
115
|
-
return (value
|
|
114
|
+
function absoluteToBin(value, histogram) {
|
|
115
|
+
return histogram.findFractionalBinOfValue(value);
|
|
116
116
|
}
|
|
117
|
-
function controlPointToAbsolute(cp,
|
|
117
|
+
function controlPointToAbsolute(cp, histogram) {
|
|
118
118
|
// the x value of the control point is in the range [0, 255]
|
|
119
119
|
// because of the way the histogram is generated
|
|
120
120
|
// (see LUT_ENTRIES and the fact that we use Uint8Array)
|
|
121
|
-
return
|
|
121
|
+
return binToAbsolute(cp.x, histogram);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/** For when all control points are outside the plot's range: just fill the plot with the settings from 1 point */
|
|
@@ -293,12 +293,8 @@ var TfEditor = function TfEditor(props) {
|
|
|
293
293
|
var lastColorRef = useRef(TFEDITOR_DEFAULT_COLOR);
|
|
294
294
|
var svgRef = useRef(null); // need access to SVG element to measure mouse position
|
|
295
295
|
|
|
296
|
-
var
|
|
297
|
-
|
|
298
|
-
rawMax = _props$channelData.rawMax,
|
|
299
|
-
dtype = _props$channelData.dtype,
|
|
300
|
-
histogram = _props$channelData.histogram;
|
|
301
|
-
var typeRange = DTYPE_RANGE[dtype];
|
|
296
|
+
var histogram = props.channelData.histogram;
|
|
297
|
+
var typeRange = DTYPE_RANGE[props.channelData.dtype];
|
|
302
298
|
|
|
303
299
|
// d3 scales define the mapping between data and screen space (and do the heavy lifting of generating plot axes)
|
|
304
300
|
/** `xScale` is in raw intensity range, not U8 range. We use `u8ToAbsolute` and `absoluteToU8` to translate to U8. */
|
|
@@ -306,17 +302,11 @@ var TfEditor = function TfEditor(props) {
|
|
|
306
302
|
return d3.scaleLinear().domain([plotMin, plotMax]).range([0, innerWidth]);
|
|
307
303
|
}, [innerWidth, plotMin, plotMax]);
|
|
308
304
|
var plotMinU8 = useMemo(function () {
|
|
309
|
-
return
|
|
310
|
-
|
|
311
|
-
rawMax: rawMax
|
|
312
|
-
});
|
|
313
|
-
}, [plotMin, rawMin, rawMax]);
|
|
305
|
+
return absoluteToBin(plotMin, histogram);
|
|
306
|
+
}, [plotMin, histogram]);
|
|
314
307
|
var plotMaxU8 = useMemo(function () {
|
|
315
|
-
return
|
|
316
|
-
|
|
317
|
-
rawMax: rawMax
|
|
318
|
-
});
|
|
319
|
-
}, [plotMax, rawMin, rawMax]);
|
|
308
|
+
return absoluteToBin(plotMax, histogram);
|
|
309
|
+
}, [plotMax, histogram]);
|
|
320
310
|
var yScale = useMemo(function () {
|
|
321
311
|
return d3.scaleLinear().domain([0, 1]).range([innerHeight, 0]);
|
|
322
312
|
}, [innerHeight]);
|
|
@@ -326,7 +316,7 @@ var TfEditor = function TfEditor(props) {
|
|
|
326
316
|
x: 0,
|
|
327
317
|
y: 0
|
|
328
318
|
};
|
|
329
|
-
return [
|
|
319
|
+
return [absoluteToBin(xScale.invert(clamp(event.clientX - svgRect.x - TFEDITOR_MARGINS.left, 0, innerWidth)), histogram), yScale.invert(clamp(event.clientY - svgRect.y - TFEDITOR_MARGINS.top, 0, innerHeight))];
|
|
330
320
|
};
|
|
331
321
|
var dragControlPoint = function dragControlPoint(draggedIdx, x, opacity) {
|
|
332
322
|
var newControlPoints = _toConsumableArray(controlPointsRef.current);
|
|
@@ -461,15 +451,12 @@ var TfEditor = function TfEditor(props) {
|
|
|
461
451
|
var areaPath = useMemo(function () {
|
|
462
452
|
var _areaGenerator;
|
|
463
453
|
var areaGenerator = d3.area().x(function (d) {
|
|
464
|
-
return xScale(controlPointToAbsolute(d,
|
|
465
|
-
rawMin: rawMin,
|
|
466
|
-
rawMax: rawMax
|
|
467
|
-
}));
|
|
454
|
+
return xScale(controlPointToAbsolute(d, histogram));
|
|
468
455
|
}).y0(function (d) {
|
|
469
456
|
return yScale(d.opacity);
|
|
470
457
|
}).y1(innerHeight).curve(d3.curveLinear);
|
|
471
458
|
return (_areaGenerator = areaGenerator(controlPointsToRender)) !== null && _areaGenerator !== void 0 ? _areaGenerator : undefined;
|
|
472
|
-
}, [controlPointsToRender, xScale, yScale, innerHeight,
|
|
459
|
+
}, [controlPointsToRender, xScale, yScale, innerHeight, histogram]);
|
|
473
460
|
|
|
474
461
|
/** d3-generated svg data string representing the "basic mode" min/max slider handles */
|
|
475
462
|
var sliderHandlePath = useMemo(function () {
|
|
@@ -529,17 +516,14 @@ var TfEditor = function TfEditor(props) {
|
|
|
529
516
|
.data(binLengthsToRender) // bind the histogram bins to this selection
|
|
530
517
|
.join("rect") // ensure we have exactly as many bound `rect` elements in the DOM as we have histogram bins
|
|
531
518
|
.attr("class", "bar").attr("width", barWidth).attr("x", function (_len, idx) {
|
|
532
|
-
return xScale(
|
|
533
|
-
rawMin: rawMin,
|
|
534
|
-
rawMax: rawMax
|
|
535
|
-
}));
|
|
519
|
+
return xScale(binToAbsolute(idx + start, histogram));
|
|
536
520
|
}) // set position and height from data
|
|
537
521
|
.attr("y", function (len) {
|
|
538
522
|
return binScale(len);
|
|
539
523
|
}).attr("height", function (len) {
|
|
540
524
|
return innerHeight - binScale(len);
|
|
541
525
|
});
|
|
542
|
-
}, [xScale,
|
|
526
|
+
}, [xScale, histogram, innerWidth, innerHeight, plotMinU8, plotMaxU8]);
|
|
543
527
|
var applyTFGenerator = useCallback(function (generator) {
|
|
544
528
|
setSelectedPointIdx(null);
|
|
545
529
|
lastColorRef.current = TFEDITOR_DEFAULT_COLOR;
|
|
@@ -574,7 +558,7 @@ var TfEditor = function TfEditor(props) {
|
|
|
574
558
|
return /*#__PURE__*/React.createElement("circle", {
|
|
575
559
|
key: i,
|
|
576
560
|
className: i === selectedPointIdx ? "selected" : "",
|
|
577
|
-
cx: xScale(controlPointToAbsolute(cp,
|
|
561
|
+
cx: xScale(controlPointToAbsolute(cp, histogram)),
|
|
578
562
|
cy: yScale(cp.opacity),
|
|
579
563
|
style: {
|
|
580
564
|
fill: colorArrayToString(cp.color)
|
|
@@ -606,22 +590,22 @@ var TfEditor = function TfEditor(props) {
|
|
|
606
590
|
}, "Advanced")), !props.useControlPoints && /*#__PURE__*/React.createElement("div", {
|
|
607
591
|
className: "tf-editor-control-row ramp-row"
|
|
608
592
|
}, "Levels min/max", /*#__PURE__*/React.createElement(InputNumber, {
|
|
609
|
-
value:
|
|
593
|
+
value: binToAbsolute(props.ramp[0], histogram),
|
|
610
594
|
onChange: function onChange(v) {
|
|
611
|
-
return v !== null && setRamp([
|
|
595
|
+
return v !== null && setRamp([absoluteToBin(v, histogram), props.ramp[1]]);
|
|
612
596
|
},
|
|
613
597
|
formatter: numberFormatter,
|
|
614
598
|
min: typeRange.min,
|
|
615
|
-
max: Math.min(
|
|
599
|
+
max: Math.min(binToAbsolute(props.ramp[1], histogram), typeRange.max),
|
|
616
600
|
size: "small",
|
|
617
601
|
controls: false
|
|
618
602
|
}), /*#__PURE__*/React.createElement(InputNumber, {
|
|
619
|
-
value:
|
|
603
|
+
value: binToAbsolute(props.ramp[1], histogram),
|
|
620
604
|
onChange: function onChange(v) {
|
|
621
|
-
return v !== null && setRamp([props.ramp[0],
|
|
605
|
+
return v !== null && setRamp([props.ramp[0], absoluteToBin(v, histogram)]);
|
|
622
606
|
},
|
|
623
607
|
formatter: numberFormatter,
|
|
624
|
-
min: Math.max(typeRange.min,
|
|
608
|
+
min: Math.max(typeRange.min, binToAbsolute(props.ramp[0], histogram)),
|
|
625
609
|
max: typeRange.max,
|
|
626
610
|
size: "small",
|
|
627
611
|
controls: false
|
|
@@ -667,7 +651,7 @@ var TfEditor = function TfEditor(props) {
|
|
|
667
651
|
}), controlPointCircles, !props.useControlPoints && /*#__PURE__*/React.createElement("g", {
|
|
668
652
|
className: "ramp-sliders"
|
|
669
653
|
}, plotMinU8 <= props.ramp[0] && props.ramp[0] <= plotMaxU8 && /*#__PURE__*/React.createElement("g", {
|
|
670
|
-
transform: "translate(".concat(xScale(
|
|
654
|
+
transform: "translate(".concat(xScale(binToAbsolute(props.ramp[0], histogram)), ")")
|
|
671
655
|
}, /*#__PURE__*/React.createElement("line", {
|
|
672
656
|
y1: innerHeight,
|
|
673
657
|
strokeDasharray: "5,5",
|
|
@@ -686,7 +670,7 @@ var TfEditor = function TfEditor(props) {
|
|
|
686
670
|
return setDraggedPointIdx(TfEditorRampSliderHandle.Min);
|
|
687
671
|
}
|
|
688
672
|
})), plotMinU8 <= props.ramp[1] && props.ramp[1] <= plotMaxU8 && /*#__PURE__*/React.createElement("g", {
|
|
689
|
-
transform: "translate(".concat(xScale(
|
|
673
|
+
transform: "translate(".concat(xScale(binToAbsolute(props.ramp[1], histogram)), ")")
|
|
690
674
|
}, /*#__PURE__*/React.createElement("line", {
|
|
691
675
|
y1: innerHeight,
|
|
692
676
|
strokeDasharray: "5,5",
|
|
@@ -738,8 +722,8 @@ var TfEditor = function TfEditor(props) {
|
|
|
738
722
|
},
|
|
739
723
|
onClick: function onClick() {
|
|
740
724
|
return changeChannelSetting({
|
|
741
|
-
plotMin: rawMin,
|
|
742
|
-
plotMax: rawMax
|
|
725
|
+
plotMin: props.channelData.rawMin,
|
|
726
|
+
plotMax: props.channelData.rawMax
|
|
743
727
|
});
|
|
744
728
|
}
|
|
745
729
|
}, "Fit to data"), /*#__PURE__*/React.createElement(Button, {
|
|
@@ -40,6 +40,10 @@ function parseLutValue(value, histogram) {
|
|
|
40
40
|
// percentile
|
|
41
41
|
var _parsedValue = parseFloat(value.substring(1)) / 100.0;
|
|
42
42
|
return histogram.findBinOfPercentile(_parsedValue);
|
|
43
|
+
} else if (firstChar === "v") {
|
|
44
|
+
// value
|
|
45
|
+
var _parsedValue2 = parseFloat(value.substring(1));
|
|
46
|
+
return histogram.findFractionalBinOfValue(_parsedValue2);
|
|
43
47
|
} else {
|
|
44
48
|
// plain number
|
|
45
49
|
return parseFloat(value);
|
|
@@ -47,21 +51,26 @@ function parseLutValue(value, histogram) {
|
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
/**
|
|
50
|
-
* Parses a lookup table (LUT) from a `ViewerChannelSetting` object, where the
|
|
51
|
-
* array of two alphanumeric strings.
|
|
54
|
+
* Parses a lookup table (LUT) from a `ViewerChannelSetting` object, where the
|
|
55
|
+
* `lut` field is an array of two alphanumeric strings.
|
|
52
56
|
*
|
|
53
|
-
* @returns a Lut object if the `lut` field is valid; otherwise, returns
|
|
57
|
+
* @returns a Lut object if the `lut` field is valid; otherwise, returns
|
|
58
|
+
* undefined.
|
|
54
59
|
*
|
|
55
60
|
* Min and max values are determined as following:
|
|
56
|
-
* - Plain numbers are
|
|
57
|
-
*
|
|
61
|
+
* - Plain numbers are indices of histogram bins, typically in the range [0,
|
|
62
|
+
* 255].
|
|
63
|
+
* - `v{n}` represents a raw intensity value, where `n` is a number.
|
|
64
|
+
* - `p{n}` represents a percentile, where `n` is a percentile in the [0, 100]
|
|
65
|
+
* range.
|
|
58
66
|
* - `m{n}` represents the median multiplied by `n / 100`.
|
|
59
|
-
* - `autoij` in either the min or max fields will use the "auto" algorithm
|
|
60
|
-
*
|
|
67
|
+
* - `autoij` in either the min or max fields will use the "auto" algorithm from
|
|
68
|
+
* ImageJ to select the min and max.
|
|
61
69
|
*
|
|
62
70
|
* @example
|
|
63
71
|
* ```
|
|
64
|
-
* "0:255" // min:
|
|
72
|
+
* "0:255" // min: bin 0, max: bin 255.
|
|
73
|
+
* "v100:v150" // min: intensity 100, max: intensity 150.
|
|
65
74
|
* "p50:p90" // min: 50th percentile, max: 90th percentile.
|
|
66
75
|
* "m1:p75" // min: median, max: 75th percentile.
|
|
67
76
|
* "autoij:0" // use Auto-IJ to calculate min and max.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aics/vole-app",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.5",
|
|
4
4
|
"description": "web view of cell volume images",
|
|
5
5
|
"repository": "github:allen-cell-animated/vole-app",
|
|
6
6
|
"main": "es/index.js",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"author": "Megan Riel-Mehan",
|
|
42
42
|
"license": "ISC",
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@aics/vole-core": "^
|
|
44
|
+
"@aics/vole-core": "^4.1.0",
|
|
45
45
|
"@ant-design/icons": "^5.2.5",
|
|
46
46
|
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
|
47
47
|
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
|
@@ -4,21 +4,26 @@ export declare function controlPointsToLut(controlPoints: ControlPoint[]): Lut;
|
|
|
4
4
|
/** Returns a default lookup table based on a min/max percentile of the current volume's data. */
|
|
5
5
|
export declare function getDefaultLut(histogram: Histogram): Lut;
|
|
6
6
|
/**
|
|
7
|
-
* Parses a lookup table (LUT) from a `ViewerChannelSetting` object, where the
|
|
8
|
-
* array of two alphanumeric strings.
|
|
7
|
+
* Parses a lookup table (LUT) from a `ViewerChannelSetting` object, where the
|
|
8
|
+
* `lut` field is an array of two alphanumeric strings.
|
|
9
9
|
*
|
|
10
|
-
* @returns a Lut object if the `lut` field is valid; otherwise, returns
|
|
10
|
+
* @returns a Lut object if the `lut` field is valid; otherwise, returns
|
|
11
|
+
* undefined.
|
|
11
12
|
*
|
|
12
13
|
* Min and max values are determined as following:
|
|
13
|
-
* - Plain numbers are
|
|
14
|
-
*
|
|
14
|
+
* - Plain numbers are indices of histogram bins, typically in the range [0,
|
|
15
|
+
* 255].
|
|
16
|
+
* - `v{n}` represents a raw intensity value, where `n` is a number.
|
|
17
|
+
* - `p{n}` represents a percentile, where `n` is a percentile in the [0, 100]
|
|
18
|
+
* range.
|
|
15
19
|
* - `m{n}` represents the median multiplied by `n / 100`.
|
|
16
|
-
* - `autoij` in either the min or max fields will use the "auto" algorithm
|
|
17
|
-
*
|
|
20
|
+
* - `autoij` in either the min or max fields will use the "auto" algorithm from
|
|
21
|
+
* ImageJ to select the min and max.
|
|
18
22
|
*
|
|
19
23
|
* @example
|
|
20
24
|
* ```
|
|
21
|
-
* "0:255" // min:
|
|
25
|
+
* "0:255" // min: bin 0, max: bin 255.
|
|
26
|
+
* "v100:v150" // min: intensity 100, max: intensity 150.
|
|
22
27
|
* "p50:p90" // min: 50th percentile, max: 90th percentile.
|
|
23
28
|
* "m1:p75" // min: median, max: 75th percentile.
|
|
24
29
|
* "autoij:0" // use Auto-IJ to calculate min and max.
|
|
@@ -10,7 +10,8 @@ export interface ViewerChannelSetting {
|
|
|
10
10
|
* Min and max values for the intensity lookup table, which maps from raw intensity values
|
|
11
11
|
* in the volume to opacity and color. Defaults to [0, 255].
|
|
12
12
|
*
|
|
13
|
-
* - Plain numbers are
|
|
13
|
+
* - Plain numbers are indices of histogram bins, in the range [0, 255].
|
|
14
|
+
* - `v{n}` represents a raw intensity value, where `n` is an integer.
|
|
14
15
|
* - `p{n}` represents a percentile, where `n` is a percentile in the [0, 100] range.
|
|
15
16
|
* - `m{n}` represents the median multiplied by `n / 100`.
|
|
16
17
|
* - `autoij` in either the min or max fields will use the "auto" algorithm
|