td-plots 1.8.2 → 1.9.0

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.
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+ import { PlotParams } from "react-plotly.js";
3
+ import "./plotStyles.scss";
4
+ export interface LineDataTrace {
5
+ x: number[] | Date[];
6
+ y: number[];
7
+ name?: string;
8
+ color?: string;
9
+ hovertemplate?: string;
10
+ }
11
+ export interface HistogramDataTrace {
12
+ x: number[] | Date[];
13
+ name?: string;
14
+ color?: string;
15
+ hovertemplate?: string;
16
+ }
17
+ export interface LineWithHistogramProps {
18
+ lineData: LineDataTrace;
19
+ histogramData: HistogramDataTrace;
20
+ width?: number;
21
+ height?: number;
22
+ title?: string;
23
+ plotId?: string;
24
+ xAxisTitle?: string;
25
+ yAxisTitle?: string;
26
+ y2AxisTitle?: string;
27
+ containerStyleOverrides?: React.CSSProperties;
28
+ extraLayoutConfig?: Partial<PlotParams["layout"]>;
29
+ revision?: number;
30
+ }
31
+ declare const LineWithHistogram: (props: LineWithHistogramProps) => import("react/jsx-runtime").JSX.Element;
32
+ export default LineWithHistogram;
package/dist/index.d.ts CHANGED
@@ -12,8 +12,7 @@ export type { BoxPlotProps } from "./components/BoxPlot";
12
12
  export { default as SummaryComparisonPlot } from "./components/SummaryComparisonPlot";
13
13
  export type { SummaryComparisonPlotProps } from "./components/SummaryComparisonPlot";
14
14
  export { SummaryComparisonPlotLegend } from "./components/SummaryComparisonPlot";
15
- export { default as LinePlot } from "./components/LinePlot";
16
- export type { LinePlotProps } from "./components/LinePlot";
17
- export { default as TestPlot } from "./components/TestPlot";
15
+ export { default as LineWithHistogram } from "./components/LineWithHistogram";
16
+ export type { LineWithHistogramProps } from "./components/LineWithHistogram";
18
17
  export { isDateArray, isNumberArray } from "./components/Utils";
19
18
  export type { PlotParams } from "react-plotly.js";
package/dist/index.esm.js CHANGED
@@ -36,7 +36,7 @@ function styleInject(css, ref) {
36
36
  }
37
37
  }
38
38
 
39
- var css_248z = ".plot-container{height:100%;max-width:100%;min-height:300px;overflow:hidden!important;position:relative;width:100%}.plot-container>div{flex:1;width:100%!important}.plot-container .main-svg{max-height:100%!important;max-width:100%!important}.plot-container .main-svg,.plot-container .plotly-graph-div,.plot-container svg.main-svg[height],.plot-container svg.main-svg[width]{height:100%!important;width:100%!important}.plot-container .point{border-radius:5px!important;overflow:hidden!important}.plot-container .cursor-ns-resize{height:0;width:0}.plot-container .cursor-ew-resize{fill:var(--selection-color,blue)!important;stroke:var(--selection-color,blue)!important}.plot-container .selectionlayer>path{stroke:var(--selection-color,blue)!important;stroke-dasharray:0!important;stroke-width:1px!important;opacity:.5!important}.plot-container .zoomlayer>path{stroke-dasharray:0!important;stroke:var(--selection-color,blue)!important;fill:var(--selection-color,blue)!important}.radial-histogram-container{aspect-ratio:1}.loading-overlay{align-items:center;background-color:hsla(0,0%,100%,.8);display:flex;height:100%;justify-content:center;left:0;position:absolute;top:0;width:100%;z-index:300}.histogram-controls{pointer-events:auto}.histogram-controls.show-always{opacity:1;visibility:visible}.histogram-controls.show-on-hover{opacity:0;transition:opacity .2s ease-in-out,visibility .2s ease-in-out;visibility:hidden}.histogram .plot-container:hover .histogram-controls.show-on-hover{opacity:1;visibility:visible}";
39
+ var css_248z = ".plot-container{height:100%;max-width:100%;min-height:300px;overflow:hidden!important;position:relative;width:100%}.plot-container>div{flex:1;width:100%!important}.plot-container .main-svg{max-height:100%!important;max-width:100%!important}.plot-container .main-svg,.plot-container .plotly-graph-div,.plot-container svg.main-svg[height],.plot-container svg.main-svg[width]{height:100%!important;width:100%!important}.plot-container .point{border-radius:5px!important;overflow:hidden!important}.plot-container .cursor-ns-resize{height:0;width:0}.plot-container .cursor-ew-resize{fill:var(--selection-color,blue)!important;stroke:var(--selection-color,blue)!important}.plot-container .selectionlayer>path{stroke:var(--selection-color,blue)!important;stroke-dasharray:0!important;stroke-width:1px!important;opacity:.5!important}.plot-container .zoomlayer>path{stroke-dasharray:0!important;stroke:var(--selection-color,blue)!important;fill:var(--selection-color,blue)!important}.radial-histogram-container{aspect-ratio:1}.loading-overlay{align-items:center;background-color:hsla(0,0%,100%,.8);display:flex;height:100%;justify-content:center;left:0;position:absolute;top:0;width:100%;z-index:300}.histogram-controls{pointer-events:auto}.histogram-controls.show-always{opacity:1;visibility:visible}.histogram-controls.show-on-hover{opacity:0;transition:opacity .2s ease-in-out,visibility .2s ease-in-out;visibility:hidden}.plot-container.histogram:hover .histogram-controls.show-on-hover{opacity:1;visibility:visible}";
40
40
  styleInject(css_248z);
