td-plots 1.10.0 → 1.10.2
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/BarPlot.d.ts +11 -0
- package/dist/components/BoxPlot.d.ts +1 -0
- package/dist/components/LegendUtils.d.ts +9 -2
- package/dist/components/PairedComparisonsBoxPlot.d.ts +1 -0
- package/dist/components/SummaryComparisonPlot.d.ts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +298 -69
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +299 -68
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1515,31 +1515,17 @@ const BoxPlot = (props) => {
|
|
|
1515
1515
|
}; // Values map to x because the boxplot is horizontal
|
|
1516
1516
|
return Object.assign({ type: "box", orientation: "h", name: trace.label, fillcolor: trace.fill === "none" ? "rgba(255, 255, 255, 0)" : undefined, line: {
|
|
1517
1517
|
color: trace.color || "#1f77b4", // Default to Plotly's default blue if no color provided
|
|
1518
|
-
}, boxpoints: false,
|
|
1518
|
+
}, boxpoints: false,
|
|
1519
|
+
// hoverinfo: "none", // Disable default hover
|
|
1520
|
+
width: trace.width }, boxDefinition);
|
|
1519
1521
|
});
|
|
1520
1522
|
const layout = Object.assign(Object.assign({}, extraLayoutConfig), { title: {
|
|
1521
1523
|
text: title,
|
|
1522
|
-
}, showlegend: false, autosize: true, width: undefined, height: undefined, margin: Object.assign({ l: 50, r: 35, t: 50, b: 50, pad: 4 }, extraLayoutConfig.margin), xaxis: {
|
|
1523
|
-
title: {
|
|
1524
|
+
}, showlegend: false, autosize: true, width: undefined, height: undefined, margin: Object.assign({ l: 50, r: 35, t: 50, b: 50, pad: 4 }, extraLayoutConfig.margin), xaxis: Object.assign({ title: {
|
|
1524
1525
|
text: xAxisTitle,
|
|
1525
|
-
},
|
|
1526
|
+
},
|
|
1526
1527
|
// range: displayXAxis, // Fixed range prevents axis shifting during interaction or data updates
|
|
1527
|
-
showgrid: true,
|
|
1528
|
-
zeroline: false,
|
|
1529
|
-
showline: true,
|
|
1530
|
-
mirror: "ticks",
|
|
1531
|
-
gridcolor: "#efefef",
|
|
1532
|
-
gridwidth: 0.2,
|
|
1533
|
-
zerolinecolor: "#969696",
|
|
1534
|
-
zerolinewidth: 1,
|
|
1535
|
-
linecolor: "#bababa",
|
|
1536
|
-
linewidth: 1,
|
|
1537
|
-
fixedrange: true, // Disable zooming
|
|
1538
|
-
ticklabelposition: "outside",
|
|
1539
|
-
// tickformat: isDateArray(data) ? dateTickFormat : d3FormatValueString, // Format ticks for dates
|
|
1540
|
-
// automargin: true, // Adjust margin if tick labels rotate
|
|
1541
|
-
// hoverformat: isNumberArray(allData) ? d3FormatValueString : undefined,
|
|
1542
|
-
}, yaxis: Object.assign({ title: {
|
|
1528
|
+
showgrid: true, zeroline: false, showline: true, mirror: "ticks", gridcolor: "#efefef", gridwidth: 0.2, zerolinecolor: "#969696", zerolinewidth: 1, linecolor: "#bababa", linewidth: 1, fixedrange: true, ticklabelposition: "outside" }, extraLayoutConfig.xaxis), yaxis: Object.assign({ title: {
|
|
1543
1529
|
text: yAxisTitle || "", // Set default to empty string to prevent Plotly from adding its own default title
|
|
1544
1530
|
standoff: 12, // Add space between title and axis
|
|
1545
1531
|
}, automargin: true, showgrid: true, zeroline: false, showline: true, mirror: "ticks", gridcolor: "#efefef", gridwidth: 0.2, zerolinecolor: "#969696", zerolinewidth: 1, linecolor: "#bababa", linewidth: 1, fixedrange: true, tickcolor: "white", ticklen: 10, ticksuffix: " " }, extraLayoutConfig.yaxis) });
|
|
@@ -1594,6 +1580,7 @@ function isBoxPlotDataSummary(value) {
|
|
|
1594
1580
|
(value.mean === undefined || typeof value.mean === "number"));
|
|
1595
1581
|
}
|
|
1596
1582
|
|
|
1583
|
+
const BOX_SIZE = 15;
|
|
1597
1584
|
const SVGBoxWithLine = (props) => {
|
|
1598
1585
|
const boxWidth = 35;
|
|
1599
1586
|
const boxHeight = 15;
|
|
@@ -1602,12 +1589,45 @@ const SVGBoxWithLine = (props) => {
|
|
|
1602
1589
|
return (jsxs("svg", { width: lineWidth, height: boxHeight, viewBox: `0 0 ${lineWidth + 3} ${boxHeight + 3}`, children: [jsx("line", { x1: 0, y1: lineY, x2: (lineWidth - boxWidth) / 2, y2: lineY, stroke: props.color, strokeWidth: "2" }), jsx("line", { x1: (lineWidth + boxWidth) / 2, y1: lineY, x2: lineWidth, y2: lineY, stroke: props.color, strokeWidth: "2" }), jsx("line", { x1: 0, y1: lineY - 5, x2: 0, y2: lineY + 5, stroke: props.color, strokeWidth: "2" }), jsx("line", { x1: lineWidth, y1: lineY - 5, x2: lineWidth, y2: lineY + 5, stroke: props.color, strokeWidth: "2" }), jsx("rect", { x: (lineWidth - boxWidth) / 2, y: "0", width: boxWidth, height: boxHeight, fill: props.boxStyle !== "outlined" ? props.color : "none", opacity: props.boxStyle === "shaded" ? 0.3 : 1 }), jsx("rect", { x: (lineWidth - boxWidth) / 2, y: "0", width: boxWidth, height: boxHeight, stroke: props.color, strokeWidth: "2", fill: "none" }), jsx("line", { x1: (lineWidth - boxWidth) / 2 + boxWidth * 0.5, y1: 0, x2: (lineWidth - boxWidth) / 2 + boxWidth * 0.5, y2: boxHeight, stroke: props.color, strokeWidth: "2" })] }));
|
|
1603
1590
|
};
|
|
1604
1591
|
const LegendBoxPlotItem = (props) => {
|
|
1592
|
+
const labelKey = props.label == null
|
|
1593
|
+
? ""
|
|
1594
|
+
: typeof props.label === "string"
|
|
1595
|
+
? props.label
|
|
1596
|
+
: props.label.toString();
|
|
1597
|
+
return (jsxs(Box, { sx: {
|
|
1598
|
+
display: "flex",
|
|
1599
|
+
alignItems: "center",
|
|
1600
|
+
mr: 4,
|
|
1601
|
+
fontFamily: "Open Sans, verdana, arial, sans-serif",
|
|
1602
|
+
}, children: [jsx(SVGBoxWithLine, { color: props.color, boxStyle: props.boxStyle }), props.label] }, labelKey));
|
|
1603
|
+
};
|
|
1604
|
+
const LegendColorItem = (props) => {
|
|
1605
|
+
const labelKey = props.label == null
|
|
1606
|
+
? ""
|
|
1607
|
+
: typeof props.label === "string"
|
|
1608
|
+
? props.label
|
|
1609
|
+
: props.label.toString();
|
|
1610
|
+
return (jsxs(Box, { sx: {
|
|
1611
|
+
display: "flex",
|
|
1612
|
+
alignItems: "center",
|
|
1613
|
+
mr: 4,
|
|
1614
|
+
fontFamily: "Open Sans, verdana, arial, sans-serif",
|
|
1615
|
+
}, children: [jsx(Box, { sx: Object.assign({ width: props.width || BOX_SIZE, height: props.height || BOX_SIZE, backgroundColor: props.color, marginRight: 1 }, props.styleOverrides) }), props.label] }, labelKey));
|
|
1616
|
+
};
|
|
1617
|
+
const LegendLineItem = (props) => {
|
|
1618
|
+
const lineWidth = props.width || 40;
|
|
1619
|
+
const lineHeight = props.height || 4;
|
|
1620
|
+
const labelKey = props.label == null
|
|
1621
|
+
? ""
|
|
1622
|
+
: typeof props.label === "string"
|
|
1623
|
+
? props.label
|
|
1624
|
+
: props.label.toString();
|
|
1605
1625
|
return (jsxs(Box, { sx: {
|
|
1606
1626
|
display: "flex",
|
|
1607
1627
|
alignItems: "center",
|
|
1608
1628
|
mr: 4,
|
|
1609
1629
|
fontFamily: "Open Sans, verdana, arial, sans-serif",
|
|
1610
|
-
}, children: [jsx(
|
|
1630
|
+
}, children: [jsx("svg", { width: lineWidth, height: lineHeight, style: { marginRight: 8 }, children: jsx("line", { x1: 0, y1: lineHeight / 2, x2: lineWidth, y2: lineHeight / 2, stroke: props.color, strokeWidth: lineHeight }) }), props.label] }, labelKey));
|
|
1611
1631
|
};
|
|
1612
1632
|
|
|
1613
1633
|
// This component takes grouped data and transforms it for displaying with the BoxPlot component.
|
|
@@ -1618,10 +1638,12 @@ const PairedComparisonsBoxPlot = (props) => {
|
|
|
1618
1638
|
// Transform the grouped data into an array for BoxPlot
|
|
1619
1639
|
const boxPlotData = groups.flatMap((group, groupIndex) => {
|
|
1620
1640
|
const groupYPosition = groupIndex; // Position the group on the y-axis based on its index
|
|
1621
|
-
group.color || "orange";
|
|
1622
|
-
return group.boxes.map((box, boxIndex) => (Object.assign(Object.assign({}, box), {
|
|
1623
|
-
|
|
1624
|
-
|
|
1641
|
+
const groupColor = group.color || "orange";
|
|
1642
|
+
return group.boxes.map((box, boxIndex) => (Object.assign(Object.assign({}, box), { color: box.color || groupColor, width: 0.28, fill: boxIndex % 2 === 0 ? "none" : "auto", y: boxIndex % 2 === 0 &&
|
|
1643
|
+
Array.isArray(group.boxes[1].values) &&
|
|
1644
|
+
group.boxes[1].values.length === 0
|
|
1645
|
+
? groupYPosition
|
|
1646
|
+
: groupYPosition + 0.25 + (boxIndex - 1) * 0.5 })));
|
|
1625
1647
|
});
|
|
1626
1648
|
// We have to construct nice ticks. We can position them with the group indices.
|
|
1627
1649
|
const tickvals = groups.map((_, index) => index);
|
|
@@ -1636,15 +1658,15 @@ const PairedComparisonsBoxPlot = (props) => {
|
|
|
1636
1658
|
y0: groupIndex - 0.5,
|
|
1637
1659
|
y1: groupIndex + 0.5,
|
|
1638
1660
|
yref: "y",
|
|
1639
|
-
fillcolor: groupIndex % 2 === 0 ? "#ffffff" : "#
|
|
1640
|
-
opacity: 0.
|
|
1661
|
+
fillcolor: groupIndex % 2 === 0 ? "#ffffff" : "#e7e5e5",
|
|
1662
|
+
opacity: 0.2,
|
|
1641
1663
|
layer: "below",
|
|
1642
1664
|
line: {
|
|
1643
1665
|
width: 0,
|
|
1644
1666
|
},
|
|
1645
1667
|
};
|
|
1646
1668
|
});
|
|
1647
|
-
|
|
1669
|
+
groups.map((group, groupIndex) => ({
|
|
1648
1670
|
type: "line",
|
|
1649
1671
|
yref: "y",
|
|
1650
1672
|
xref: "paper",
|
|
@@ -1659,8 +1681,23 @@ const PairedComparisonsBoxPlot = (props) => {
|
|
|
1659
1681
|
}));
|
|
1660
1682
|
const differenceAnnotations = [];
|
|
1661
1683
|
const differenceBetweenMediansLines = [];
|
|
1684
|
+
// Find reasonable max and min for the x axis.
|
|
1685
|
+
let globalMin = Infinity;
|
|
1686
|
+
let globalMax = -Infinity;
|
|
1662
1687
|
groups.forEach((group, groupIndex) => {
|
|
1663
|
-
//
|
|
1688
|
+
// Update global min and max
|
|
1689
|
+
group.boxes.forEach((box) => {
|
|
1690
|
+
if (isBoxPlotDataSummary(box.values)) {
|
|
1691
|
+
globalMin = Math.min(globalMin, box.values.lowerWhisker);
|
|
1692
|
+
globalMax = Math.max(globalMax, box.values.upperWhisker);
|
|
1693
|
+
}
|
|
1694
|
+
else if (Array.isArray(box.values)) {
|
|
1695
|
+
const boxMin = Math.min(...box.values);
|
|
1696
|
+
const boxMax = Math.max(...box.values);
|
|
1697
|
+
globalMin = Math.min(globalMin, boxMin);
|
|
1698
|
+
globalMax = Math.max(globalMax, boxMax);
|
|
1699
|
+
}
|
|
1700
|
+
});
|
|
1664
1701
|
if ((!isBoxPlotDataSummary(group.boxes[0].values) &&
|
|
1665
1702
|
group.boxes[0].values.length == 0) ||
|
|
1666
1703
|
(!isBoxPlotDataSummary(group.boxes[1].values) &&
|
|
@@ -1702,14 +1739,15 @@ const PairedComparisonsBoxPlot = (props) => {
|
|
|
1702
1739
|
xref: "x",
|
|
1703
1740
|
x: medianB > medianA ? medianB : medianA, // Position the annotation at the larger median
|
|
1704
1741
|
y: groupIndex, // Align with the center of the group
|
|
1705
|
-
text: ` ${differenceBetweenMedians.toFixed(1)}`,
|
|
1742
|
+
text: ` ${differenceBetweenMedians.toFixed(1)}${props.unit ? ` ${props.unit}` : ""} `, // Show the difference between the medians with optional unit
|
|
1706
1743
|
showarrow: false,
|
|
1707
1744
|
xanchor: "left",
|
|
1708
1745
|
align: "left",
|
|
1709
1746
|
font: {
|
|
1710
|
-
size:
|
|
1747
|
+
size: 16,
|
|
1711
1748
|
color: annotationColor,
|
|
1712
1749
|
style: "italic",
|
|
1750
|
+
weight: "bold",
|
|
1713
1751
|
},
|
|
1714
1752
|
});
|
|
1715
1753
|
differenceBetweenMediansLines.push({
|
|
@@ -1761,6 +1799,20 @@ const PairedComparisonsBoxPlot = (props) => {
|
|
|
1761
1799
|
range: [-0.5, groups.length - 0.5], // Add some padding to the y-axis range to accommodate the boxes
|
|
1762
1800
|
tickcolor: "#ffffff",
|
|
1763
1801
|
showgrid: false,
|
|
1802
|
+
ticklabelposition: "inside",
|
|
1803
|
+
//@ts-ignore
|
|
1804
|
+
ticklabelstandoff: 10,
|
|
1805
|
+
ticksuffix: " ", // Add space between ticks and data
|
|
1806
|
+
title: {
|
|
1807
|
+
text: yAxisTitle || "", // Set default to empty string to prevent Plotly from adding its own default title
|
|
1808
|
+
standoff: 45,
|
|
1809
|
+
},
|
|
1810
|
+
},
|
|
1811
|
+
xaxis: {
|
|
1812
|
+
insiderange: [
|
|
1813
|
+
globalMin - (globalMax - globalMin) * 0.1,
|
|
1814
|
+
globalMax + (globalMax - globalMin) * 0.1,
|
|
1815
|
+
], // Set the x-axis range based on the global min and max values with some padding
|
|
1764
1816
|
},
|
|
1765
1817
|
margin: {
|
|
1766
1818
|
t: 5,
|
|
@@ -1769,7 +1821,7 @@ const PairedComparisonsBoxPlot = (props) => {
|
|
|
1769
1821
|
shapes: [
|
|
1770
1822
|
...separatorShapes,
|
|
1771
1823
|
...differenceBetweenMediansLines,
|
|
1772
|
-
...groupAnnotations,
|
|
1824
|
+
// ...groupAnnotations,
|
|
1773
1825
|
],
|
|
1774
1826
|
annotations: differenceAnnotations,
|
|
1775
1827
|
};
|
|
@@ -1780,7 +1832,7 @@ const PairedComparisonsBoxPlot = (props) => {
|
|
|
1780
1832
|
|
|
1781
1833
|
const Plot$2 = lazy(() => Promise.resolve().then(function () { return reactPlotlyWrapper$1; }));
|
|
1782
1834
|
const SummaryComparisonPlot = (props) => {
|
|
1783
|
-
const { groups, height = 250, title = "", xAxisTitle, yAxisTitle, containerStyleOverrides, plotId = "summary-comparison-plot", tooltipPosition = "right", startXAxisAtZero = true, } = props;
|
|
1835
|
+
const { groups, height = 250, title = "", xAxisTitle, yAxisTitle, containerStyleOverrides, plotId = "summary-comparison-plot", tooltipPosition = "right", startXAxisAtZero = true, unit = "", } = props;
|
|
1784
1836
|
// Ref for plot container
|
|
1785
1837
|
const containerRef = useRef(null);
|
|
1786
1838
|
// State for custom tooltip
|
|
@@ -1862,6 +1914,8 @@ const SummaryComparisonPlot = (props) => {
|
|
|
1862
1914
|
const handleUnhover = () => {
|
|
1863
1915
|
setTooltip((prev) => (Object.assign(Object.assign({}, prev), { visible: false })));
|
|
1864
1916
|
};
|
|
1917
|
+
const comparedLines = [];
|
|
1918
|
+
const comparedAnnotations = [];
|
|
1865
1919
|
// Transform the data into a format suitable for a plotly scatterplot
|
|
1866
1920
|
const plotlyData = groups.flatMap((group, groupIndex) => {
|
|
1867
1921
|
const traces = [];
|
|
@@ -1872,10 +1926,10 @@ const SummaryComparisonPlot = (props) => {
|
|
|
1872
1926
|
mode: "lines",
|
|
1873
1927
|
name: group.groupLabel,
|
|
1874
1928
|
x: [group.data.summarizedMin, group.data.summarizedMax],
|
|
1875
|
-
y: [
|
|
1929
|
+
y: [groupIndex * 0.1, groupIndex * 0.1],
|
|
1876
1930
|
line: {
|
|
1877
1931
|
color: colorToRGBA(group.color || "orange", 1),
|
|
1878
|
-
width:
|
|
1932
|
+
width: 6,
|
|
1879
1933
|
},
|
|
1880
1934
|
showlegend: false,
|
|
1881
1935
|
hoverinfo: "none",
|
|
@@ -1887,9 +1941,9 @@ const SummaryComparisonPlot = (props) => {
|
|
|
1887
1941
|
mode: "markers",
|
|
1888
1942
|
name: group.groupLabel,
|
|
1889
1943
|
x: [group.data.comparedMedian],
|
|
1890
|
-
y: [
|
|
1944
|
+
y: [groupIndex * 0.1],
|
|
1891
1945
|
marker: {
|
|
1892
|
-
color: group.color || "orange",
|
|
1946
|
+
color: colorToRGBA(group.color || "orange", 1),
|
|
1893
1947
|
size: 10,
|
|
1894
1948
|
symbol: "circle",
|
|
1895
1949
|
line: {
|
|
@@ -1900,9 +1954,45 @@ const SummaryComparisonPlot = (props) => {
|
|
|
1900
1954
|
showlegend: false,
|
|
1901
1955
|
hoverinfo: "none",
|
|
1902
1956
|
});
|
|
1957
|
+
comparedLines.push({
|
|
1958
|
+
type: "line",
|
|
1959
|
+
name: group.groupLabel,
|
|
1960
|
+
x0: group.data.comparedMedian,
|
|
1961
|
+
x1: group.data.comparedMedian,
|
|
1962
|
+
y0: 0,
|
|
1963
|
+
y1: 1.1,
|
|
1964
|
+
yref: "paper",
|
|
1965
|
+
line: {
|
|
1966
|
+
color: group.color || "orange",
|
|
1967
|
+
width: 2,
|
|
1968
|
+
},
|
|
1969
|
+
});
|
|
1970
|
+
comparedAnnotations.push({
|
|
1971
|
+
x: group.data.comparedMedian,
|
|
1972
|
+
y: 1.08,
|
|
1973
|
+
xref: "x",
|
|
1974
|
+
yref: "paper",
|
|
1975
|
+
text: `${group.data.comparedMedian.toFixed(2)} ${unit}`,
|
|
1976
|
+
showarrow: false,
|
|
1977
|
+
xanchor: "center",
|
|
1978
|
+
yanchor: "bottom",
|
|
1979
|
+
});
|
|
1903
1980
|
}
|
|
1904
1981
|
return traces;
|
|
1905
1982
|
});
|
|
1983
|
+
// Add tick label for the compared annotation value
|
|
1984
|
+
if (comparedAnnotations.length > 0) {
|
|
1985
|
+
comparedAnnotations.push({
|
|
1986
|
+
x: -0.03, // Position to the left of the y-axis
|
|
1987
|
+
y: 1.03,
|
|
1988
|
+
xref: "paper",
|
|
1989
|
+
yref: "paper",
|
|
1990
|
+
text: "My AVG",
|
|
1991
|
+
showarrow: false,
|
|
1992
|
+
xanchor: "right",
|
|
1993
|
+
yanchor: "bottom",
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1906
1996
|
const xRangeMin = groups.reduce((min, group) => {
|
|
1907
1997
|
var _a, _b;
|
|
1908
1998
|
return Math.min(min, (_a = group.data.summarizedMin) !== null && _a !== void 0 ? _a : Infinity, (_b = group.data.comparedMedian) !== null && _b !== void 0 ? _b : Infinity);
|
|
@@ -1918,10 +2008,9 @@ const SummaryComparisonPlot = (props) => {
|
|
|
1918
2008
|
margin: {
|
|
1919
2009
|
l: 130,
|
|
1920
2010
|
r: 35, // Balance between ensuring the mean annotation doesn't get cut off and having too much margin.
|
|
1921
|
-
t: title ?
|
|
2011
|
+
t: title ? 70 : 40,
|
|
1922
2012
|
b: 50,
|
|
1923
2013
|
pad: 4,
|
|
1924
|
-
// ...extraLayoutConfig.margin, // Merge in any extra margin config provided via props
|
|
1925
2014
|
},
|
|
1926
2015
|
title: {
|
|
1927
2016
|
text: title,
|
|
@@ -1929,8 +2018,12 @@ const SummaryComparisonPlot = (props) => {
|
|
|
1929
2018
|
size: 16,
|
|
1930
2019
|
},
|
|
1931
2020
|
xref: "paper",
|
|
1932
|
-
x: 0
|
|
1933
|
-
xanchor: "
|
|
2021
|
+
x: 0,
|
|
2022
|
+
xanchor: "left",
|
|
2023
|
+
yanchor: "bottom",
|
|
2024
|
+
pad: {
|
|
2025
|
+
b: 30,
|
|
2026
|
+
},
|
|
1934
2027
|
},
|
|
1935
2028
|
xaxis: {
|
|
1936
2029
|
title: {
|
|
@@ -1975,8 +2068,12 @@ const SummaryComparisonPlot = (props) => {
|
|
|
1975
2068
|
range: [-0.08, 0.08 + (groups.length - 1) * 0.1], // Add padding around the groups
|
|
1976
2069
|
automargin: true,
|
|
1977
2070
|
tickcolor: "white", // Hide default ticks since we're using them for group labels in the paired comparisons plot
|
|
2071
|
+
//@ts-ignore
|
|
2072
|
+
ticklabelstandoff: 5,
|
|
1978
2073
|
},
|
|
1979
2074
|
hovermode: "y",
|
|
2075
|
+
shapes: comparedLines,
|
|
2076
|
+
annotations: comparedAnnotations,
|
|
1980
2077
|
};
|
|
1981
2078
|
const containerStyles = Object.assign({ width: "100%", height: height, position: "relative", display: "flex", flexDirection: "column", gap: 0 }, containerStyleOverrides);
|
|
1982
2079
|
const config = {
|
|
@@ -2259,30 +2356,88 @@ const LineWithHistogram = (props) => {
|
|
|
2259
2356
|
|
|
2260
2357
|
const Plot = lazy(() => Promise.resolve().then(function () { return reactPlotlyWrapper$1; }));
|
|
2261
2358
|
const BarPlot = (props) => {
|
|
2262
|
-
|
|
2359
|
+
var _a, _b;
|
|
2360
|
+
const { data, data2 = null, data2Selected = [], barDataWidth = 2, barWidth = 0.8, barColor = "rgb(205, 26, 154)", // Default bar color (red)
|
|
2263
2361
|
barColor2 = "rgba(100, 200, 255, 0.7)", // Default histogram bar color (blue)
|
|
2362
|
+
data2SelectedColor = "rgba(255, 0, 0, 0.5)", // Default color for the histogram selection box (red)
|
|
2264
2363
|
width = 600, height = 400, title = "", title2 = "", // Default title for histogram subplot
|
|
2265
2364
|
xAxisTitle = "X Axis", yAxisTitle = "Y Axis", xAxis2Title = "", yAxis2Title = "", xAccessor = (d) => d.x, yAccessor = (d) => d.y, containerStyleOverrides = {}, plotId = "bar-plot", xAnnotations = [], barHoverTemplate = "", // Default hover template for bars
|
|
2365
|
+
barGroups = [], // Optional array of bar groups for grouping bars by color
|
|
2366
|
+
barGroupTooltipTitle = "Group", // Default title for the bar group tooltip
|
|
2266
2367
|
} = props;
|
|
2267
2368
|
// Ref for plot container
|
|
2268
2369
|
const containerRef = useRef(null);
|
|
2370
|
+
const plotMetaRef = useRef(null);
|
|
2371
|
+
const [barGroupTooltip, setBarGroupTooltip] = useState(null);
|
|
2269
2372
|
const y2AxisPosition = 0.72; // Position of the secondary y-axis (histogram) as a fraction of the plot height
|
|
2373
|
+
const capturePlotMeta = (_figure, graphDiv) => {
|
|
2374
|
+
var _a, _b, _c;
|
|
2375
|
+
try {
|
|
2376
|
+
const m = (_a = graphDiv._fullLayout) === null || _a === void 0 ? void 0 : _a.margin;
|
|
2377
|
+
const r = (_c = (_b = graphDiv._fullLayout) === null || _b === void 0 ? void 0 : _b.xaxis) === null || _c === void 0 ? void 0 : _c.range;
|
|
2378
|
+
if (m && r) {
|
|
2379
|
+
plotMetaRef.current = {
|
|
2380
|
+
xRange: r,
|
|
2381
|
+
margin: { l: m.l, r: m.r, t: m.t, b: m.b },
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
catch (_d) { }
|
|
2386
|
+
};
|
|
2387
|
+
const handleBarGroupMouseMove = (e) => {
|
|
2388
|
+
var _a;
|
|
2389
|
+
if (!containerRef.current ||
|
|
2390
|
+
barGroups.length === 0 ||
|
|
2391
|
+
!plotMetaRef.current) {
|
|
2392
|
+
setBarGroupTooltip(null);
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
const { xRange, margin } = plotMetaRef.current;
|
|
2396
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
2397
|
+
const mouseX = e.clientX - rect.left;
|
|
2398
|
+
const mouseY = e.clientY - rect.top;
|
|
2399
|
+
const containerHeight = containerRef.current.clientHeight;
|
|
2400
|
+
const containerWidth = containerRef.current.clientWidth;
|
|
2401
|
+
const plotW = containerWidth - margin.l - margin.r;
|
|
2402
|
+
containerHeight - margin.t - margin.b;
|
|
2403
|
+
const plotBottom = containerHeight - margin.b;
|
|
2404
|
+
// barGroupShapes sit at y0=-0.02, y1=-0.04 in paper coords (just below the x-axis line)
|
|
2405
|
+
const stripTop = plotBottom - 10; // Plot bottom extends further than the x axis. Value here adjusted manually.
|
|
2406
|
+
const stripBottom = plotBottom + 20; // approximate. Doesn't have to be perfect.
|
|
2407
|
+
if (mouseY < stripTop || mouseY > stripBottom) {
|
|
2408
|
+
setBarGroupTooltip(null);
|
|
2409
|
+
return;
|
|
2410
|
+
}
|
|
2411
|
+
const dataX = xRange[0] + ((mouseX - margin.l) / plotW) * (xRange[1] - xRange[0]);
|
|
2412
|
+
const hovered = barGroups.find((g) => dataX >= g.min && dataX <= g.max);
|
|
2413
|
+
setBarGroupTooltip(hovered
|
|
2414
|
+
? {
|
|
2415
|
+
x: mouseX,
|
|
2416
|
+
y: plotBottom,
|
|
2417
|
+
name: hovered.name,
|
|
2418
|
+
label: (_a = hovered.label) !== null && _a !== void 0 ? _a : hovered.name,
|
|
2419
|
+
color: hovered.color,
|
|
2420
|
+
min: hovered.min,
|
|
2421
|
+
max: hovered.max,
|
|
2422
|
+
}
|
|
2423
|
+
: null);
|
|
2424
|
+
};
|
|
2270
2425
|
const plotlyData = [
|
|
2271
2426
|
{
|
|
2272
2427
|
x: data.map((point) => xAccessor(point)),
|
|
2273
2428
|
y: data.map((point) => yAccessor(point)),
|
|
2274
|
-
|
|
2429
|
+
customdata: data.map((point) => [xAccessor(point) + barDataWidth]),
|
|
2275
2430
|
yaxis: "y",
|
|
2276
2431
|
type: "bar",
|
|
2277
2432
|
marker: {
|
|
2278
|
-
color:
|
|
2433
|
+
color: "white", // Use the provided bar color
|
|
2279
2434
|
line: {
|
|
2280
|
-
color:
|
|
2281
|
-
width:
|
|
2435
|
+
color: barColor,
|
|
2436
|
+
width: 2,
|
|
2282
2437
|
},
|
|
2283
2438
|
},
|
|
2284
2439
|
width: barWidth, // width centered on the x value.
|
|
2285
|
-
|
|
2440
|
+
hovertemplate: barHoverTemplate || "%{y}", // Use provided hover template or default to showing y value
|
|
2286
2441
|
},
|
|
2287
2442
|
];
|
|
2288
2443
|
const histogramSubplotData = data2
|
|
@@ -2299,11 +2454,10 @@ const BarPlot = (props) => {
|
|
|
2299
2454
|
},
|
|
2300
2455
|
xaxis: "x2", // Use secondary x-axis for histogram
|
|
2301
2456
|
yaxis: "y2", // Place histogram on secondary y-axis
|
|
2457
|
+
hovertemplate: "[%{x})<br>Count: %{y}<extra></extra>", // Custom hover text
|
|
2302
2458
|
},
|
|
2303
2459
|
]
|
|
2304
2460
|
: [];
|
|
2305
|
-
// Create a multiply-like effect by using a semi-transparent dark overlay
|
|
2306
|
-
const multiplyColor = "rgba(29, 104, 185, 0.1)";
|
|
2307
2461
|
const selectedHistogramShape = data2Selected.length === 2
|
|
2308
2462
|
? [
|
|
2309
2463
|
{
|
|
@@ -2313,10 +2467,10 @@ const BarPlot = (props) => {
|
|
|
2313
2467
|
y0: y2AxisPosition, // Start at the top of the histogram subplot
|
|
2314
2468
|
y1: 1,
|
|
2315
2469
|
yref: "paper",
|
|
2316
|
-
fillcolor: multiplyColor,
|
|
2317
2470
|
line: {
|
|
2318
|
-
width:
|
|
2319
|
-
color:
|
|
2471
|
+
width: 2,
|
|
2472
|
+
color: data2SelectedColor,
|
|
2473
|
+
dash: "dot",
|
|
2320
2474
|
},
|
|
2321
2475
|
layer: "above", // Ensure the selection box is above the bars
|
|
2322
2476
|
},
|
|
@@ -2392,6 +2546,59 @@ const BarPlot = (props) => {
|
|
|
2392
2546
|
},
|
|
2393
2547
|
]
|
|
2394
2548
|
: [];
|
|
2549
|
+
const xMax = data.length > 0 ? Math.max(...data.map((d) => xAccessor(d))) : 0;
|
|
2550
|
+
const barGroupShapes = barGroups.flatMap((group) => [
|
|
2551
|
+
{
|
|
2552
|
+
type: "rect",
|
|
2553
|
+
xref: "x",
|
|
2554
|
+
yref: "paper",
|
|
2555
|
+
x0: group.min,
|
|
2556
|
+
x1: group.max > xMax ? xMax + barWidth : group.max,
|
|
2557
|
+
y0: -0.02,
|
|
2558
|
+
y1: -0.07,
|
|
2559
|
+
fillcolor: group.color,
|
|
2560
|
+
line: {
|
|
2561
|
+
width: 1,
|
|
2562
|
+
color: "white",
|
|
2563
|
+
},
|
|
2564
|
+
},
|
|
2565
|
+
]);
|
|
2566
|
+
const barGroupShapeAnnotation = barGroups.length > 0
|
|
2567
|
+
? {
|
|
2568
|
+
xref: "x",
|
|
2569
|
+
yref: "paper",
|
|
2570
|
+
x: barGroups[0].min + barDataWidth / 2,
|
|
2571
|
+
y: -0.043,
|
|
2572
|
+
text: barGroupTooltipTitle,
|
|
2573
|
+
showarrow: false,
|
|
2574
|
+
yanchor: "middle",
|
|
2575
|
+
xanchor: "left",
|
|
2576
|
+
font: {
|
|
2577
|
+
size: 14,
|
|
2578
|
+
color: "#fff",
|
|
2579
|
+
weight: 500,
|
|
2580
|
+
},
|
|
2581
|
+
}
|
|
2582
|
+
: null;
|
|
2583
|
+
const barGroupHighlightBox = barGroupTooltip
|
|
2584
|
+
? [
|
|
2585
|
+
{
|
|
2586
|
+
type: "rect",
|
|
2587
|
+
xref: "x",
|
|
2588
|
+
yref: "paper",
|
|
2589
|
+
x0: barGroupTooltip.min,
|
|
2590
|
+
x1: barGroupTooltip.max > xMax ? xMax + barWidth : barGroupTooltip.max,
|
|
2591
|
+
y0: 0,
|
|
2592
|
+
y1: data2 ? y2AxisPosition - 0.02 : 1,
|
|
2593
|
+
fillcolor: colorToRGBA(barGroupTooltip.color, 0.2),
|
|
2594
|
+
line: {
|
|
2595
|
+
width: 2,
|
|
2596
|
+
color: barGroupTooltip.color,
|
|
2597
|
+
},
|
|
2598
|
+
layer: "above",
|
|
2599
|
+
},
|
|
2600
|
+
]
|
|
2601
|
+
: [];
|
|
2395
2602
|
const layout = Object.assign(Object.assign(Object.assign(Object.assign({ title: data2
|
|
2396
2603
|
? undefined
|
|
2397
2604
|
: {
|
|
@@ -2418,8 +2625,9 @@ const BarPlot = (props) => {
|
|
|
2418
2625
|
linecolor: "#bababa",
|
|
2419
2626
|
linewidth: 1,
|
|
2420
2627
|
fixedrange: true, // Disable zooming
|
|
2421
|
-
// tickformat: isDateArray(data) ? dateTickFormat : d3FormatValueString, // Format ticks for dates
|
|
2422
2628
|
automargin: true, // Adjust margin if tick labels rotate
|
|
2629
|
+
ticklen: 21,
|
|
2630
|
+
tickcolor: "white",
|
|
2423
2631
|
} }, (data2 && {
|
|
2424
2632
|
xaxis2: {
|
|
2425
2633
|
title: {
|
|
@@ -2484,12 +2692,14 @@ const BarPlot = (props) => {
|
|
|
2484
2692
|
})), { bargap: 0.03, shapes: [
|
|
2485
2693
|
...titleBackgroundShapes,
|
|
2486
2694
|
...selectedHistogramShape,
|
|
2695
|
+
...barGroupShapes,
|
|
2696
|
+
...barGroupHighlightBox,
|
|
2487
2697
|
...xAnnotations.map((annotation) => ({
|
|
2488
2698
|
type: "line",
|
|
2489
2699
|
x0: annotation.x,
|
|
2490
2700
|
x1: annotation.x,
|
|
2491
2701
|
y0: 0,
|
|
2492
|
-
y1: 1.
|
|
2702
|
+
y1: 1.05,
|
|
2493
2703
|
xref: "x",
|
|
2494
2704
|
yref: "paper",
|
|
2495
2705
|
line: {
|
|
@@ -2499,9 +2709,10 @@ const BarPlot = (props) => {
|
|
|
2499
2709
|
})),
|
|
2500
2710
|
], annotations: [
|
|
2501
2711
|
...titleAnnotations,
|
|
2712
|
+
...(barGroupShapeAnnotation ? [barGroupShapeAnnotation] : []),
|
|
2502
2713
|
...xAnnotations.map((annotation) => ({
|
|
2503
2714
|
x: annotation.x,
|
|
2504
|
-
y: 1.
|
|
2715
|
+
y: 1.06,
|
|
2505
2716
|
xref: "x",
|
|
2506
2717
|
yref: "paper",
|
|
2507
2718
|
text: annotation.text || "",
|
|
@@ -2513,7 +2724,6 @@ const BarPlot = (props) => {
|
|
|
2513
2724
|
},
|
|
2514
2725
|
})),
|
|
2515
2726
|
] });
|
|
2516
|
-
console.log("BarPlot layout:", layout);
|
|
2517
2727
|
const config = {
|
|
2518
2728
|
responsive: true, // Make the plot responsive
|
|
2519
2729
|
displayModeBar: false, // Hide the mode bar
|
|
@@ -2522,20 +2732,39 @@ const BarPlot = (props) => {
|
|
|
2522
2732
|
staticPlot: false, // Enable interactivity
|
|
2523
2733
|
};
|
|
2524
2734
|
const containerStyles = Object.assign({ width: "100%", height: "100%", position: "relative" }, containerStyleOverrides);
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
position: "relative",
|
|
2528
|
-
width: "100%",
|
|
2529
|
-
height: "100%",
|
|
2530
|
-
}, children: jsx(Plot, { data: [...plotlyData, ...histogramSubplotData],
|
|
2531
|
-
// Type doesn't contain "mirror" prop but it works.
|
|
2532
|
-
//@ts-ignore
|
|
2533
|
-
layout: layout, config: config, useResizeHandler: true, style: {
|
|
2735
|
+
return (jsxs("div", { ref: containerRef, className: `plot-container histogram ${plotId}`, style: Object.assign(Object.assign({}, containerStyles), { cursor: barGroupTooltip ? "pointer" : "default" }), onMouseMove: handleBarGroupMouseMove, onMouseLeave: () => setBarGroupTooltip(null), children: [jsx(Suspense, { fallback: jsx(Loading, {}), children: jsx("div", { style: {
|
|
2736
|
+
position: "relative",
|
|
2534
2737
|
width: "100%",
|
|
2535
2738
|
height: "100%",
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2739
|
+
}, children: jsx(Plot, { data: [...plotlyData, ...histogramSubplotData],
|
|
2740
|
+
// Type doesn't contain "mirror" prop but it works.
|
|
2741
|
+
//@ts-ignore
|
|
2742
|
+
layout: layout, config: config, useResizeHandler: true, style: {
|
|
2743
|
+
width: "100%",
|
|
2744
|
+
height: "100%",
|
|
2745
|
+
display: "block",
|
|
2746
|
+
transition: "opacity 0.15s ease-in-out",
|
|
2747
|
+
}, onInitialized: capturePlotMeta, onUpdate: capturePlotMeta }, `bar-${plotId || "default"}`) }) }), barGroupTooltip && (jsxs("div", { style: {
|
|
2748
|
+
position: "absolute",
|
|
2749
|
+
left: barGroupTooltip.x + 250 >
|
|
2750
|
+
((_b = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth) !== null && _b !== void 0 ? _b : Infinity)
|
|
2751
|
+
? barGroupTooltip.x - 250
|
|
2752
|
+
: barGroupTooltip.x + 12,
|
|
2753
|
+
top: barGroupTooltip.y + 10,
|
|
2754
|
+
backgroundColor: "rgba(255, 255, 255, 0.9)",
|
|
2755
|
+
borderRadius: "4px",
|
|
2756
|
+
color: "#333",
|
|
2757
|
+
padding: "8px 12px",
|
|
2758
|
+
fontSize: "13px",
|
|
2759
|
+
lineHeight: "1.5",
|
|
2760
|
+
pointerEvents: "none",
|
|
2761
|
+
zIndex: 1000,
|
|
2762
|
+
whiteSpace: "nowrap",
|
|
2763
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
|
|
2764
|
+
borderLeft: `7px solid ${barGroupTooltip.color}`,
|
|
2765
|
+
fontFamily: '"Open Sans", verdana, arial, sans-serif',
|
|
2766
|
+
maxWidth: "250px",
|
|
2767
|
+
}, children: [barGroupTooltipTitle, ": ", jsx("b", { children: barGroupTooltip.label })] }))] }));
|
|
2539
2768
|
};
|
|
2540
2769
|
|
|
2541
2770
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
@@ -100019,5 +100248,5 @@ var reactPlotlyWrapper$1 = /*#__PURE__*/Object.freeze({
|
|
|
100019
100248
|
default: reactPlotlyWrapper
|
|
100020
100249
|
});
|
|
100021
100250
|
|
|
100022
|
-
export { BarPlot, BoxPlot, HistogramPlot, LineWithHistogram, PairedComparisonsBoxPlot, RadialHistogramPlot, StatsDonut, SummaryComparisonPlot, SummaryComparisonPlotLegend, isDateArray, isNumberArray };
|
|
100251
|
+
export { BarPlot, BoxPlot, HistogramPlot, LegendColorItem, LegendLineItem, LineWithHistogram, PairedComparisonsBoxPlot, RadialHistogramPlot, StatsDonut, SummaryComparisonPlot, SummaryComparisonPlotLegend, isDateArray, isNumberArray };
|
|
100023
100252
|
//# sourceMappingURL=index.esm.js.map
|