td-plots 1.5.2 → 1.5.3
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 +1 -1
- package/dist/index.esm.js +103 -77
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +103 -77
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ export type HistogramPlotProps = {
|
|
|
9
9
|
barColor?: string;
|
|
10
10
|
unselectedBarColor?: string;
|
|
11
11
|
selectorsColor?: string;
|
|
12
|
-
handleClickOrSelection?: (minValue: number | Date, maxValue: number | Date) => void;
|
|
12
|
+
handleClickOrSelection?: (minValue: number | Date, maxValue: number | Date, shiftKeyPressed?: boolean) => void;
|
|
13
13
|
containerStyleOverrides?: React.CSSProperties;
|
|
14
14
|
onDeselect?: () => void;
|
|
15
15
|
plotId?: string;
|
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;
|
|
@@ -6080,6 +6057,8 @@ var HistogramPlot = function (props) {
|
|
|
6080
6057
|
var containerRef = useRef(null);
|
|
6081
6058
|
// Track any selections made in this plot so we can style the selection box.
|
|
6082
6059
|
var _o = useState(null), selectedRange = _o[0], setSelectedRange = _o[1];
|
|
6060
|
+
// Combine all data into one for later calculations
|
|
6061
|
+
var allData = __spreadArray(__spreadArray([], data, true), unselectedData, true);
|
|
6083
6062
|
// If all the data becomes selected, we should forget any old selections.
|
|
6084
6063
|
useEffect(function () {
|
|
6085
6064
|
if (unselectedData.length === 0) {
|
|
@@ -6092,6 +6071,8 @@ var HistogramPlot = function (props) {
|
|
|
6092
6071
|
// to access that information once the plot has been initialized so that we can prevent the
|
|
6093
6072
|
// axis range from changing during interaction. Dates use strings.
|
|
6094
6073
|
var _p = useState(undefined), fixedXAxisRange = _p[0], setFixedXAxisRange = _p[1];
|
|
6074
|
+
// track xbins too
|
|
6075
|
+
var _q = useState(undefined), binSize = _q[0], setBinSize = _q[1];
|
|
6095
6076
|
// Once the plot is drawn, record the initial axis range so we can keep it fixed.
|
|
6096
6077
|
// figure should be Readonly<Plotly.Figure> but react-plotly.js doesn't expose that type, so we use any.
|
|
6097
6078
|
var handlePlotUpdate = function (figure, graphDiv) {
|
|
@@ -6107,17 +6088,42 @@ var HistogramPlot = function (props) {
|
|
|
6107
6088
|
setFixedXAxisRange(range);
|
|
6108
6089
|
}
|
|
6109
6090
|
}
|
|
6091
|
+
if (!binSize) {
|
|
6092
|
+
// Get the bin size from the first trace. Both traces should have the same bin size.
|
|
6093
|
+
if (figure && figure.data && figure.data.length > 0 && figure.data[0].xbins && figure.data[0].xbins.size) {
|
|
6094
|
+
setBinSize(figure.data[0].xbins.size);
|
|
6095
|
+
}
|
|
6096
|
+
}
|
|
6110
6097
|
};
|
|
6098
|
+
// Track shift key state
|
|
6099
|
+
var isShiftPressed = useRef(false);
|
|
6100
|
+
// Add keyboard event listeners to track shift key
|
|
6101
|
+
useEffect(function () {
|
|
6102
|
+
var handleKeyDown = function (e) {
|
|
6103
|
+
if (e.key === 'Shift') {
|
|
6104
|
+
isShiftPressed.current = true;
|
|
6105
|
+
}
|
|
6106
|
+
};
|
|
6107
|
+
var handleKeyUp = function (e) {
|
|
6108
|
+
if (e.key === 'Shift') {
|
|
6109
|
+
isShiftPressed.current = false;
|
|
6110
|
+
}
|
|
6111
|
+
};
|
|
6112
|
+
// Add event listeners to document to catch shift key globally
|
|
6113
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
6114
|
+
document.addEventListener('keyup', handleKeyUp);
|
|
6115
|
+
// Cleanup
|
|
6116
|
+
return function () {
|
|
6117
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
6118
|
+
document.removeEventListener('keyup', handleKeyUp);
|
|
6119
|
+
};
|
|
6120
|
+
}, []);
|
|
6111
6121
|
// Create handler for click event that can use event data to update the plot if desired.
|
|
6112
6122
|
var handleClick = function (event) {
|
|
6123
|
+
var _a, _b, _c, _d;
|
|
6113
6124
|
if (!event || !event.points || event.points.length === 0) {
|
|
6114
6125
|
return;
|
|
6115
6126
|
}
|
|
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
6127
|
// Use the bin number to determine which bar was clicked and determine the range of the clicked bar.
|
|
6122
6128
|
if ("binNumber" in event.points[0] && typeof event.points[0].binNumber === 'number') {
|
|
6123
6129
|
// Get the index of the clicked bar with respect to the trace. So if
|
|
@@ -6133,40 +6139,48 @@ var HistogramPlot = function (props) {
|
|
|
6133
6139
|
var globalFirstBinStart = void 0;
|
|
6134
6140
|
if (isDateArray(data)) {
|
|
6135
6141
|
// Date bins are represented as strings (sometimes). We'll need to convert whatever plotly gives us to timestamps.
|
|
6136
|
-
globalFirstBinStart =
|
|
6137
|
-
minTraceValue = Math.min.apply(Math, data.map(function (d) { return d.getTime(); }));
|
|
6142
|
+
globalFirstBinStart = fixedXAxisRange ? new Date(fixedXAxisRange[0]).getTime() : new Date(event.points[0].data.xbins.start).getTime();
|
|
6143
|
+
minTraceValue = (event.points[0].curveNumber === 0) ? Math.min.apply(Math, data.map(function (d) { return d.getTime(); })) : Math.min.apply(Math, unselectedData.map(function (d) { return d.getTime(); }));
|
|
6138
6144
|
}
|
|
6139
6145
|
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
6146
|
// Get the min value of the trace and the beginning of the first bin (globally)
|
|
6146
|
-
minTraceValue = Math.min.apply(Math, data);
|
|
6147
|
-
globalFirstBinStart = event.points[0].data.xbins.start;
|
|
6147
|
+
minTraceValue = (event.points[0].curveNumber === 0) ? Math.min.apply(Math, data) : Math.min.apply(Math, unselectedData);
|
|
6148
|
+
globalFirstBinStart = fixedXAxisRange ? fixedXAxisRange[0] : event.points[0].data.xbins.start;
|
|
6148
6149
|
}
|
|
6149
6150
|
// Finally, we need to calculate the min and max values of the clicked bin.
|
|
6150
6151
|
// If the bin size is a month or more, plotly records it in their "mstring" format like "M3" for 3 months.
|
|
6151
6152
|
// We then must convert it back to milliseconds. Otherwise, it's always ms.
|
|
6152
|
-
var binSize =
|
|
6153
|
-
|
|
6154
|
-
|
|
6153
|
+
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;
|
|
6154
|
+
var convertedBinSize = typeof size === 'string'
|
|
6155
|
+
? plotlyMToMilliseconds(size)
|
|
6156
|
+
: size;
|
|
6155
6157
|
// This minTraceValue is in the 0th bin of this trace. Find the index of this bin in the whole plot.
|
|
6156
|
-
var clickedBinGlobalIndex = clickedBinIndex + Math.floor((minTraceValue - globalFirstBinStart) /
|
|
6157
|
-
var
|
|
6158
|
-
globalFirstBinStart + clickedBinGlobalIndex *
|
|
6159
|
-
globalFirstBinStart + (clickedBinGlobalIndex + 1) *
|
|
6160
|
-
], minBinValue =
|
|
6158
|
+
var clickedBinGlobalIndex = clickedBinIndex + Math.floor((minTraceValue - globalFirstBinStart) / convertedBinSize);
|
|
6159
|
+
var _e = [
|
|
6160
|
+
globalFirstBinStart + clickedBinGlobalIndex * convertedBinSize,
|
|
6161
|
+
globalFirstBinStart + (clickedBinGlobalIndex + 1) * convertedBinSize
|
|
6162
|
+
], minBinValue = _e[0], maxBinValue = _e[1];
|
|
6161
6163
|
if (isDateArray(data)) {
|
|
6162
6164
|
var minDate = new Date(minBinValue);
|
|
6163
6165
|
var maxDate = new Date(maxBinValue);
|
|
6164
|
-
handleClickOrSelection(minDate, maxDate);
|
|
6165
|
-
|
|
6166
|
+
handleClickOrSelection(minDate, maxDate, isShiftPressed.current);
|
|
6167
|
+
var newMinMax = [minDate, maxDate];
|
|
6168
|
+
if (isShiftPressed.current && selectedRange) {
|
|
6169
|
+
setSelectedRange(__spreadArray(__spreadArray([], selectedRange, true), [newMinMax], false));
|
|
6170
|
+
}
|
|
6171
|
+
else {
|
|
6172
|
+
setSelectedRange([newMinMax]);
|
|
6173
|
+
}
|
|
6166
6174
|
}
|
|
6167
6175
|
else {
|
|
6168
|
-
handleClickOrSelection(minBinValue, maxBinValue);
|
|
6169
|
-
|
|
6176
|
+
handleClickOrSelection(minBinValue, maxBinValue, isShiftPressed.current);
|
|
6177
|
+
var newMinMax = [minBinValue, maxBinValue];
|
|
6178
|
+
if (isShiftPressed.current && selectedRange) {
|
|
6179
|
+
setSelectedRange(__spreadArray(__spreadArray([], selectedRange, true), [newMinMax], false));
|
|
6180
|
+
}
|
|
6181
|
+
else {
|
|
6182
|
+
setSelectedRange([newMinMax]);
|
|
6183
|
+
}
|
|
6170
6184
|
}
|
|
6171
6185
|
}
|
|
6172
6186
|
};
|
|
@@ -6188,11 +6202,11 @@ var HistogramPlot = function (props) {
|
|
|
6188
6202
|
var lastBinMidPoint = new Date(event.points[event.points.length - 1].x).getTime();
|
|
6189
6203
|
// If the bin size is a month or more, plotly records it in their "mstring" format like "M3" for 3 months.
|
|
6190
6204
|
// 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 +
|
|
6205
|
+
var convertedBinSize = typeof binSize === 'string'
|
|
6206
|
+
? plotlyMToMilliseconds(binSize)
|
|
6207
|
+
: binSize;
|
|
6208
|
+
minValue = new Date(firstBinMidPoint - convertedBinSize / 2);
|
|
6209
|
+
maxValue = new Date(lastBinMidPoint + convertedBinSize / 2);
|
|
6196
6210
|
}
|
|
6197
6211
|
else {
|
|
6198
6212
|
// No bins selected, so the range should be empty.
|
|
@@ -6212,11 +6226,12 @@ var HistogramPlot = function (props) {
|
|
|
6212
6226
|
// Set the range based on the bins selected. Plotly will include a bin in event.points if
|
|
6213
6227
|
// at least half of it is selected.
|
|
6214
6228
|
if (event.points && event.points.length > 0) {
|
|
6215
|
-
|
|
6216
|
-
var
|
|
6217
|
-
var
|
|
6218
|
-
var
|
|
6219
|
-
var
|
|
6229
|
+
// Find the max and min midpoints. They may be from curve 0 or 1.
|
|
6230
|
+
var firstBinMidPoint = Math.min.apply(Math, event.points.map(function (p) { return p.x; }));
|
|
6231
|
+
var lastBinMidPoint = Math.max.apply(Math, event.points.map(function (p) { return p.x; }));
|
|
6232
|
+
var convertedBinSize = binSize;
|
|
6233
|
+
var roundedMinValue = firstBinMidPoint - convertedBinSize / 2;
|
|
6234
|
+
var roundedMaxValue = lastBinMidPoint + convertedBinSize / 2;
|
|
6220
6235
|
minValue = roundedMinValue;
|
|
6221
6236
|
maxValue = roundedMaxValue;
|
|
6222
6237
|
}
|
|
@@ -6235,12 +6250,24 @@ var HistogramPlot = function (props) {
|
|
|
6235
6250
|
if (minValue !== undefined && maxValue !== undefined) {
|
|
6236
6251
|
// Update selected range. Have to be strict about types.
|
|
6237
6252
|
if (typeof minValue === 'number' && typeof maxValue === 'number') {
|
|
6238
|
-
|
|
6253
|
+
var newMinMax = [minValue, maxValue];
|
|
6254
|
+
if (isShiftPressed.current && selectedRange) {
|
|
6255
|
+
setSelectedRange(__spreadArray(__spreadArray([], selectedRange, true), [newMinMax], false));
|
|
6256
|
+
}
|
|
6257
|
+
else {
|
|
6258
|
+
setSelectedRange([newMinMax]);
|
|
6259
|
+
}
|
|
6239
6260
|
}
|
|
6240
6261
|
else if (minValue instanceof Date && maxValue instanceof Date) {
|
|
6241
|
-
|
|
6262
|
+
var newMinMax = [minValue, maxValue];
|
|
6263
|
+
if (isShiftPressed.current && selectedRange) {
|
|
6264
|
+
setSelectedRange(__spreadArray(__spreadArray([], selectedRange, true), [newMinMax], false));
|
|
6265
|
+
}
|
|
6266
|
+
else {
|
|
6267
|
+
setSelectedRange([newMinMax]);
|
|
6268
|
+
}
|
|
6242
6269
|
}
|
|
6243
|
-
handleClickOrSelection(minValue, maxValue);
|
|
6270
|
+
handleClickOrSelection(minValue, maxValue, isShiftPressed.current);
|
|
6244
6271
|
}
|
|
6245
6272
|
};
|
|
6246
6273
|
// Create the selected range box
|
|
@@ -6251,20 +6278,20 @@ var HistogramPlot = function (props) {
|
|
|
6251
6278
|
return []; // Don't show the box if the entire dataset is selected.
|
|
6252
6279
|
// Create a multiply-like effect by using a semi-transparent dark overlay
|
|
6253
6280
|
var multiplyColor = 'rgba(29, 104, 185, 0.1)';
|
|
6254
|
-
return
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6281
|
+
return selectedRange.map(function (maxMin) { return ({
|
|
6282
|
+
type: 'rect',
|
|
6283
|
+
x0: isDateArray(maxMin) ? maxMin[0].getTime() : maxMin[0],
|
|
6284
|
+
x1: isDateArray(maxMin) ? maxMin[1].getTime() : maxMin[1],
|
|
6285
|
+
y0: 0,
|
|
6286
|
+
y1: 1,
|
|
6287
|
+
yref: 'paper',
|
|
6288
|
+
fillcolor: multiplyColor,
|
|
6289
|
+
line: {
|
|
6290
|
+
width: 1,
|
|
6291
|
+
color: multiplyColor
|
|
6292
|
+
},
|
|
6293
|
+
layer: 'above' // Ensure the selection box is above the bars
|
|
6294
|
+
}); });
|
|
6268
6295
|
}, [selectedRange, unselectedData]);
|
|
6269
6296
|
// Calculate the mean of the selected data using normalized data
|
|
6270
6297
|
var meanValue = (_a = calculateMean(data)) !== null && _a !== void 0 ? _a : 0; // Default to 0 if no data
|
|
@@ -6283,7 +6310,6 @@ var HistogramPlot = function (props) {
|
|
|
6283
6310
|
}
|
|
6284
6311
|
}] : [];
|
|
6285
6312
|
// Draw mean line for all data
|
|
6286
|
-
var allData = __spreadArray(__spreadArray([], data, true), unselectedData, true);
|
|
6287
6313
|
var allDataMeanValue = (_c = calculateMean(allData)) !== null && _c !== void 0 ? _c : 0;
|
|
6288
6314
|
var allDataMeanLine = (statsAnnotations.includes('mean') && unselectedData.length > 0 && data.length > 0) ? [{
|
|
6289
6315
|
type: 'line',
|