41
41
 
42
42
  function formatDecimal(x) {
@@ -539,7 +539,7 @@ var SettingsIcon = createSvgIcon(/*#__PURE__*/jsx("path", {
539
539
  d: "M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6"
540
540
  }), 'Settings');
541
541
 
542
- const Plot$6 = lazy(() => import('react-plotly.js'));
542
+ const Plot$5 = lazy(() => import('react-plotly.js'));
543
543
  const HistogramPlot = (props) => {
544
544
  var _a, _b, _c, _d;
545
545
  const { data, title, xAxisTitle, barColor = "rgb(72, 72, 74)", unselectedBarColor = "rgba(203, 195, 195, 0.88)", selectorsColor = "black", containerStyleOverrides, unselectedData = [], handleClickOrSelection = () => { }, onDeselect = () => { }, plotId, selectByBin = false, dateTickFormat, binSizeOverride, statsAnnotations = ["mean"], emptySelectedRange = false, d3FormatValueString = ".1f", showBinSizeControls = "always", onBinSizeCalculated, onBinSizeChange, showBinSizeControlValue = true, isMobile = false, settingsTitleStylingOverrides = {}, } = props;
@@ -1291,7 +1291,7 @@ const HistogramPlot = (props) => {
1291
1291
  const newBinSize = newValue;
1292
1292
  setBinSize(newBinSize);
1293
1293
  onBinSizeChange === null || onBinSizeChange === void 0 ? void 0 : onBinSizeChange(newBinSize);
1294
- }, colorOverride: barColor, valueLabelFormat: valueLabelFormat, titleStylingOverrides: settingsTitleStylingOverrides, disabledTooltipText: "Requires 10 or more data points" }) }) })] })), jsx(Plot$6, { data: plotlyData, layout: layout, config: config, onSelected: handleSelection, onClick: handleClick, onDeselect: () => {
1294
+ }, colorOverride: barColor, valueLabelFormat: valueLabelFormat, titleStylingOverrides: settingsTitleStylingOverrides, disabledTooltipText: "Requires 10 or more data points" }) }) })] })), jsx(Plot$5, { data: plotlyData, layout: layout, config: config, onSelected: handleSelection, onClick: handleClick, onDeselect: () => {
1295
1295
  onDeselect();
1296
1296
  setSelectedRange(null); // Remove selected box
1297
1297
  }, onUpdate: handlePlotUpdate, useResizeHandler: true, style: {
@@ -1302,7 +1302,7 @@ const HistogramPlot = (props) => {
1302
1302
  } }, `histogram-${plotId || "default"}`)] }) }) }));
1303
1303
  };
1304
1304
 
