td-plots 1.2.2 → 1.3.1

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.
@@ -3,8 +3,7 @@ import './plotStyles.scss';
3
3
  export type HistogramPlotProps = {
4
4
  data: number[] | Date[];
5
5
  unselectedData?: number[] | Date[];
6
- showMeanLine?: boolean;
7
- showAllDataMeanLine?: boolean;
6
+ showMeanLines?: boolean;
8
7
  title?: string;
9
8
  xAxisTitle?: string;
10
9
  barColor?: string;
@@ -14,6 +13,7 @@ export type HistogramPlotProps = {
14
13
  containerStyleOverrides?: React.CSSProperties;
15
14
  onDeselect?: () => void;
16
15
  plotId?: string;
16
+ selectByBin?: boolean;
17
17
  };
18
18
  export declare const HistogramPlot: (props: HistogramPlotProps) => import("react/jsx-runtime").JSX.Element;
19
19
  export default HistogramPlot;
package/dist/index.esm.js CHANGED
@@ -5840,7 +5840,7 @@ var Loading = function () {
5840
5840
  var Plot$2 = lazy(function () { return import('react-plotly.js'); });
5841
5841
  var HistogramPlot = function (props) {
5842
5842
  var _a, _b;
5843
- var data = props.data, title = props.title, xAxisTitle = props.xAxisTitle, _c = props.barColor, barColor = _c === void 0 ? 'rgb(72, 72, 74)' : _c, _d = props.unselectedBarColor, unselectedBarColor = _d === void 0 ? 'rgba(203, 195, 195, 0.88)' : _d, _e = props.selectorsColor, selectorsColor = _e === void 0 ? 'black' : _e, _f = props.showMeanLine, showMeanLine = _f === void 0 ? true : _f, _g = props.showAllDataMeanLine, showAllDataMeanLine = _g === void 0 ? true : _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;
5843
+ var data = props.data, title = props.title, xAxisTitle = props.xAxisTitle, _c = props.barColor, barColor = _c === void 0 ? 'rgb(72, 72, 74)' : _c, _d = props.unselectedBarColor, unselectedBarColor = _d === void 0 ? 'rgba(203, 195, 195, 0.88)' : _d, _e = props.selectorsColor, selectorsColor = _e === void 0 ? 'black' : _e, _f = props.showMeanLines, showMeanLines = _f === void 0 ? true : _f, containerStyleOverrides = props.containerStyleOverrides, _g = props.unselectedData, unselectedData = _g === void 0 ? [] : _g, _h = props.handleClickOrSelection, handleClickOrSelection = _h === void 0 ? function () { } : _h, _j = props.onDeselect, onDeselect = _j === void 0 ? function () { } : _j, plotId = props.plotId, _k = props.selectByBin, selectByBin = _k === void 0 ? false : _k;
5844
5844
  // Ref for plot container
5845
5845
  var containerRef = useRef(null);
5846
5846
  // Track any selections made in this plot so we can style the selection box.
@@ -5851,14 +5851,23 @@ var HistogramPlot = function (props) {
5851
5851
  // to access that information once the plot has been initialized so that we can prevent the
5852
5852
  // axis range from changing during interaction. Dates use strings.
5853
5853
  var _m = useState(undefined), fixedXAxisRange = _m[0], setFixedXAxisRange = _m[1];
5854
+ // Once the plot is drawn, record the initial axis range so we can keep it fixed.
5854
5855
  // figure should be Readonly<Plotly.Figure> but react-plotly.js doesn't expose that type, so we use any.
5855
- var handlePlotInitialized = function (figure, graphDiv) {
5856
- var _a, _b;
5857
- if (((_b = (_a = figure.layout) === null || _a === void 0 ? void 0 : _a.xaxis) === null || _b === void 0 ? void 0 : _b.range) && !fixedXAxisRange) {
5858
- var computedRange = typeof (figure.layout.xaxis.range[0]) === 'string'
5859
- ? [new Date(figure.layout.xaxis.range[0]), new Date(figure.layout.xaxis.range[1])]
5860
- : [figure.layout.xaxis.range[0], figure.layout.xaxis.range[1]];
5861
- setFixedXAxisRange(computedRange);
5856
+ var handlePlotUpdate = function (figure, graphDiv) {
5857
+ var _a;
5858
+ if (!fixedXAxisRange) {
5859
+ var currentLayout = graphDiv._fullLayout;
5860
+ if ((_a = currentLayout === null || currentLayout === void 0 ? void 0 : currentLayout.xaxis) === null || _a === void 0 ? void 0 : _a.range) {
5861
+ var range = currentLayout.xaxis.range;
5862
+ // Skip temporary [-1, 1] range
5863
+ if (range[0] === -1 && range[1] === 1) {
5864
+ return;
5865
+ }
5866
+ var computedRange = typeof (range[0]) === 'string'
5867
+ ? [new Date(range[0]), new Date(range[1])]
5868
+ : [range[0], range[1]];
5869
+ setFixedXAxisRange(computedRange);
5870
+ }
5862
5871
  }
5863
5872
  };
5864
5873
  // Create handler for click event that can use event data to update the plot if desired.
@@ -5927,22 +5936,73 @@ var HistogramPlot = function (props) {
5927
5936
  var minValue;
5928
5937
  var maxValue;
5929
5938
  if (typeof event.range.x[0] === 'string' && typeof event.range.x[1] === 'string') {
5930
- // Then we must be dealing with dates
5931
- minValue = new Date(event.range.x[0]);
5932
- maxValue = new Date(event.range.x[1]);
5933
- setSelectedRange([minValue, maxValue]);
5939
+ // Then we are must be dealing with dates
5940
+ if (selectByBin) {
5941
+ // Set selected range to include the whole bin if at least half the bin is within the explicit range
5942
+ // Plotly already tells us which bins were selected based on this logic. These are the points in the event.
5943
+ if (event.points && event.points.length > 0) {
5944
+ // Means at least one bin has been selected
5945
+ var firstBinMidPoint = new Date(event.points[0].x).getTime();
5946
+ var lastBinMidPoint = new Date(event.points[event.points.length - 1].x).getTime();
5947
+ var binSize = event.points[0].data.xbins.size;
5948
+ minValue = new Date(firstBinMidPoint - binSize / 2);
5949
+ maxValue = new Date(lastBinMidPoint + binSize / 2);
5950
+ }
5951
+ else {
5952
+ // No bins selected, so the range should be empty.
5953
+ minValue = new Date(event.range.x[0]);
5954
+ maxValue = minValue;
5955
+ }
5956
+ }
5957
+ else {
5958
+ // Set the range based on the explicit selection boundaries
5959
+ minValue = new Date(event.range.x[0]);
5960
+ maxValue = new Date(event.range.x[1]);
5961
+ }
5934
5962
  }
5935
5963
  else {
5936
- minValue = event.range.x[0];
5937
- maxValue = event.range.x[1];
5938
- setSelectedRange([minValue, maxValue]);
5964
+ // Handle selection for numbers
5965
+ if (selectByBin) {
5966
+ // Set the range based on the bins selected. Plotly will include a bin in event.points if
5967
+ // at least half of it is selected.
5968
+ if (event.points && event.points.length > 0) {
5969
+ var firstBinMidPoint = event.points[0].x;
5970
+ var lastBinMidPoint = event.points[event.points.length - 1].x;
5971
+ var binSize = event.points[0].data.xbins.size;
5972
+ var roundedMinValue = firstBinMidPoint - binSize / 2;
5973
+ var roundedMaxValue = lastBinMidPoint + binSize / 2;
5974
+ minValue = roundedMinValue;
5975
+ maxValue = roundedMaxValue;
5976
+ }
5977
+ else {
5978
+ // No bins selected, so set the range to be empty.
5979
+ minValue = event.range.x[0];
5980
+ maxValue = minValue;
5981
+ }
5982
+ }
5983
+ else {
5984
+ // Set the range based on the explicit selection boundaries
5985
+ minValue = event.range.x[0];
5986
+ maxValue = event.range.x[1];
5987
+ }
5988
+ }
5989
+ if (minValue !== undefined && maxValue !== undefined) {
5990
+ // Update selected range. Have to be strict about types.
5991
+ if (typeof minValue === 'number' && typeof maxValue === 'number') {
5992
+ setSelectedRange([minValue, maxValue]);
5993
+ }
5994
+ else if (minValue instanceof Date && maxValue instanceof Date) {
5995
+ setSelectedRange([minValue, maxValue]);
5996
+ }
5997
+ handleClickOrSelection(minValue, maxValue);
5939
5998
  }
5940
- handleClickOrSelection(minValue, maxValue);
5941
5999
  };
5942
6000
  // Create the selected range box
5943
6001
  var selectedRangeBox = useMemo(function () {
5944
6002
  if (!selectedRange)
5945
6003
  return [];
6004
+ if (unselectedData.length === 0)
6005
+ return []; // Don't show the box if the entire dataset is selected.
5946
6006
  // Create a multiply-like effect by using a semi-transparent dark overlay
5947
6007
  var multiplyColor = 'rgba(29, 104, 185, 0.1)';
5948
6008
  return [{
@@ -5959,7 +6019,7 @@ var HistogramPlot = function (props) {
5959
6019
  },
5960
6020
  layer: 'above' // Ensure the selection box is above the bars
5961
6021
  }];
5962
- }, [selectedRange]);
6022
+ }, [selectedRange, unselectedData]);
5963
6023
  var unselectedTrace = {
5964
6024
  x: unselectedData,
5965
6025
  type: 'histogram',
@@ -5998,7 +6058,7 @@ var HistogramPlot = function (props) {
5998
6058
  // Calculate the mean of the selected data using normalized data
5999
6059
  var meanValue = (_a = calculateMean(data)) !== null && _a !== void 0 ? _a : 0; // Default to 0 if no data
6000
6060
  var meanLineRadius = 0.01; // distance from the top of the y axis to the top/bottom end of the mean line
6001
- var meanLine = showMeanLine ? [{
6061
+ var meanLine = (showMeanLines && data.length > 0) ? [{
6002
6062
  type: 'line',
6003
6063
  x0: meanValue,
6004
6064
  y0: 1 - meanLineRadius,
@@ -6013,7 +6073,7 @@ var HistogramPlot = function (props) {
6013
6073
  // Draw mean line for all data
6014
6074
  var allData = __spreadArray(__spreadArray([], data, true), unselectedData, true);
6015
6075
  var allDataMeanValue = (_b = calculateMean(allData)) !== null && _b !== void 0 ? _b : 0;
6016
- var allDataMeanLine = (showAllDataMeanLine && unselectedData.length > 0) ? [{
6076
+ var allDataMeanLine = (showMeanLines && unselectedData.length > 0 && data.length > 0) ? [{
6017
6077
  type: 'line',
6018
6078
  x0: allDataMeanValue,
6019
6079
  y0: 1 - meanLineRadius,
@@ -6082,7 +6142,7 @@ var HistogramPlot = function (props) {
6082
6142
  dragmode: 'select', // Enable drag to select
6083
6143
  selectdirection: 'h', // User can select in horizontal direction only
6084
6144
  shapes: __spreadArray(__spreadArray(__spreadArray([], allDataMeanLine, true), meanLine, true), selectedRangeBox, true), // Add the mean line and selection box
6085
- annotations: (showMeanLine && meanLine) ? [{
6145
+ annotations: (showMeanLines && meanLine && data.length > 0) ? [{
6086
6146
  x: meanValue,
6087
6147
  y: 1 + meanLineRadius + 0.04, // Position above the mean line. Value set with respect to the paper coordinates.
6088
6148
  yref: 'paper',
@@ -6111,7 +6171,7 @@ var HistogramPlot = function (props) {
6111
6171
  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 () {
6112
6172
  onDeselect();
6113
6173
  setSelectedRange(null); // Remove selected box
6114
- }, onInitialized: handlePlotInitialized, useResizeHandler: true, style: {
6174
+ }, onUpdate: handlePlotUpdate, useResizeHandler: true, style: {
6115
6175
  width: "100%",
6116
6176
  height: "100%",
6117
6177
  display: "block"