td-plots 1.2.0 → 1.2.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.
@@ -4,7 +4,6 @@ export type HistogramPlotProps = {
4
4
  data: number[] | Date[];
5
5
  unselectedData?: number[] | Date[];
6
6
  showMeanLine?: boolean;
7
- meanLineColor?: string;
8
7
  title?: string;
9
8
  xAxisTitle?: string;
10
9
  barColor?: string;
package/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsx as jsx$1, Fragment } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import { forwardRef, useContext, lazy, useRef, Suspense } from 'react';
3
+ import { forwardRef, useContext, lazy, useRef, useState, useMemo, Suspense } from 'react';
4
4
 
5
5
  function styleInject(css, ref) {
6
6
  if ( ref === void 0 ) ref = {};
@@ -7787,9 +7787,13 @@ var Loading = function () {
7787
7787
  var Plot$2 = lazy(function () { return import('react-plotly.js'); });
7788
7788
  var HistogramPlot = function (props) {
7789
7789
  var _a;
7790
- var data = props.data, title = props.title, xAxisTitle = props.xAxisTitle, _b = props.barColor, barColor = _b === void 0 ? 'rgb(72, 72, 74)' : _b, _c = props.unselectedBarColor, unselectedBarColor = _c === void 0 ? 'rgba(203, 195, 195, 0.88)' : _c, _d = props.selectorsColor, selectorsColor = _d === void 0 ? 'black' : _d, _e = props.showMeanLine, showMeanLine = _e === void 0 ? true : _e, _f = props.meanLineColor, meanLineColor = _f === void 0 ? 'grey' : _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;
7790
+ var data = props.data, title = props.title, xAxisTitle = props.xAxisTitle, _b = props.barColor, barColor = _b === void 0 ? 'rgb(72, 72, 74)' : _b, _c = props.unselectedBarColor, unselectedBarColor = _c === void 0 ? 'rgba(203, 195, 195, 0.88)' : _c, _d = props.selectorsColor, selectorsColor = _d === void 0 ? 'black' : _d, _e = props.showMeanLine, showMeanLine = _e === void 0 ? true : _e, containerStyleOverrides = props.containerStyleOverrides, _f = props.unselectedData, unselectedData = _f === void 0 ? [] : _f, _g = props.handleClickOrSelection, handleClickOrSelection = _g === void 0 ? function () { } : _g, _h = props.onDeselect, onDeselect = _h === void 0 ? function () { } : _h, plotId = props.plotId;
7791
7791
  // Ref for plot container
7792
7792
  var containerRef = useRef(null);
7793
+ // Track any selections made in this plot so we can style the selection box.
7794
+ var _j = useState(null), selectedRange = _j[0], setSelectedRange = _j[1];
7795
+ // Set the bins based on the entire data set.
7796
+ var nBins = Math.ceil(Math.sqrt(data.length + unselectedData.length));
7793
7797
  // Create handler for click event that can use event data to update the plot if desired.
7794
7798
  var handleClick = function (event) {
7795
7799
  if (!event || !event.points || event.points.length === 0) {
@@ -7800,9 +7804,8 @@ var HistogramPlot = function (props) {
7800
7804
  if (event.points[0].curveNumber !== 0) {
7801
7805
  return;
7802
7806
  }
7803
- // If we are given a function to update the data (handleClickOrSelection), use
7804
- // the bin number to determine which bar was clicked and determine the range of the clicked bar.
7805
- if (handleClickOrSelection && "binNumber" in event.points[0] && typeof event.points[0].binNumber === 'number') {
7807
+ // Use the bin number to determine which bar was clicked and determine the range of the clicked bar.
7808
+ if ("binNumber" in event.points[0] && typeof event.points[0].binNumber === 'number') {
7806
7809
  // Get the index of the clicked bar with respect to the trace. So if
7807
7810
  // my trace has only one bar (0, 1] but another trace has bars (-1, 0], (0, 1], (1, 2], etc.
7808
7811
  // then when I click on (0, 1] in my trace the index will be 0, even thought it would be
@@ -7841,9 +7844,11 @@ var HistogramPlot = function (props) {
7841
7844
  var minDate = new Date(minBinValue);
7842
7845
  var maxDate = new Date(maxBinValue);
7843
7846
  handleClickOrSelection(minDate, maxDate);
7847
+ setSelectedRange([minDate, maxDate]);
7844
7848
  }
7845
7849
  else {
7846
7850
  handleClickOrSelection(minBinValue, maxBinValue);
7851
+ setSelectedRange([minBinValue, maxBinValue]);
7847
7852
  }
7848
7853
  }
7849
7854
  };
@@ -7858,17 +7863,36 @@ var HistogramPlot = function (props) {
7858
7863
  // Then we must be dealing with dates
7859
7864
  minValue = new Date(event.range.x[0]);
7860
7865
  maxValue = new Date(event.range.x[1]);
7866
+ setSelectedRange([minValue, maxValue]);
7861
7867
  }
7862
7868
  else {
7863
7869
  minValue = event.range.x[0];
7864
7870
  maxValue = event.range.x[1];
7871
+ setSelectedRange([minValue, maxValue]);
7865
7872
  }
7866
- if (handleClickOrSelection) {
7867
- handleClickOrSelection(minValue, maxValue);
7868
- }
7873
+ handleClickOrSelection(minValue, maxValue);
7869
7874
  };
7870
- // Set the bins based on the entire data set.
7871
- var nBins = Math.ceil(Math.sqrt(data.length + unselectedData.length));
7875
+ // Create the selected range box
7876
+ var selectedRangeBox = useMemo(function () {
7877
+ if (!selectedRange)
7878
+ return [];
7879
+ // Create a multiply-like effect by using a semi-transparent dark overlay
7880
+ var multiplyColor = 'rgba(29, 104, 185, 0.1)';
7881
+ return [{
7882
+ type: 'rect',
7883
+ x0: isDateArray(selectedRange) ? selectedRange[0].getTime() : selectedRange[0],
7884
+ x1: isDateArray(selectedRange) ? selectedRange[1].getTime() : selectedRange[1],
7885
+ y0: 0,
7886
+ y1: 1,
7887
+ yref: 'paper',
7888
+ fillcolor: multiplyColor,
7889
+ line: {
7890
+ width: 1,
7891
+ color: multiplyColor
7892
+ },
7893
+ layer: 'above' // Ensure the selection box is above the bars
7894
+ }];
7895
+ }, [selectedRange]);
7872
7896
  var unselectedTrace = {
7873
7897
  x: unselectedData,
7874
7898
  type: 'histogram',
@@ -7917,18 +7941,21 @@ var HistogramPlot = function (props) {
7917
7941
  isDateArray(allData) ? new Date(dataMin - padding) : dataMin - padding,
7918
7942
  isDateArray(allData) ? new Date(dataMax + padding) : dataMax + padding
7919
7943
  ];
7944
+ var meanLineRadius = 0.01; // distance from the top of the y axis to the top/bottom end of the mean line
7920
7945
  var meanLine = showMeanLine ? {
7921
7946
  type: 'line',
7922
7947
  x0: meanValue,
7923
- y0: 0,
7948
+ y0: 1 - meanLineRadius,
7924
7949
  x1: meanValue,
7925
7950
  yref: 'paper',
7926
- y1: 1.04, // Extend slightly above so we can annotate better
7951
+ y1: 1 + meanLineRadius + 0.04, // Add extra length above to make the line look centered on the y-axis top.
7927
7952
  line: {
7928
- color: meanLineColor,
7953
+ color: barColor,
7929
7954
  width: 1.5,
7930
7955
  }
7931
7956
  } : {};
7957
+ // Draw the mean line annotation on right unless the mean is too close to the upper end of the x-axis range.
7958
+ var drawMeanAnnotationOnRight = meanValue < (0.75 * (fixedXAxisRange[1] - fixedXAxisRange[0]) + fixedXAxisRange[0]);
7932
7959
  var layout = {
7933
7960
  title: {
7934
7961
  text: title,
@@ -7965,8 +7992,10 @@ var HistogramPlot = function (props) {
7965
7992
  },
7966
7993
  yaxis: {
7967
7994
  title: {
7968
- text: 'Count'
7995
+ text: 'Count',
7996
+ standoff: 12, // Add space between title and axis
7969
7997
  },
7998
+ automargin: true, // Required for standoff to work properly
7970
7999
  showgrid: true,
7971
8000
  zeroline: false,
7972
8001
  showline: true,
@@ -7983,19 +8012,22 @@ var HistogramPlot = function (props) {
7983
8012
  bargap: 0.03, // Gap between bars
7984
8013
  dragmode: 'select', // Enable drag to select
7985
8014
  selectdirection: 'h', // User can select in horizontal direction only
7986
- shapes: meanLine ? [meanLine] : [], // Add the mean line if it exists
7987
- annotations: showMeanLine ? [{
8015
+ shapes: __spreadArray([meanLine], selectedRangeBox, true), // Add the mean line and selection box
8016
+ annotations: (showMeanLine && meanLine) ? [{
7988
8017
  x: meanValue,
7989
- y: 1.12, // Position above the top of the plot
8018
+ y: 1 + meanLineRadius + 0.12, // Position above the mean line
7990
8019
  yref: 'paper',
7991
8020
  text: "Mean: ".concat(isDateArray(data) ? new Date(meanValue).toLocaleDateString('en-US', {
7992
8021
  month: 'short',
7993
8022
  day: '2-digit',
7994
8023
  year: 'numeric'
7995
8024
  }) : meanValue.toFixed(2)),
7996
- showarrow: false, // No arrow for the annotation
8025
+ xanchor: drawMeanAnnotationOnRight ? 'left' : 'right',
8026
+ yanchor: 'top',
8027
+ xshift: drawMeanAnnotationOnRight ? -3 : 3,
8028
+ showarrow: false,
7997
8029
  font: {
7998
- color: meanLineColor,
8030
+ color: barColor,
7999
8031
  size: 12,
8000
8032
  },
8001
8033
  }] : [],
@@ -8008,7 +8040,10 @@ var HistogramPlot = function (props) {
8008
8040
  staticPlot: false, // Enable interactivity
8009
8041
  };
8010
8042
  var containerStyles = __assign({ width: "100%", height: "100%", position: "relative" }, containerStyleOverrides);
8011
- return (jsx$1("div", { ref: containerRef, className: "plot-container ".concat(plotId), style: __assign({ '--selection-color': selectorsColor }, containerStyles), children: jsx$1(Suspense, { fallback: jsx$1(Loading, {}), children: jsx$1(Fragment, { children: jsx$1(Plot$2, { data: plotlyData, layout: layout, config: config, onSelected: handleSelection, onClick: handleClick, onDeselect: onDeselect, useResizeHandler: true, style: {
8043
+ return (jsx$1("div", { ref: containerRef, className: "plot-container ".concat(plotId), style: __assign({ '--selection-color': selectorsColor }, containerStyles), children: jsx$1(Suspense, { fallback: jsx$1(Loading, {}), children: jsx$1(Fragment, { children: jsx$1(Plot$2, { data: plotlyData, layout: layout, config: config, onSelected: handleSelection, onClick: handleClick, onDeselect: function () {
8044
+ onDeselect();
8045
+ setSelectedRange(null); // Remove selected box
8046
+ }, useResizeHandler: true, style: {
8012
8047
  width: "100%",
8013
8048
  height: "100%",
8014
8049
  display: "block"