1305
- const Plot$5 = lazy(() => import('react-plotly.js'));
1305
+ const Plot$4 = lazy(() => import('react-plotly.js'));
1306
1306
  const RadialHistogramPlot = (props) => {
1307
1307
  const { data, barColor = 'rgb(72, 72, 74)', unselectedBarColor = 'rgba(203, 195, 195, 0.88)', selectorsColor = 'black', onSelected, onClick, containerStyleOverrides, barWidth = 20, // Default bar width in degrees
1308
1308
  } = props;
@@ -1402,14 +1402,14 @@ const RadialHistogramPlot = (props) => {
1402
1402
  staticPlot: false,
1403
1403
  };
1404
1404
  const containerStyles = Object.assign({ width: "100%", height: "100%", position: "relative" }, containerStyleOverrides);
1405
- return (jsx("div", { ref: containerRef, className: "plot-container radial-histogram-container", style: Object.assign({ '--selection-color': selectorsColor }, containerStyles), children: jsx(Suspense, { fallback: jsx(Loading, {}), children: jsx(Plot$5, { data: plotlyData, layout: layout, config: config, onSelected: onSelected, onClick: onClick, useResizeHandler: true, style: {
1405
+ return (jsx("div", { ref: containerRef, className: "plot-container radial-histogram-container", style: Object.assign({ '--selection-color': selectorsColor }, containerStyles), children: jsx(Suspense, { fallback: jsx(Loading, {}), children: jsx(Plot$4, { data: plotlyData, layout: layout, config: config, onSelected: onSelected, onClick: onClick, useResizeHandler: true, style: {
1406
1406
  width: "100%",
1407
1407
  height: "100%",
1408
1408
  display: "block"
1409
1409
  } }) }) }));
1410
1410
  };
1411
1411
 
1412
- const Plot$4 = lazy(() => import('react-plotly.js'));
1412
+ const Plot$3 = lazy(() => import('react-plotly.js'));
1413
1413
  const StatsDonut = (props) => {
1414
1414
  const { withCenterLabel = false, centerLabel, centerValue, showLegend = true, legendPosition = "right", containerStyle = {}, } = props;
1415
1415
  // Configure legend position based on prop
@@ -1457,7 +1457,7 @@ const StatsDonut = (props) => {
1457
1457
  },
1458
1458
  ]
1459
1459
  : [];
1460
- return (jsx("div", { style: Object.assign({ width: "100%", height: "100%", minHeight: "300px", display: "flex", justifyContent: "center", alignItems: "center" }, containerStyle), children: jsx(Suspense, { fallback: jsx(Loading, {}), children: jsx(Plot$4, { data: [
1460
+ return (jsx("div", { style: Object.assign({ width: "100%", height: "100%", minHeight: "300px", display: "flex", justifyContent: "center", alignItems: "center" }, containerStyle), children: jsx(Suspense, { fallback: jsx(Loading, {}), children: jsx(Plot$3, { data: [
1461
1461
  {
1462
1462
  type: "pie",
1463
1463
  values: props.values,
@@ -1490,7 +1490,7 @@ const StatsDonut = (props) => {
1490
1490
  }, useResizeHandler: true }) }) }));
1491
1491
  };
1492
1492
 
1493
- const Plot$3 = lazy(() => import('react-plotly.js'));
1493
+ const Plot$2 = lazy(() => import('react-plotly.js'));
1494
1494
  const BoxPlot = (props) => {
1495
1495
  const { data, width = 600, height = 400, title = "Box Plot", xAxisTitle, yAxisTitle, containerStyleOverrides, plotId = "boxplot", extraLayoutConfig = {}, } = props;
1496
1496
  // Ref for plot container
@@ -1556,7 +1556,7 @@ const BoxPlot = (props) => {
1556
1556
  position: "relative",
1557
1557
  width: "100%",
1558
1558
  height: "100%",
1559
- }, children: [jsx(Plot$3, { data: plotlyData, layout: layout, config: config, useResizeHandler: true,
1559
+ }, children: [jsx(Plot$2, { data: plotlyData, layout: layout, config: config, useResizeHandler: true,
1560
1560
  // onHover={handleHover}
1561
1561
  // onUnhover={handleUnhover}
1562
1562
  style: {
@@ -1842,7 +1842,7 @@ const PairedComparisonsBoxPlot = (props) => {
1842
1842
  return (jsxs("div", { style: Object.assign({}, containerStyles), children: [showLegend && legendNode, jsx(BoxPlot, { data: boxPlotData, width: width, height: height, title: title, xAxisTitle: xAxisTitle, yAxisTitle: yAxisTitle, extraLayoutConfig: extraLayoutConfig, containerStyleOverrides: containerStyleOverrides, plotId: `${plotId}-boxplot` })] }));
1843
1843
  };
1844
1844
 
1845
- const Plot$2 = lazy(() => import('react-plotly.js'));
1845
+ const Plot$1 = lazy(() => import('react-plotly.js'));
1846
1846
  const SummaryComparisonPlot = (props) => {
1847
1847
  const { groups, height = 250, title = "", xAxisTitle, yAxisTitle, containerStyleOverrides, plotId = "summary-comparison-plot", tooltipPosition = "right", startXAxisAtZero = true, } = props;
1848
1848
  // Ref for plot container
@@ -1886,11 +1886,11 @@ const SummaryComparisonPlot = (props) => {
1886
1886
  content += `
1887
1887
  <table style="width: 100%; margin-top: 4px;">
1888
1888
  <tr>
1889
- <td style="text-align: left; padding: 2px 18px 2px 0;">Population P25:</td>
1889
+ <td style="text-align: left; padding: 2px 18px 2px 0;">Population avg-\u03C3:</td>
1890
1890
  <td style="text-align: right; padding: 2px 0;">${summarizedMinText}</td>
1891
1891
  </tr>
1892
1892
  <tr>
1893
- <td style="text-align: left; padding: 2px 18px 2px 0;">Population P75:</td>
1893
+ <td style="text-align: left; padding: 2px 18px 2px 0;">Population avg+\u03C3:</td>
1894
1894
  <td style="text-align: right; padding: 2px 0;">${summarizedMaxText}</td>
1895
1895
  </tr>
1896
1896
  <tr>
@@ -2056,7 +2056,7 @@ const SummaryComparisonPlot = (props) => {
2056
2056
  position: "relative",
2057
2057
  width: "100%",
2058
2058
  height: "100%",
2059
- }, children: [jsx(Plot$2, { data: plotlyData, layout: layout, config: config, useResizeHandler: true, onHover: handleHover, onUnhover: handleUnhover, style: {
2059
+ }, children: [jsx(Plot$1, { data: plotlyData, layout: layout, config: config, useResizeHandler: true, onHover: handleHover, onUnhover: handleUnhover, style: {
2060
2060
  width: "100%",
2061
2061
  height: `${height}px`,
2062
2062
  display: "block",
@@ -2095,42 +2095,150 @@ const SummaryComparisonPlotLegend = ({ comparedDataLabel, summarizedDataLabel, c
2095
2095
  } }), jsx("span", { children: comparedDataLabel })] }), jsxs("div", { style: { display: "flex", gap: "5px", alignItems: "center" }, children: [jsx(Box, { width: 30, height: 3, sx: { backgroundColor: color } }), jsx("span", { children: summarizedDataLabel })] })] }));
2096
2096
  };
2097
2097
 
2098
- const Plot$1 = lazy(() => import('react-plotly.js'));
2099
- const LinePlot = (props) => {
2100
- var _a, _b;
2101
- const { data, width = 600, height = 400, title, xAxisTitle, yAxisTitle, containerStyleOverrides, plotId = "boxplot", extraLayoutConfig = {}, additionalYAxis, additionalContextTrace, } = props;
2098
+ const Plot = lazy(() => import('react-plotly.js'));
2099
+ // This component plots a line chart in the foreground with a histogram in the backgroun. The histogram
2100
+ // is used only for context, while the line is intended to have the focus. To that end, the line plot has hover interactions
2101
+ // while the histogram does not.
2102
+ // Additionally, because of plotly restrictions in the web (overlaying y issues) we cannot draw both plots
2103
+ // as normal. Instead, we first render a histogram, extract the calculated bin positions and heights from the rendered plot, and
2104
+ // then render a second plot with just the line and use the extracted histogram bin information to draw the histogram as shapes in
2105
+ // the background of the line plot. This allows us to have a shared x-axis and aligned y-axes for both plots, while only having hover
2106
+ // interactions on the line plot.
2107
+ const LineWithHistogram = (props) => {
2108
+ const { lineData, histogramData, width = 600, height = 400, title, xAxisTitle, yAxisTitle, containerStyleOverrides, plotId = "lineplot", extraLayoutConfig = {}, y2AxisTitle, revision = 0, } = props;
2102
2109
  // Ref for plot container
2103
2110
  const containerRef = useRef(null);
2104
- const plotlyData = data.map((trace) => {
2105
- return {
2106
- type: "scatter",
2107
- mode: "lines+markers",
2108
- x: trace.x,
2109
- y: trace.y,
2110
- name: trace.label,
2111
- line: {
2112
- color: trace.color || "#1f77b4", // Default to Plotly's default blue if no color provided
2113
- },
2111
+ // State to store extracted histogram bin information
2112
+ const [histogramBins, setHistogramBins] = useState([]);
2113
+ // State to trigger re-render of hidden histogram plot when data changes
2114
+ const [hiddenPlotKey, setHiddenPlotKey] = useState(0);
2115
+ // When histogram data changes, reset bins and remount the hidden plot so onInitialized re-fires
2116
+ useEffect(() => {
2117
+ setHistogramBins([]);
2118
+ setHiddenPlotKey((k) => k + 1);
2119
+ }, [histogramData.x]);
2120
+ // Callback to extract histogram bin data from Plotly after it's rendered
2121
+ const handlePlotInitialized = (figure, graphDiv) => {
2122
+ try {
2123
+ // Only extract once - prevent infinite loop
2124
+ if (histogramBins.length > 0) {
2125
+ return;
2126
+ }
2127
+ // Access the calculated histogram data from Plotly's internal data
2128
+ const histogramTrace = graphDiv.data[0]; // First trace is the histogram
2129
+ if (histogramTrace && histogramTrace.type === "histogram") {
2130
+ // Plotly computes x (bin edges) and y (bin heights) after rendering
2131
+ // We need to access the computed bins from the graph div
2132
+ const fullData = graphDiv.calcdata;
2133
+ if (fullData && fullData[0]) {
2134
+ const histCalcData = fullData[0]; // Contains bin information
2135
+ const bins = [];
2136
+ // Extract bin information from Plotly's calculated data
2137
+ for (let i = 0; i < histCalcData.length; i++) {
2138
+ const point = histCalcData[i];
2139
+ if (point.p0 !== undefined &&
2140
+ point.p1 !== undefined &&
2141
+ point.s !== undefined) {
2142
+ bins.push({
2143
+ x0: point.p0,
2144
+ x1: point.p1,
2145
+ y: point.s, // bin height
2146
+ });
2147
+ }
2148
+ }
2149
+ if (bins.length > 0) {
2150
+ setHistogramBins(bins);
2151
+ }
2152
+ }
2153
+ }
2154
+ }
2155
+ catch (error) {
2156
+ console.error("Error extracting histogram bins:", error);
2157
+ }
2158
+ };
2159
+ // Data for the hidden histogram plot used to extract bin information.
2160
+ // This plot is not visible and is only used for bin calculation.
2161
+ const histogramPlotlyData = [
2162
+ {
2163
+ type: "histogram",
2164
+ x: histogramData.x,
2165
+ name: histogramData.name || "histogram",
2114
2166
  marker: {
2115
- color: trace.color || "#1f77b4",
2167
+ color: histogramData.color || "rgb(211, 211, 212)",
2168
+ line: {
2169
+ color: "white",
2170
+ width: 0.5,
2171
+ },
2172
+ },
2173
+ },
2174
+ ];
2175
+ const plotlyData = [
2176
+ // Only the line trace - no histogram trace in main plot
2177
+ // Line trace on primary y-axis for hover interactions
2178
+ Object.assign({ type: "scatter", mode: "lines+markers", x: lineData.x, y: lineData.y, name: lineData.name, line: {
2179
+ color: lineData.color || "#1f77b4",
2180
+ shape: "hv", // Step-wise line.
2181
+ }, marker: {
2182
+ color: lineData.color || "#1f77b4",
2116
2183
  size: 6,
2184
+ }, hoverinfo: lineData.hovertemplate ? "text" : "x+y+name" }, (lineData.hovertemplate && { hovertemplate: lineData.hovertemplate })),
2185
+ // Dummy invisible point on yaxis2 to force the axis to render
2186
+ // Position it at the top of the histogram range to ensure the
2187
+ // y2 axis scales appropriately even if the line data doesn't reach that high.
2188
+ // This is a hack to work around Plotly's behavior of not rendering an axis if no data
2189
+ // is plotted on it.
2190
+ ...(histogramBins.length > 0
2191
+ ? [
2192
+ {
2193
+ type: "scatter",
2194
+ mode: "markers",
2195
+ yaxis: "y2",
2196
+ x: [lineData.x[0]], // First x point
2197
+ y: [Math.max(...histogramBins.map((bin) => bin.y))], // Top of histogram range
2198
+ marker: {
2199
+ size: 0.1,
2200
+ opacity: 0,
2201
+ color: "rgba(0,0,0,0)",
2202
+ },
2203
+ hoverinfo: "skip",
2204
+ showlegend: false,
2205
+ },
2206
+ ]
2207
+ : []),
2208
+ ];
2209
+ // Convert histogram bins to Plotly shapes (rectangles drawn in the background)
2210
+ // Use yaxis2 coordinates so bins align with the right y-axis
2211
+ const histogramShapes = histogramBins.length > 0
2212
+ ? histogramBins.map((bin) => ({
2213
+ type: "rect",
2214
+ xref: "x",
2215
+ yref: "y2", // Use secondary y-axis to match the histogram scale
2216
+ x0: bin.x0,
2217
+ x1: bin.x1,
2218
+ y0: 0, // Start at y2 = 0
2219
+ y1: bin.y, // Height matches bin count on y2 axis
2220
+ fillcolor: histogramData.color || "rgb(211, 211, 212)",
2221
+ line: {
2222
+ color: histogramData.color || "rgb(211, 211, 212)", // Match fill color
2223
+ width: 0, // No border
2117
2224
  },
2118
- zorder: 1, // Ensure lines are above any additional context traces (like scatter points)
2119
- };
2120
- });
2121
- const layout = Object.assign(Object.assign(Object.assign({}, extraLayoutConfig), { title: {
2225
+ layer: "below", // Ensure shapes are drawn below traces
2226
+ }))
2227
+ : [];
2228
+ const layout = Object.assign(Object.assign({}, extraLayoutConfig), { title: {
2122
2229
  text: title,
2123
2230
  }, showlegend: false, autosize: true, width: undefined, height: undefined, hovermode: "closest", margin: {
2124
2231
  l: 50,
2125
- r: additionalContextTrace ? 80 : 35, // Balance between ensuring the mean annotation doesn't get cut off and having too much margin.
2232
+ r: 80, // Balance between ensuring the mean annotation doesn't get cut off and having too much margin.
2126
2233
  t: title ? 50 : 20, // Adjust top margin based on whether a title is provided
2127
2234
  b: 50,
2128
2235
  pad: 4,
2129
- }, xaxis: {
2236
+ },
2237
+ // Add histogram shapes as background rectangles
2238
+ shapes: histogramShapes, xaxis: {
2130
2239
  title: {
2131
2240
  text: xAxisTitle,
2132
2241
  },
2133
- // range: displayXAxis, // Fixed range prevents axis shifting during interaction or data updates
2134
2242
  showgrid: true,
2135
2243
  zeroline: false,
2136
2244
  showline: true,
@@ -2148,7 +2256,7 @@ const LinePlot = (props) => {
2148
2256
  text: yAxisTitle || "", // Set default to empty string to prevent Plotly from adding its own default title
2149
2257
  standoff: 12, // Add space between title and axis
2150
2258
  font: {
2151
- color: ((_a = data[0]) === null || _a === void 0 ? void 0 : _a.color) || "#1f77b4", // Match y-axis title color to line color
2259
+ color: lineData.color || "#1f77b4", // Match y-axis title color to line color
2152
2260
  },
2153
2261
  },
2154
2262
  automargin: true, // Required for standoff to work properly
@@ -2164,14 +2272,33 @@ const LinePlot = (props) => {
2164
2272
  linewidth: 1,
2165
2273
  fixedrange: true, // Disable zooming
2166
2274
  tickfont: {
2167
- color: ((_b = data[0]) === null || _b === void 0 ? void 0 : _b.color) || "#1f77b4", // Match y-axis tick color to line color
2275
+ color: lineData.color || "#1f77b4", // Match y-axis tick color to line color
2168
2276
  },
2169
2277
  tickcolor: "white", // Hide default ticks since we're using them for group labels in the paired comparisons plot
2170
2278
  ticklen: 10, // Give ticks a length to push labels away from y axis.
2171
- // ticksuffix: " ", // Add space between y axis and ticks
2172
- } }), (additionalYAxis
2173
- ? { yaxis2: Object.assign(Object.assign({}, additionalYAxis), { side: "right", overlaying: "y" }) }
2174
- : {}));
2279
+ },
2280
+ // Second y-axis for histogram bin counts (right side)
2281
+ yaxis2: {
2282
+ side: "right",
2283
+ overlaying: "y",
2284
+ showgrid: false, // Hide grid for histogram axis
2285
+ zeroline: false, // Hide zero line
2286
+ showline: true,
2287
+ linecolor: "#bababa",
2288
+ linewidth: 1,
2289
+ tickfont: {
2290
+ color: histogramData.color || "rgb(150, 150, 150)",
2291
+ },
2292
+ title: {
2293
+ text: y2AxisTitle || "Count",
2294
+ font: {
2295
+ color: histogramData.color || "rgb(150, 150, 150)",
2296
+ },
2297
+ standoff: 22,
2298
+ },
2299
+ tickprefix: " ", // Add space between the ticks and axis
2300
+ fixedrange: true,
2301
+ } });
2175
2302
  const config = {
2176
2303
  responsive: true, // Make the plot responsive
2177
2304
  displayModeBar: false, // Hide the mode bar
@@ -2180,41 +2307,17 @@ const LinePlot = (props) => {
2180
2307
  staticPlot: false, // Enable interactivity
2181
2308
  };
2182
2309
  const containerStyles = Object.assign({ width: "100%", height: "100%", position: "relative" }, containerStyleOverrides);
2183
- return (jsx("div", { ref: containerRef, style: Object.assign({}, containerStyles), children: jsx(Suspense, { fallback: jsx(Loading, {}), children: jsx("div", { style: {
2184
- position: "relative",
2185
- width: "100%",
2186
- height: "100%",
2187
- }, children: jsx(Plot$1, { data: [
2188
- ...(additionalContextTrace ? [additionalContextTrace] : []),
2189
- ...plotlyData,
2190
- ], layout: layout, config: config, useResizeHandler: true, style: {
2310
+ return (jsx("div", { ref: containerRef, style: Object.assign({}, containerStyles), children: jsxs(Suspense, { fallback: jsx(Loading, {}), children: [jsx("div", { style: {
2311
+ position: "relative",
2191
2312
  width: "100%",
2192
2313
  height: "100%",
2193
- display: "block",
2194
- transition: "opacity 0.15s ease-in-out",
2195
- }, onHover: () => {
2196
- console.log("hovering");
2197
- } }, `boxplot-${plotId || "default"}`) }) }) }));
2198
- };
2199
-
2200
- const Plot = lazy(() => import('react-plotly.js'));
2201
- const TestPlot = (props) => {
2202
- var _a, _b;
2203
- const data = [
2204
- {
2205
- x: [1, 2, 3, 4],
2206
- y: [10, 15, 13, 17],
2207
- type: 'bar',
2208
- marker: { color: 'blue' },
2209
- },
2210
- ];
2211
- const layout = {
2212
- title: { text: 'Test Bar Plot' },
2213
- xaxis: { title: { text: (_a = props.xaxisTitle) !== null && _a !== void 0 ? _a : 'X Axis' } },
2214
- yaxis: { title: { text: (_b = props.yaxisTitle) !== null && _b !== void 0 ? _b : 'Y Axis' } },
2215
- };
2216
- return jsx(Plot, { data: data, layout: layout });
2314
+ }, children: jsx(Plot, { data: plotlyData, layout: layout, config: config, useResizeHandler: true, style: {
2315
+ width: "100%",
2316
+ height: "100%",
2317
+ display: "block",
2318
+ transition: "opacity 0.15s ease-in-out",
2319
+ }, revision: revision }, `lineplot-${plotId || "default"}`) }), jsx("div", { style: { display: "none" }, children: jsx(Plot, { data: histogramPlotlyData, layout: { width: 400, height: 300 }, onInitialized: handlePlotInitialized }, `hidden-histogram-${plotId || "default"}-${hiddenPlotKey}`) })] }) }));
2217
2320
  };
2218
2321
 
2219
- export { BoxPlot, HistogramPlot, LinePlot, PairedComparisonsBoxPlot, RadialHistogramPlot, StatsDonut, SummaryComparisonPlot, SummaryComparisonPlotLegend, TestPlot, isDateArray, isNumberArray };
2322
+ export { BoxPlot, HistogramPlot, LineWithHistogram, PairedComparisonsBoxPlot, RadialHistogramPlot, StatsDonut, SummaryComparisonPlot, SummaryComparisonPlotLegend, isDateArray, isNumberArray };
2220
2323
  //# sourceMappingURL=index.esm.js.map