td-plots 1.5.2 → 1.5.4
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/dist/components/Histogram.d.ts +5 -4
- package/dist/index.esm.js +311 -227
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +311 -227
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -105,29 +105,6 @@ var plotlyMToMilliseconds = function (mString) {
|
|
|
105
105
|
}
|
|
106
106
|
return 0;
|
|
107
107
|
};
|
|
108
|
-
// Convert a string specifying a day (with no time) to a timestamp
|
|
109
|
-
var convertDateDescriptionToTimestamp = function (startValue) {
|
|
110
|
-
if (typeof startValue === 'number') {
|
|
111
|
-
// Then we're assuming it's already a timestamp
|
|
112
|
-
return startValue;
|
|
113
|
-
}
|
|
114
|
-
if (typeof startValue === 'string') {
|
|
115
|
-
// Try to parse the date string.
|
|
116
|
-
var date = new Date(startValue);
|
|
117
|
-
// Sometimes the date will fail to be a proper Date if it does not
|
|
118
|
-
// have a time component. Add a time stamp if necessary.
|
|
119
|
-
if (isNaN(date.getTime())) {
|
|
120
|
-
// Then date did not have a time and is just a day. Try adding a time.
|
|
121
|
-
var dateWithTime = new Date(startValue + 'T00:00:00');
|
|
122
|
-
if (isNaN(dateWithTime.getTime())) {
|
|
123
|
-
throw new Error("Cannot parse date: ".concat(startValue));
|
|
124
|
-
}
|
|
125
|
-
return dateWithTime.getTime();
|
|
126
|
-
}
|
|
127
|
-
return date.getTime();
|
|
128
|
-
}
|
|
129
|
-
throw new Error("Unexpected type for start value: ".concat(typeof startValue));
|
|
130
|
-
};
|
|
131
108
|
|
|
132
109
|
function getDefaultExportFromCjs (x) {
|
|
133
110
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
@@ -6075,11 +6052,19 @@ var Loading = function () {
|
|
|
6075
6052
|
var Plot$2 = lazy(function () { return import('react-plotly.js'); });
|
|
6076
6053
|
var HistogramPlot = function (props) {
|
|
6077
6054
|
var _a, _b, _c, _d;
|
|
6078
|
-
var data = props.data, title = props.title, xAxisTitle = props.xAxisTitle, _e = props.barColor, barColor = _e === void 0 ?
|
|
6055
|
+
var data = props.data, title = props.title, xAxisTitle = props.xAxisTitle, _e = props.barColor, barColor = _e === void 0 ? "rgb(72, 72, 74)" : _e, _f = props.unselectedBarColor, unselectedBarColor = _f === void 0 ? "rgba(203, 195, 195, 0.88)" : _f, _g = props.selectorsColor, selectorsColor = _g === void 0 ? "black" : _g, containerStyleOverrides = props.containerStyleOverrides, _h = props.unselectedData, unselectedData = _h === void 0 ? [] : _h, _j = props.handleClickOrSelection, handleClickOrSelection = _j === void 0 ? function () { } : _j, _k = props.onDeselect, onDeselect = _k === void 0 ? function () { } : _k, plotId = props.plotId, _l = props.selectByBin, selectByBin = _l === void 0 ? false : _l, dateTickFormat = props.dateTickFormat, binSizeOverride = props.binSizeOverride, _m = props.statsAnnotations, statsAnnotations = _m === void 0 ? ["mean"] : _m, _o = props.emptySelectedRange, emptySelectedRange = _o === void 0 ? false : _o;
|
|
6079
6056
|
// Ref for plot container
|
|
6080
6057
|
var containerRef = useRef(null);
|
|
6081
6058
|
// Track any selections made in this plot so we can style the selection box.
|
|
6082
|
-
var
|
|
6059
|
+
var _p = useState(null), selectedRange = _p[0], setSelectedRange = _p[1];
|
|
6060
|
+
// If the parent component wants to clear the selection, reset selectedRange to null.
|
|
6061
|
+
useEffect(function () {
|
|
6062
|
+
if (emptySelectedRange) {
|
|
6063
|
+
setSelectedRange(null);
|
|
6064
|
+
}
|
|
6065
|
+
}, [emptySelectedRange]);
|
|
6066
|
+
// Combine all data into one for later calculations
|
|
6067
|
+
var allData = __spreadArray(__spreadArray([], data, true), unselectedData, true);
|
|
6083
6068
|
// If all the data becomes selected, we should forget any old selections.
|
|
6084
6069
|
useEffect(function () {
|
|
6085
6070
|
if (unselectedData.length === 0) {
|
|
@@ -6087,11 +6072,15 @@ var HistogramPlot = function (props) {
|
|
|
6087
6072
|
}
|
|
6088
6073
|
}, [unselectedData]);
|
|
6089
6074
|
// Set the bins based on the entire data set.
|
|
6090
|
-
var nBins =
|
|
6075
|
+
var nBins = data.length + unselectedData.length >= 10
|
|
6076
|
+
? Math.ceil(Math.sqrt(data.length + unselectedData.length))
|
|
6077
|
+
: 0;
|
|
6091
6078
|
// Plotly determines "nice" bins which consequently means it internally decides the axis range. We need
|
|
6092
6079
|
// to access that information once the plot has been initialized so that we can prevent the
|
|
6093
6080
|
// axis range from changing during interaction. Dates use strings.
|
|
6094
|
-
var
|
|
6081
|
+
var _q = useState(undefined), fixedXAxisRange = _q[0], setFixedXAxisRange = _q[1];
|
|
6082
|
+
// track xbins too
|
|
6083
|
+
var _r = useState(undefined), binSize = _r[0], setBinSize = _r[1];
|
|
6095
6084
|
// Once the plot is drawn, record the initial axis range so we can keep it fixed.
|
|
6096
6085
|
// figure should be Readonly<Plotly.Figure> but react-plotly.js doesn't expose that type, so we use any.
|
|
6097
6086
|
var handlePlotUpdate = function (figure, graphDiv) {
|
|
@@ -6107,23 +6096,53 @@ var HistogramPlot = function (props) {
|
|
|
6107
6096
|
setFixedXAxisRange(range);
|
|
6108
6097
|
}
|
|
6109
6098
|
}
|
|
6099
|
+
if (!binSize) {
|
|
6100
|
+
// Get the bin size from the first trace. Both traces should have the same bin size.
|
|
6101
|
+
if (figure &&
|
|
6102
|
+
figure.data &&
|
|
6103
|
+
figure.data.length > 0 &&
|
|
6104
|
+
figure.data[0].xbins &&
|
|
6105
|
+
figure.data[0].xbins.size) {
|
|
6106
|
+
setBinSize(figure.data[0].xbins.size);
|
|
6107
|
+
}
|
|
6108
|
+
}
|
|
6110
6109
|
};
|
|
6110
|
+
// Track shift key state
|
|
6111
|
+
var isShiftPressed = useRef(false);
|
|
6112
|
+
// Add keyboard event listeners to track shift key
|
|
6113
|
+
useEffect(function () {
|
|
6114
|
+
var handleKeyDown = function (e) {
|
|
6115
|
+
if (e.key === "Shift") {
|
|
6116
|
+
isShiftPressed.current = true;
|
|
6117
|
+
}
|
|
6118
|
+
};
|
|
6119
|
+
var handleKeyUp = function (e) {
|
|
6120
|
+
if (e.key === "Shift") {
|
|
6121
|
+
isShiftPressed.current = false;
|
|
6122
|
+
}
|
|
6123
|
+
};
|
|
6124
|
+
// Add event listeners to document to catch shift key globally
|
|
6125
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
6126
|
+
document.addEventListener("keyup", handleKeyUp);
|
|
6127
|
+
// Cleanup
|
|
6128
|
+
return function () {
|
|
6129
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
6130
|
+
document.removeEventListener("keyup", handleKeyUp);
|
|
6131
|
+
};
|
|
6132
|
+
}, []);
|
|
6111
6133
|
// Create handler for click event that can use event data to update the plot if desired.
|
|
6112
6134
|
var handleClick = function (event) {
|
|
6135
|
+
var _a, _b, _c, _d;
|
|
6113
6136
|
if (!event || !event.points || event.points.length === 0) {
|
|
6114
6137
|
return;
|
|
6115
6138
|
}
|
|
6116
|
-
// The main trace is always curve number 0.
|
|
6117
|
-
// If we clicked the unselected data trace, nothing should happen.
|
|
6118
|
-
if (event.points[0].curveNumber !== 0) {
|
|
6119
|
-
return;
|
|
6120
|
-
}
|
|
6121
6139
|
// Use the bin number to determine which bar was clicked and determine the range of the clicked bar.
|
|
6122
|
-
if ("binNumber" in event.points[0] &&
|
|
6140
|
+
if ("binNumber" in event.points[0] &&
|
|
6141
|
+
typeof event.points[0].binNumber === "number") {
|
|
6123
6142
|
// Get the index of the clicked bar with respect to the trace. So if
|
|
6124
6143
|
// my trace has only one bar (0, 1] but another trace has bars (-1, 0], (0, 1], (1, 2], etc.
|
|
6125
6144
|
// then when I click on (0, 1] in my trace the index will be 0, even thought it would be
|
|
6126
|
-
// the second bar in the other trace. Because of this, we can't use data.xbins to
|
|
6145
|
+
// the second bar in the other trace. Because of this, we can't use data.xbins to
|
|
6127
6146
|
// find the clicked bar, because its start and end values are based on all traces, not just the clicked trace.
|
|
6128
6147
|
var clickedBinIndex = event.points[0].binNumber;
|
|
6129
6148
|
// Handle dates and numbers separately
|
|
@@ -6133,40 +6152,57 @@ var HistogramPlot = function (props) {
|
|
|
6133
6152
|
var globalFirstBinStart = void 0;
|
|
6134
6153
|
if (isDateArray(data)) {
|
|
6135
6154
|
// Date bins are represented as strings (sometimes). We'll need to convert whatever plotly gives us to timestamps.
|
|
6136
|
-
globalFirstBinStart =
|
|
6137
|
-
|
|
6155
|
+
globalFirstBinStart = fixedXAxisRange
|
|
6156
|
+
? new Date(fixedXAxisRange[0]).getTime()
|
|
6157
|
+
: new Date(event.points[0].data.xbins.start).getTime();
|
|
6158
|
+
minTraceValue =
|
|
6159
|
+
event.points[0].curveNumber === 0
|
|
6160
|
+
? Math.min.apply(Math, data.map(function (d) { return d.getTime(); })) : Math.min.apply(Math, unselectedData.map(function (d) { return d.getTime(); }));
|
|
6138
6161
|
}
|
|
6139
6162
|
else {
|
|
6140
|
-
// All of the event info should be numbers
|
|
6141
|
-
if (typeof event.points[0].data.xbins.start !== 'number') {
|
|
6142
|
-
console.error("Unexpected type for xbins.start. Expected number.");
|
|
6143
|
-
return;
|
|
6144
|
-
}
|
|
6145
6163
|
// Get the min value of the trace and the beginning of the first bin (globally)
|
|
6146
|
-
minTraceValue =
|
|
6147
|
-
|
|
6164
|
+
minTraceValue =
|
|
6165
|
+
event.points[0].curveNumber === 0
|
|
6166
|
+
? Math.min.apply(Math, data) : Math.min.apply(Math, unselectedData);
|
|
6167
|
+
globalFirstBinStart = fixedXAxisRange
|
|
6168
|
+
? fixedXAxisRange[0]
|
|
6169
|
+
: event.points[0].data.xbins.start;
|
|
6148
6170
|
}
|
|
6149
6171
|
// Finally, we need to calculate the min and max values of the clicked bin.
|
|
6150
6172
|
// If the bin size is a month or more, plotly records it in their "mstring" format like "M3" for 3 months.
|
|
6151
6173
|
// We then must convert it back to milliseconds. Otherwise, it's always ms.
|
|
6152
|
-
var binSize =
|
|
6153
|
-
|
|
6154
|
-
|
|
6174
|
+
var size = binSize !== null && binSize !== void 0 ? binSize : (_d = (_c = (_b = (_a = event.points) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.xbins) === null || _d === void 0 ? void 0 : _d.size;
|
|
6175
|
+
var convertedBinSize = typeof size === "string"
|
|
6176
|
+
? plotlyMToMilliseconds(size)
|
|
6177
|
+
: size;
|
|
6155
6178
|
// This minTraceValue is in the 0th bin of this trace. Find the index of this bin in the whole plot.
|
|
6156
|
-
var clickedBinGlobalIndex = clickedBinIndex +
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
globalFirstBinStart +
|
|
6160
|
-
|
|
6179
|
+
var clickedBinGlobalIndex = clickedBinIndex +
|
|
6180
|
+
Math.floor((minTraceValue - globalFirstBinStart) / convertedBinSize);
|
|
6181
|
+
var _e = [
|
|
6182
|
+
globalFirstBinStart + clickedBinGlobalIndex * convertedBinSize,
|
|
6183
|
+
globalFirstBinStart + (clickedBinGlobalIndex + 1) * convertedBinSize,
|
|
6184
|
+
], minBinValue = _e[0], maxBinValue = _e[1];
|
|
6161
6185
|
if (isDateArray(data)) {
|
|
6162
6186
|
var minDate = new Date(minBinValue);
|
|
6163
6187
|
var maxDate = new Date(maxBinValue);
|
|
6164
|
-
handleClickOrSelection(minDate, maxDate);
|
|
6165
|
-
|
|
6188
|
+
handleClickOrSelection(minDate, maxDate, isShiftPressed.current);
|
|
6189
|
+
var newMinMax = [minDate, maxDate];
|
|
6190
|
+
if (isShiftPressed.current && selectedRange) {
|
|
6191
|
+
setSelectedRange(__spreadArray(__spreadArray([], selectedRange, true), [newMinMax], false));
|
|
6192
|
+
}
|
|
6193
|
+
else {
|
|
6194
|
+
setSelectedRange([newMinMax]);
|
|
6195
|
+
}
|
|
6166
6196
|
}
|
|
6167
6197
|
else {
|
|
6168
|
-
handleClickOrSelection(minBinValue, maxBinValue);
|
|
6169
|
-
|
|
6198
|
+
handleClickOrSelection(minBinValue, maxBinValue, isShiftPressed.current);
|
|
6199
|
+
var newMinMax = [minBinValue, maxBinValue];
|
|
6200
|
+
if (isShiftPressed.current && selectedRange) {
|
|
6201
|
+
setSelectedRange(__spreadArray(__spreadArray([], selectedRange, true), [newMinMax], false));
|
|
6202
|
+
}
|
|
6203
|
+
else {
|
|
6204
|
+
setSelectedRange([newMinMax]);
|
|
6205
|
+
}
|
|
6170
6206
|
}
|
|
6171
6207
|
}
|
|
6172
6208
|
};
|
|
@@ -6177,7 +6213,8 @@ var HistogramPlot = function (props) {
|
|
|
6177
6213
|
}
|
|
6178
6214
|
var minValue;
|
|
6179
6215
|
var maxValue;
|
|
6180
|
-
if (typeof event.range.x[0] ===
|
|
6216
|
+
if (typeof event.range.x[0] === "string" &&
|
|
6217
|
+
typeof event.range.x[1] === "string") {
|
|
6181
6218
|
// Then we are must be dealing with dates
|
|
6182
6219
|
if (selectByBin) {
|
|
6183
6220
|
// Set selected range to include the whole bin if at least half the bin is within the explicit range
|
|
@@ -6188,11 +6225,11 @@ var HistogramPlot = function (props) {
|
|
|
6188
6225
|
var lastBinMidPoint = new Date(event.points[event.points.length - 1].x).getTime();
|
|
6189
6226
|
// If the bin size is a month or more, plotly records it in their "mstring" format like "M3" for 3 months.
|
|
6190
6227
|
// We then must convert it back to milliseconds. Otherwise, it's always ms.
|
|
6191
|
-
var
|
|
6192
|
-
? plotlyMToMilliseconds(
|
|
6193
|
-
:
|
|
6194
|
-
minValue = new Date(firstBinMidPoint -
|
|
6195
|
-
maxValue = new Date(lastBinMidPoint +
|
|
6228
|
+
var convertedBinSize = typeof binSize === "string"
|
|
6229
|
+
? plotlyMToMilliseconds(binSize)
|
|
6230
|
+
: binSize;
|
|
6231
|
+
minValue = new Date(firstBinMidPoint - convertedBinSize / 2);
|
|
6232
|
+
maxValue = new Date(lastBinMidPoint + convertedBinSize / 2);
|
|
6196
6233
|
}
|
|
6197
6234
|
else {
|
|
6198
6235
|
// No bins selected, so the range should be empty.
|
|
@@ -6212,11 +6249,12 @@ var HistogramPlot = function (props) {
|
|
|
6212
6249
|
// Set the range based on the bins selected. Plotly will include a bin in event.points if
|
|
6213
6250
|
// at least half of it is selected.
|
|
6214
6251
|
if (event.points && event.points.length > 0) {
|
|
6215
|
-
|
|
6216
|
-
var
|
|
6217
|
-
var
|
|
6218
|
-
var
|
|
6219
|
-
var
|
|
6252
|
+
// Find the max and min midpoints. They may be from curve 0 or 1.
|
|
6253
|
+
var firstBinMidPoint = Math.min.apply(Math, event.points.map(function (p) { return p.x; }));
|
|
6254
|
+
var lastBinMidPoint = Math.max.apply(Math, event.points.map(function (p) { return p.x; }));
|
|
6255
|
+
var convertedBinSize = binSize;
|
|
6256
|
+
var roundedMinValue = firstBinMidPoint - convertedBinSize / 2;
|
|
6257
|
+
var roundedMaxValue = lastBinMidPoint + convertedBinSize / 2;
|
|
6220
6258
|
minValue = roundedMinValue;
|
|
6221
6259
|
maxValue = roundedMaxValue;
|
|
6222
6260
|
}
|
|
@@ -6234,13 +6272,25 @@ var HistogramPlot = function (props) {
|
|
|
6234
6272
|
}
|
|
6235
6273
|
if (minValue !== undefined && maxValue !== undefined) {
|
|
6236
6274
|
// Update selected range. Have to be strict about types.
|
|
6237
|
-
if (typeof minValue ===
|
|
6238
|
-
|
|
6275
|
+
if (typeof minValue === "number" && typeof maxValue === "number") {
|
|
6276
|
+
var newMinMax = [minValue, maxValue];
|
|
6277
|
+
if (isShiftPressed.current && selectedRange) {
|
|
6278
|
+
setSelectedRange(__spreadArray(__spreadArray([], selectedRange, true), [newMinMax], false));
|
|
6279
|
+
}
|
|
6280
|
+
else {
|
|
6281
|
+
setSelectedRange([newMinMax]);
|
|
6282
|
+
}
|
|
6239
6283
|
}
|
|
6240
6284
|
else if (minValue instanceof Date && maxValue instanceof Date) {
|
|
6241
|
-
|
|
6285
|
+
var newMinMax = [minValue, maxValue];
|
|
6286
|
+
if (isShiftPressed.current && selectedRange) {
|
|
6287
|
+
setSelectedRange(__spreadArray(__spreadArray([], selectedRange, true), [newMinMax], false));
|
|
6288
|
+
}
|
|
6289
|
+
else {
|
|
6290
|
+
setSelectedRange([newMinMax]);
|
|
6291
|
+
}
|
|
6242
6292
|
}
|
|
6243
|
-
handleClickOrSelection(minValue, maxValue);
|
|
6293
|
+
handleClickOrSelection(minValue, maxValue, isShiftPressed.current);
|
|
6244
6294
|
}
|
|
6245
6295
|
};
|
|
6246
6296
|
// Create the selected range box
|
|
@@ -6250,129 +6300,146 @@ var HistogramPlot = function (props) {
|
|
|
6250
6300
|
if (unselectedData.length === 0)
|
|
6251
6301
|
return []; // Don't show the box if the entire dataset is selected.
|
|
6252
6302
|
// Create a multiply-like effect by using a semi-transparent dark overlay
|
|
6253
|
-
var multiplyColor =
|
|
6254
|
-
return
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6303
|
+
var multiplyColor = "rgba(29, 104, 185, 0.1)";
|
|
6304
|
+
return selectedRange.map(function (maxMin) { return ({
|
|
6305
|
+
type: "rect",
|
|
6306
|
+
x0: isDateArray(maxMin) ? maxMin[0].getTime() : maxMin[0],
|
|
6307
|
+
x1: isDateArray(maxMin) ? maxMin[1].getTime() : maxMin[1],
|
|
6308
|
+
y0: 0,
|
|
6309
|
+
y1: 1,
|
|
6310
|
+
yref: "paper",
|
|
6311
|
+
fillcolor: multiplyColor,
|
|
6312
|
+
line: {
|
|
6313
|
+
width: 1,
|
|
6314
|
+
color: multiplyColor,
|
|
6315
|
+
},
|
|
6316
|
+
layer: "above", // Ensure the selection box is above the bars
|
|
6317
|
+
}); });
|
|
6268
6318
|
}, [selectedRange, unselectedData]);
|
|
6269
6319
|
// Calculate the mean of the selected data using normalized data
|
|
6270
6320
|
var meanValue = (_a = calculateMean(data)) !== null && _a !== void 0 ? _a : 0; // Default to 0 if no data
|
|
6271
6321
|
var stdevValue = (_b = calculateStandardDeviation(data)) !== null && _b !== void 0 ? _b : 0;
|
|
6272
6322
|
var meanLineRadius = 0.01; // distance from the top of the y axis to the top/bottom end of the mean line
|
|
6273
|
-
var meanLine =
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6323
|
+
var meanLine = statsAnnotations.includes("mean") && data.length > 0
|
|
6324
|
+
? [
|
|
6325
|
+
{
|
|
6326
|
+
type: "line",
|
|
6327
|
+
x0: meanValue,
|
|
6328
|
+
y0: 1 - meanLineRadius,
|
|
6329
|
+
x1: meanValue,
|
|
6330
|
+
yref: "paper",
|
|
6331
|
+
y1: 1 + meanLineRadius + 0.04, // Add extra length above to make the line look centered on the y-axis top.
|
|
6332
|
+
line: {
|
|
6333
|
+
color: barColor,
|
|
6334
|
+
width: 1.5,
|
|
6335
|
+
},
|
|
6336
|
+
},
|
|
6337
|
+
]
|
|
6338
|
+
: [];
|
|
6285
6339
|
// Draw mean line for all data
|
|
6286
|
-
var allData = __spreadArray(__spreadArray([], data, true), unselectedData, true);
|
|
6287
6340
|
var allDataMeanValue = (_c = calculateMean(allData)) !== null && _c !== void 0 ? _c : 0;
|
|
6288
|
-
var allDataMeanLine =
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6341
|
+
var allDataMeanLine = statsAnnotations.includes("mean") &&
|
|
6342
|
+
unselectedData.length > 0 &&
|
|
6343
|
+
data.length > 0
|
|
6344
|
+
? [
|
|
6345
|
+
{
|
|
6346
|
+
type: "line",
|
|
6347
|
+
x0: allDataMeanValue,
|
|
6348
|
+
y0: 1 - meanLineRadius,
|
|
6349
|
+
x1: allDataMeanValue,
|
|
6350
|
+
yref: "paper",
|
|
6351
|
+
y1: 1 + meanLineRadius + 0.04, // Add extra length above to make the line look centered on the y-axis top.
|
|
6352
|
+
line: {
|
|
6353
|
+
color: unselectedBarColor,
|
|
6354
|
+
width: 1.5,
|
|
6355
|
+
},
|
|
6356
|
+
},
|
|
6357
|
+
]
|
|
6358
|
+
: [];
|
|
6359
|
+
var stdevLines = statsAnnotations.includes("stdev") && data.length > 0
|
|
6360
|
+
? [
|
|
6361
|
+
{
|
|
6362
|
+
type: "line",
|
|
6363
|
+
x0: meanValue - stdevValue,
|
|
6364
|
+
y0: 1 - meanLineRadius,
|
|
6365
|
+
x1: meanValue - stdevValue,
|
|
6366
|
+
yref: "paper",
|
|
6367
|
+
y1: 1 + meanLineRadius + 0.04, // Add extra length above to make the line look centered on the y-axis top.
|
|
6368
|
+
line: {
|
|
6369
|
+
color: barColor,
|
|
6370
|
+
width: 1.5,
|
|
6371
|
+
dash: "dot",
|
|
6372
|
+
},
|
|
6373
|
+
},
|
|
6374
|
+
{
|
|
6375
|
+
type: "line",
|
|
6376
|
+
x0: meanValue + stdevValue,
|
|
6377
|
+
y0: 1 - meanLineRadius,
|
|
6378
|
+
x1: meanValue + stdevValue,
|
|
6379
|
+
yref: "paper",
|
|
6380
|
+
y1: 1 + meanLineRadius + 0.04, // Add extra length above to make the line look centered on the y-axis top.
|
|
6381
|
+
line: {
|
|
6382
|
+
color: barColor,
|
|
6383
|
+
width: 1.5,
|
|
6384
|
+
dash: "dot",
|
|
6385
|
+
},
|
|
6386
|
+
},
|
|
6387
|
+
]
|
|
6326
6388
|
: [];
|
|
6327
6389
|
var allDataStdevValue = (_d = calculateStandardDeviation(allData)) !== null && _d !== void 0 ? _d : 0;
|
|
6328
|
-
var allDataStdevLines =
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6390
|
+
var allDataStdevLines = statsAnnotations.includes("stdev") &&
|
|
6391
|
+
unselectedData.length > 0 &&
|
|
6392
|
+
data.length > 0
|
|
6393
|
+
? [
|
|
6394
|
+
{
|
|
6395
|
+
type: "line",
|
|
6396
|
+
x0: allDataMeanValue - allDataStdevValue,
|
|
6397
|
+
y0: 1 - meanLineRadius,
|
|
6398
|
+
x1: allDataMeanValue - allDataStdevValue,
|
|
6399
|
+
yref: "paper",
|
|
6400
|
+
y1: 1 + meanLineRadius + 0.04, // Add extra length above to make the line look centered on the y-axis top.
|
|
6401
|
+
line: {
|
|
6402
|
+
color: unselectedBarColor,
|
|
6403
|
+
width: 1.5,
|
|
6404
|
+
dash: "dot",
|
|
6405
|
+
},
|
|
6406
|
+
},
|
|
6407
|
+
{
|
|
6408
|
+
type: "line",
|
|
6409
|
+
x0: allDataMeanValue + allDataStdevValue,
|
|
6410
|
+
y0: 1 - meanLineRadius,
|
|
6411
|
+
x1: allDataMeanValue + allDataStdevValue,
|
|
6412
|
+
yref: "paper",
|
|
6413
|
+
y1: 1 + meanLineRadius + 0.04, // Add extra length above to make the line look centered on the y-axis top.
|
|
6414
|
+
line: {
|
|
6415
|
+
color: unselectedBarColor,
|
|
6416
|
+
width: 1.5,
|
|
6417
|
+
dash: "dot",
|
|
6418
|
+
},
|
|
6419
|
+
},
|
|
6420
|
+
]
|
|
6354
6421
|
: [];
|
|
6355
|
-
// If binSizeOverride is provided, use it to set the bin size and range explicitly.
|
|
6422
|
+
// If binSizeOverride is provided, use it to set the bin size and range explicitly.
|
|
6356
6423
|
// Plotly does a better job of setting bins and ending them at nice numbers, so only use
|
|
6357
6424
|
// this prop when necessary.
|
|
6358
|
-
var xBins =
|
|
6359
|
-
?
|
|
6425
|
+
var xBins = binSizeOverride && allData.length > 0
|
|
6426
|
+
? isDateArray(allData)
|
|
6360
6427
|
? {
|
|
6361
6428
|
start: roundToPrevDay(Math.min.apply(Math, allData.map(function (d) { return d.getTime(); }))), // Find a nice round number as a starting point.
|
|
6362
6429
|
end: roundToNextDay(Math.max.apply(Math, allData.map(function (d) { return d.getTime(); }))),
|
|
6363
|
-
size: binSizeOverride // bin size in milliseconds
|
|
6430
|
+
size: binSizeOverride, // bin size in milliseconds
|
|
6364
6431
|
}
|
|
6365
6432
|
: isNumberArray(allData)
|
|
6366
6433
|
? {
|
|
6367
6434
|
start: Math.floor(Math.min.apply(Math, allData)),
|
|
6368
6435
|
end: Math.ceil(Math.max.apply(Math, allData)),
|
|
6369
|
-
size: binSizeOverride
|
|
6436
|
+
size: binSizeOverride,
|
|
6370
6437
|
}
|
|
6371
|
-
: undefined
|
|
6438
|
+
: undefined
|
|
6372
6439
|
: undefined;
|
|
6373
6440
|
var unselectedTrace = {
|
|
6374
6441
|
x: unselectedData,
|
|
6375
|
-
type:
|
|
6442
|
+
type: "histogram",
|
|
6376
6443
|
autobinx: false,
|
|
6377
6444
|
xbins: xBins,
|
|
6378
6445
|
// nbinsx is valid but not included in the type definition
|
|
@@ -6385,59 +6452,73 @@ var HistogramPlot = function (props) {
|
|
|
6385
6452
|
width: 0.5,
|
|
6386
6453
|
},
|
|
6387
6454
|
},
|
|
6388
|
-
hovertemplate:
|
|
6455
|
+
hovertemplate: "[%{x})<br>Count: %{y}<extra></extra>",
|
|
6389
6456
|
};
|
|
6390
|
-
var meanAnnotation =
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6457
|
+
var meanAnnotation = statsAnnotations.includes("mean") && meanLine && data.length > 0
|
|
6458
|
+
? [
|
|
6459
|
+
{
|
|
6460
|
+
x: meanValue,
|
|
6461
|
+
y: 1 + meanLineRadius + 0.04, // Position above the mean line. Value set with respect to the paper coordinates.
|
|
6462
|
+
yref: "paper",
|
|
6463
|
+
text: "<span style=\"font-weight:300\">AVG </span><span style=\"font-weight:600\">".concat(isDateArray(data)
|
|
6464
|
+
? new Date(meanValue).toLocaleDateString("en-US", {
|
|
6465
|
+
month: "2-digit",
|
|
6466
|
+
day: "2-digit",
|
|
6467
|
+
year: "2-digit",
|
|
6468
|
+
})
|
|
6469
|
+
: meanValue.toFixed(2), "</span>"),
|
|
6470
|
+
xanchor: "center",
|
|
6471
|
+
yanchor: "bottom",
|
|
6472
|
+
showarrow: false,
|
|
6473
|
+
font: {
|
|
6474
|
+
color: barColor,
|
|
6475
|
+
size: 12,
|
|
6476
|
+
},
|
|
6405
6477
|
},
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6478
|
+
]
|
|
6479
|
+
: [];
|
|
6480
|
+
var stdevAnnotation = statsAnnotations.includes("stdev") && stdevLines && data.length > 0
|
|
6481
|
+
? [
|
|
6482
|
+
{
|
|
6483
|
+
x: meanValue, // Draw above the mean annotation
|
|
6484
|
+
y: 1 +
|
|
6485
|
+
meanLineRadius +
|
|
6486
|
+
(statsAnnotations.includes("mean") ? 0.11 : 0.04),
|
|
6487
|
+
yref: "paper",
|
|
6488
|
+
text: "<span style=\"font-weight:300\">\u03C3 </span><span style=\"font-weight:600\">±".concat(isDateArray(data)
|
|
6489
|
+
? new Date(stdevValue).toLocaleDateString("en-US", {
|
|
6490
|
+
month: "2-digit",
|
|
6491
|
+
day: "2-digit",
|
|
6492
|
+
year: "2-digit",
|
|
6493
|
+
})
|
|
6494
|
+
: stdevValue.toFixed(2), "</span>"),
|
|
6495
|
+
xanchor: "center",
|
|
6496
|
+
yanchor: "bottom",
|
|
6497
|
+
showarrow: false,
|
|
6498
|
+
font: {
|
|
6499
|
+
color: barColor,
|
|
6500
|
+
size: 12,
|
|
6501
|
+
},
|
|
6422
6502
|
},
|
|
6423
|
-
|
|
6503
|
+
]
|
|
6504
|
+
: [];
|
|
6424
6505
|
var plotlyData = [
|
|
6425
6506
|
{
|
|
6426
6507
|
x: data,
|
|
6427
|
-
type:
|
|
6508
|
+
type: "histogram",
|
|
6428
6509
|
autobinx: false,
|
|
6429
6510
|
xbins: xBins,
|
|
6430
6511
|
// nbinsx is valid but not included in the type definition
|
|
6431
6512
|
//@ts-ignore
|
|
6432
6513
|
nbinsx: nBins, // Maximum number of bins. Plotly may adjust to make bins "nicer".
|
|
6433
6514
|
marker: {
|
|
6434
|
-
color: barColor !== null && barColor !== void 0 ? barColor :
|
|
6515
|
+
color: barColor !== null && barColor !== void 0 ? barColor : "blue",
|
|
6435
6516
|
line: {
|
|
6436
6517
|
color: "white",
|
|
6437
6518
|
width: 0.5,
|
|
6438
6519
|
},
|
|
6439
6520
|
},
|
|
6440
|
-
hovertemplate:
|
|
6521
|
+
hovertemplate: "[%{x})<br>Count: %{y}<extra></extra>", // Custom hover text
|
|
6441
6522
|
},
|
|
6442
6523
|
unselectedTrace,
|
|
6443
6524
|
];
|
|
@@ -6445,63 +6526,66 @@ var HistogramPlot = function (props) {
|
|
|
6445
6526
|
title: {
|
|
6446
6527
|
text: title,
|
|
6447
6528
|
},
|
|
6448
|
-
barmode:
|
|
6529
|
+
barmode: "stack", // Stack unselected bars on top of selected bars
|
|
6449
6530
|
showlegend: false,
|
|
6450
6531
|
autosize: true,
|
|
6451
6532
|
width: undefined, // Let autosize handle width
|
|
6452
6533
|
height: undefined, // Let autosize handle height
|
|
6453
6534
|
margin: {
|
|
6454
6535
|
l: 50,
|
|
6455
|
-
r: 35, // Balance between ensuring the mean annotation doesn't get cut off and having too much margin.
|
|
6536
|
+
r: 35, // Balance between ensuring the mean annotation doesn't get cut off and having too much margin.
|
|
6456
6537
|
t: 40 + (title ? 50 : 0), // Add extra top margin if there is a title
|
|
6457
6538
|
b: 50,
|
|
6458
|
-
pad: 4
|
|
6539
|
+
pad: 4,
|
|
6459
6540
|
},
|
|
6460
6541
|
xaxis: {
|
|
6461
6542
|
title: {
|
|
6462
|
-
text: xAxisTitle
|
|
6543
|
+
text: xAxisTitle,
|
|
6463
6544
|
},
|
|
6464
6545
|
range: fixedXAxisRange, // Fixed range prevents axis shifting during interaction or data updates
|
|
6465
6546
|
showgrid: true,
|
|
6466
6547
|
zeroline: false,
|
|
6467
6548
|
showline: true,
|
|
6468
|
-
mirror:
|
|
6469
|
-
gridcolor:
|
|
6549
|
+
mirror: "ticks",
|
|
6550
|
+
gridcolor: "#efefef",
|
|
6470
6551
|
gridwidth: 0.2,
|
|
6471
|
-
zerolinecolor:
|
|
6552
|
+
zerolinecolor: "#969696",
|
|
6472
6553
|
zerolinewidth: 1,
|
|
6473
|
-
linecolor:
|
|
6554
|
+
linecolor: "#bababa",
|
|
6474
6555
|
linewidth: 1,
|
|
6475
6556
|
fixedrange: true, // Disable zooming
|
|
6476
|
-
ticklabelposition:
|
|
6557
|
+
ticklabelposition: "outside",
|
|
6477
6558
|
tickformat: isDateArray(data) ? dateTickFormat : undefined, // Format ticks for dates
|
|
6478
6559
|
automargin: true, // Adjust margin if tick labels rotate
|
|
6479
|
-
hoverformat:
|
|
6560
|
+
hoverformat: isNumberArray(allData) &&
|
|
6561
|
+
Math.max.apply(Math, allData) - Math.min.apply(Math, allData) > 3
|
|
6562
|
+
? ".1~f"
|
|
6563
|
+
: undefined,
|
|
6480
6564
|
},
|
|
6481
6565
|
yaxis: {
|
|
6482
6566
|
title: {
|
|
6483
|
-
text:
|
|
6567
|
+
text: "Count",
|
|
6484
6568
|
standoff: 12, // Add space between title and axis
|
|
6485
6569
|
},
|
|
6486
6570
|
automargin: true, // Required for standoff to work properly
|
|
6487
6571
|
showgrid: true,
|
|
6488
6572
|
zeroline: false,
|
|
6489
6573
|
showline: true,
|
|
6490
|
-
mirror:
|
|
6491
|
-
gridcolor:
|
|
6574
|
+
mirror: "ticks",
|
|
6575
|
+
gridcolor: "#efefef",
|
|
6492
6576
|
gridwidth: 0.2,
|
|
6493
|
-
zerolinecolor:
|
|
6577
|
+
zerolinecolor: "#969696",
|
|
6494
6578
|
zerolinewidth: 1,
|
|
6495
|
-
linecolor:
|
|
6579
|
+
linecolor: "#bababa",
|
|
6496
6580
|
linewidth: 1,
|
|
6497
6581
|
fixedrange: true, // Disable zooming
|
|
6498
|
-
ticksuffix:
|
|
6582
|
+
ticksuffix: " ", // Add space between y axis and ticks
|
|
6499
6583
|
},
|
|
6500
6584
|
bargap: 0.03, // Gap between bars
|
|
6501
|
-
dragmode:
|
|
6502
|
-
selectdirection:
|
|
6585
|
+
dragmode: "select", // Enable drag to select
|
|
6586
|
+
selectdirection: "h", // User can select in horizontal direction only
|
|
6503
6587
|
shapes: __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], allDataMeanLine, true), meanLine, true), selectedRangeBox, true), stdevLines, true), allDataStdevLines, true), // Add the mean line and selection box
|
|
6504
|
-
annotations: __spreadArray(__spreadArray([], meanAnnotation, true), stdevAnnotation, true)
|
|
6588
|
+
annotations: __spreadArray(__spreadArray([], meanAnnotation, true), stdevAnnotation, true),
|
|
6505
6589
|
};
|
|
6506
6590
|
var config = {
|
|
6507
6591
|
responsive: true, // Make the plot responsive
|
|
@@ -6511,14 +6595,14 @@ var HistogramPlot = function (props) {
|
|
|
6511
6595
|
staticPlot: false, // Enable interactivity
|
|
6512
6596
|
};
|
|
6513
6597
|
var containerStyles = __assign({ width: "100%", height: "100%", position: "relative" }, containerStyleOverrides);
|
|
6514
|
-
return (jsx("div", { ref: containerRef, className: "plot-container ".concat(plotId), style: __assign({
|
|
6598
|
+
return (jsx("div", { ref: containerRef, className: "plot-container ".concat(plotId), style: __assign({ "--selection-color": selectorsColor }, containerStyles), children: jsx(Suspense, { fallback: jsx(Loading, {}), children: jsx(Fragment, { children: jsx(Plot$2, { data: plotlyData, layout: layout, config: config, onSelected: handleSelection, onClick: handleClick, onDeselect: function () {
|
|
6515
6599
|
onDeselect();
|
|
6516
6600
|
setSelectedRange(null); // Remove selected box
|
|
6517
6601
|
}, onUpdate: handlePlotUpdate, useResizeHandler: true, style: {
|
|
6518
6602
|
width: "100%",
|
|
6519
6603
|
height: "100%",
|
|
6520
|
-
display: "block"
|
|
6521
|
-
} }, "histogram-".concat(plotId ||
|
|
6604
|
+
display: "block",
|
|
6605
|
+
} }, "histogram-".concat(plotId || "default")) }) }) }));
|
|
6522
6606
|
};
|
|
6523
6607
|
|
|
6524
6608
|
var Plot$1 = lazy(function () { return import('react-plotly.js'); });
|