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