diff --git a/src/viser/__init__.py b/src/viser/__init__.py
index b375a9ebd..419217c1c 100644
--- a/src/viser/__init__.py
+++ b/src/viser/__init__.py
@@ -8,6 +8,7 @@
from ._gui_handles import GuiHtmlHandle as GuiHtmlHandle
from ._gui_handles import GuiImageHandle as GuiImageHandle
from ._gui_handles import GuiInputHandle as GuiInputHandle
+from ._gui_handles import GuiLineChartHandle as GuiLineChartHandle
from ._gui_handles import GuiMarkdownHandle as GuiMarkdownHandle
from ._gui_handles import GuiMultiSliderHandle as GuiMultiSliderHandle
from ._gui_handles import GuiNumberHandle as GuiNumberHandle
diff --git a/src/viser/_gui_api.py b/src/viser/_gui_api.py
index 1aeb331e8..b2734b800 100644
--- a/src/viser/_gui_api.py
+++ b/src/viser/_gui_api.py
@@ -43,6 +43,7 @@
GuiFolderHandle,
GuiHtmlHandle,
GuiImageHandle,
+ GuiLineChartHandle,
GuiMarkdownHandle,
GuiModalHandle,
GuiMultiSliderHandle,
@@ -784,6 +785,76 @@ def add_plotly(
handle.aspect = aspect
return handle
+ def add_mantine_linechart(
+ self,
+ x_data: Sequence[float],
+ y_data: Sequence[float],
+ title: str | None = None,
+ x_label: str | None = None,
+ y_label: str | None = None,
+ series_name: str = "Series 1",
+ color: str | None = None,
+ height: int = 300,
+ visible: bool = True,
+ order: float | None = None,
+ ) -> GuiLineChartHandle:
+ """Add a Mantine line chart to the GUI.
+
+ Args:
+ x_data: X-axis data points.
+ y_data: Y-axis data points.
+ title: Optional title for the plot.
+ x_label: Optional label for the x-axis.
+ y_label: Optional label for the y-axis.
+ series_name: Name for the data series.
+ color: Optional color for the line (CSS color string).
+ height: Height of the plot in pixels.
+ visible: Whether the plot is visible.
+ order: Optional ordering, smallest values will be displayed first.
+
+ Returns:
+ A handle that can be used to interact with the line chart.
+ """
+ if len(x_data) != len(y_data):
+ raise ValueError("x_data and y_data must have the same length")
+
+ # Create data points and series to send to the client
+ data_points = tuple(_messages.GuiLineChartDataPoint(x=float(x), y=float(y))
+ for x, y in zip(x_data, y_data))
+ series = _messages.GuiLineChartSeries(
+ name=series_name,
+ data=data_points,
+ color=color
+ )
+
+ # this is very similar to Plotly
+ order = _apply_default_order(order)
+ message = _messages.GuiLineChartMessage(
+ uuid=_make_uuid(),
+ container_uuid=self._get_container_uuid(),
+ props=_messages.GuiLineChartProps(
+ order=order,
+ title=title,
+ x_label=x_label,
+ y_label=y_label,
+ _series_data=(series,),
+ height=height,
+ visible=visible,
+ ),
+ )
+ self._websock_interface.queue_message(message)
+
+ return GuiLineChartHandle(
+ _GuiHandleState(
+ uuid=message.uuid,
+ gui_api=self,
+ value=None,
+ props=message.props,
+ parent_container_id=message.container_uuid,
+ ),
+ _series_data=(series,),
+ )
+
def add_button(
self,
label: str,
diff --git a/src/viser/_gui_handles.py b/src/viser/_gui_handles.py
index 1efad94f1..e0ab56139 100644
--- a/src/viser/_gui_handles.py
+++ b/src/viser/_gui_handles.py
@@ -851,3 +851,45 @@ def image(self, image: np.ndarray) -> None:
)
self._data = data
del media_type
+
+
+class GuiLineChartHandle(_GuiHandle[None], _messages.GuiLineChartProps):
+ """Handle for updating and removing Mantine line charts."""
+
+ def __init__(self, _impl: _GuiHandleState, _series_data: tuple[_messages.GuiLineChartSeries, ...]):
+ super().__init__(_impl=_impl)
+ self._series_data_internal = _series_data
+
+ @property
+ def series_data(self) -> tuple[_messages.GuiLineChartSeries, ...]:
+ """Current series data of this line chart. Synchronized automatically when assigned."""
+ return self._series_data_internal
+
+ @series_data.setter
+ def series_data(self, series_data: tuple[_messages.GuiLineChartSeries, ...]) -> None:
+ self._series_data_internal = series_data
+ self._series_data = series_data
+
+ def update_series(self, series_name: str, x_data: list[float], y_data: list[float], color: str | None = None) -> None:
+ """Update a single data series."""
+ if len(x_data) != len(y_data):
+ raise ValueError("x_data and y_data must have the same length")
+
+ # Create new data points
+ new_data_points = tuple(_messages.GuiLineChartDataPoint(x=x, y=y) for x, y in zip(x_data, y_data))
+ new_series = _messages.GuiLineChartSeries(name=series_name, data=new_data_points, color=color)
+
+ # Update or add the series
+ updated_series = []
+ series_found = False
+ for series in self._series_data_internal:
+ if series.name == series_name:
+ updated_series.append(new_series)
+ series_found = True
+ else:
+ updated_series.append(series)
+
+ if not series_found:
+ updated_series.append(new_series)
+
+ self.series_data = tuple(updated_series)
diff --git a/src/viser/_messages.py b/src/viser/_messages.py
index 4164ca4e5..22b9f62d3 100644
--- a/src/viser/_messages.py
+++ b/src/viser/_messages.py
@@ -1022,6 +1022,45 @@ class GuiImageMessage(_CreateGuiComponentMessage):
props: GuiImageProps
+@dataclasses.dataclass
+class GuiLineChartDataPoint:
+ """Single data point for line chart."""
+ x: float
+ y: float
+
+
+@dataclasses.dataclass
+class GuiLineChartSeries:
+ """Data series for line chart."""
+ name: str
+ data: Tuple[GuiLineChartDataPoint, ...]
+ color: Optional[str] = None
+
+
+@dataclasses.dataclass
+class GuiLineChartProps:
+ order: float
+ """Order value for arranging GUI elements. Synchronized automatically when assigned."""
+ title: Optional[str]
+ """Title of the line chart. Synchronized automatically when assigned."""
+ x_label: Optional[str]
+ """X-axis label. Synchronized automatically when assigned."""
+ y_label: Optional[str]
+ """Y-axis label. Synchronized automatically when assigned."""
+ _series_data: Tuple[GuiLineChartSeries, ...]
+ """(Private) Chart data series. Synchronized automatically when assigned."""
+ height: int
+ """Height of the chart in pixels. Synchronized automatically when assigned."""
+ visible: bool
+ """Visibility state of the chart. Synchronized automatically when assigned."""
+
+
+@dataclasses.dataclass
+class GuiLineChartMessage(_CreateGuiComponentMessage):
+ container_uuid: str
+ props: GuiLineChartProps
+
+
@dataclasses.dataclass
class GuiTabGroupProps:
_tab_labels: Tuple[str, ...]
diff --git a/src/viser/client/package.json b/src/viser/client/package.json
index 935acbf96..31b2539ff 100644
--- a/src/viser/client/package.json
+++ b/src/viser/client/package.json
@@ -34,6 +34,7 @@
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-error-boundary": "^4.0.10",
+ "recharts": "^2.12.7",
"react-intersection-observer": "^9.13.1",
"react-qr-code": "^2.0.12",
"rehype-color-chips": "^0.1.3",
diff --git a/src/viser/client/src/ControlPanel/Generated.tsx b/src/viser/client/src/ControlPanel/Generated.tsx
index 3540ddb80..cc3c16b1f 100644
--- a/src/viser/client/src/ControlPanel/Generated.tsx
+++ b/src/viser/client/src/ControlPanel/Generated.tsx
@@ -17,6 +17,7 @@ import RgbaComponent from "../components/Rgba";
import ButtonGroupComponent from "../components/ButtonGroup";
import MarkdownComponent from "../components/Markdown";
import PlotlyComponent from "../components/PlotlyComponent";
+import LineChartComponent from "../components/LineChart";
import TabGroupComponent from "../components/TabGroup";
import FolderComponent from "../components/Folder";
import MultiSliderComponent from "../components/MultiSlider";
@@ -106,6 +107,8 @@ function GeneratedInput(props: { guiUuid: string }) {
return ;
case "GuiPlotlyMessage":
return ;
+ case "GuiLineChartMessage":
+ return ;
case "GuiImageMessage":
return ;
case "GuiButtonMessage":
diff --git a/src/viser/client/src/WebsocketMessages.ts b/src/viser/client/src/WebsocketMessages.ts
index ce31874a3..6baea9e42 100644
--- a/src/viser/client/src/WebsocketMessages.ts
+++ b/src/viser/client/src/WebsocketMessages.ts
@@ -487,6 +487,28 @@ export interface GuiImageMessage {
visible: boolean;
};
}
+/** GuiLineChartMessage(uuid: 'str', container_uuid: 'str', props: 'GuiLineChartProps')
+ *
+ * (automatically generated)
+ */
+export interface GuiLineChartMessage {
+ type: "GuiLineChartMessage";
+ uuid: string;
+ container_uuid: string;
+ props: {
+ order: number;
+ title: string | null;
+ x_label: string | null;
+ y_label: string | null;
+ _series_data: {
+ name: string;
+ data: { x: number; y: number }[];
+ color: string | null;
+ }[];
+ height: number;
+ visible: boolean;
+ };
+}
/** GuiTabGroupMessage(uuid: 'str', container_uuid: 'str', props: 'GuiTabGroupProps')
*
* (automatically generated)
@@ -1290,6 +1312,7 @@ export type Message =
| GuiProgressBarMessage
| GuiPlotlyMessage
| GuiImageMessage
+ | GuiLineChartMessage
| GuiTabGroupMessage
| GuiButtonMessage
| GuiUploadButtonMessage
@@ -1376,6 +1399,7 @@ export type GuiComponentMessage =
| GuiProgressBarMessage
| GuiPlotlyMessage
| GuiImageMessage
+ | GuiLineChartMessage
| GuiTabGroupMessage
| GuiButtonMessage
| GuiUploadButtonMessage
@@ -1428,6 +1452,7 @@ const typeSetGuiComponentMessage = new Set([
"GuiProgressBarMessage",
"GuiPlotlyMessage",
"GuiImageMessage",
+ "GuiLineChartMessage",
"GuiTabGroupMessage",
"GuiButtonMessage",
"GuiUploadButtonMessage",
diff --git a/src/viser/client/src/components/LineChart.tsx b/src/viser/client/src/components/LineChart.tsx
new file mode 100644
index 000000000..91126837a
--- /dev/null
+++ b/src/viser/client/src/components/LineChart.tsx
@@ -0,0 +1,104 @@
+import React from "react";
+import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from "recharts";
+import { Box, Paper, Text } from "@mantine/core";
+import { GuiLineChartMessage } from "../WebsocketMessages";
+import { folderWrapper } from "./Folder.css";
+
+interface DataPoint {
+ x: number;
+ y: number;
+ [key: string]: number;
+}
+
+function processSeriesData(seriesData: GuiLineChartMessage["props"]["_series_data"]): DataPoint[] {
+ if (seriesData.length === 0) return [];
+
+ // Create a map of x values to data points
+ const xValueMap = new Map();
+
+ // Populate the map with all x values and their corresponding y values for each series
+ seriesData.forEach((series) => {
+ series.data.forEach((point) => {
+ if (!xValueMap.has(point.x)) {
+ xValueMap.set(point.x, { x: point.x, y: 0 });
+ }
+ const dataPoint = xValueMap.get(point.x)!;
+ dataPoint[series.name] = point.y;
+ });
+ });
+
+ // Convert map to array and sort by x value
+ return Array.from(xValueMap.values()).sort((a, b) => a.x - b.x);
+}
+
+export default function LineChartComponent({
+ props: { visible, title, x_label, y_label, _series_data, height },
+}: GuiLineChartMessage) {
+ if (!visible) return <>>;
+
+ const data = processSeriesData(_series_data);
+
+ // Generate colors for series that don't have explicit colors
+ const getColor = (index: number, customColor?: string | null) => {
+ if (customColor) return customColor;
+
+ const colors = [
+ "#8884d8", "#82ca9d", "#ffc658", "#ff7c7c", "#8dd1e1",
+ "#d084d0", "#ffb347", "#87ceeb", "#98fb98", "#f0e68c"
+ ];
+ return colors[index % colors.length];
+ };
+
+ return (
+
+ {title && (
+
+ {title}
+
+ )}
+
+
+
+
+
+
+
+ {_series_data.length > 1 && (
+
+ )}
+ {_series_data.map((series, index) => (
+
+ ))}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/viser/client/yarn.lock b/src/viser/client/yarn.lock
index 712e34b0a..56eab7848 100644
--- a/src/viser/client/yarn.lock
+++ b/src/viser/client/yarn.lock
@@ -963,6 +963,57 @@
dependencies:
"@babel/types" "^7.20.7"
+"@types/d3-array@^3.0.3":
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5"
+ integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==
+
+"@types/d3-color@*":
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2"
+ integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==
+
+"@types/d3-ease@^3.0.0":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b"
+ integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==
+
+"@types/d3-interpolate@^3.0.1":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c"
+ integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==
+ dependencies:
+ "@types/d3-color" "*"
+
+"@types/d3-path@*":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.1.1.tgz#f632b380c3aca1dba8e34aa049bcd6a4af23df8a"
+ integrity sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==
+
+"@types/d3-scale@^4.0.2":
+ version "4.0.9"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.9.tgz#57a2f707242e6fe1de81ad7bfcccaaf606179afb"
+ integrity sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==
+ dependencies:
+ "@types/d3-time" "*"
+
+"@types/d3-shape@^3.1.0":
+ version "3.1.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.7.tgz#2b7b423dc2dfe69c8c93596e673e37443348c555"
+ integrity sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==
+ dependencies:
+ "@types/d3-path" "*"
+
+"@types/d3-time@*", "@types/d3-time@^3.0.0":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.4.tgz#8472feecd639691450dd8000eb33edd444e1323f"
+ integrity sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==
+
+"@types/d3-timer@^3.0.0":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70"
+ integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==
+
"@types/debug@^4.0.0":
version "4.1.12"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
@@ -1596,7 +1647,7 @@ character-reference-invalid@^2.0.0:
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9"
integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==
-clsx@^2.1.1:
+clsx@^2.0.0, clsx@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
@@ -1684,11 +1735,77 @@ csstype@^3.0.2, csstype@^3.0.7:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
-d3-color@^3.1.0:
+"d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6:
+ version "3.2.4"
+ resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5"
+ integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==
+ dependencies:
+ internmap "1 - 2"
+
+"d3-color@1 - 3", d3-color@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2"
integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==
+d3-ease@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4"
+ integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==
+
+"d3-format@1 - 3":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641"
+ integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==
+
+"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d"
+ integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
+ dependencies:
+ d3-color "1 - 3"
+
+d3-path@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526"
+ integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==
+
+d3-scale@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396"
+ integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==
+ dependencies:
+ d3-array "2.10.0 - 3"
+ d3-format "1 - 3"
+ d3-interpolate "1.2.0 - 3"
+ d3-time "2.1.1 - 3"
+ d3-time-format "2 - 4"
+
+d3-shape@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5"
+ integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==
+ dependencies:
+ d3-path "^3.1.0"
+
+"d3-time-format@2 - 4":
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a"
+ integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==
+ dependencies:
+ d3-time "1 - 3"
+
+"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7"
+ integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==
+ dependencies:
+ d3-array "2 - 3"
+
+d3-timer@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0"
+ integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
+
data-view-buffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570"
@@ -1723,6 +1840,11 @@ debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3
dependencies:
ms "^2.1.3"
+decimal.js-light@^2.4.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934"
+ integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==
+
decode-named-character-reference@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz#5d6ce68792808901210dac42a8e9853511e2b8bf"
@@ -2273,6 +2395,11 @@ eval@0.1.8:
"@types/node" "*"
require-like ">= 0.1.1"
+eventemitter3@^4.0.1:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
+
extend@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
@@ -2283,6 +2410,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+fast-equals@^5.0.1:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.2.2.tgz#885d7bfb079fac0ce0e8450374bce29e9b742484"
+ integrity sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==
+
fast-glob@^3.2.11, fast-glob@^3.2.9:
version "3.3.3"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
@@ -2687,6 +2819,11 @@ internal-slot@^1.1.0:
hasown "^2.0.2"
side-channel "^1.1.0"
+"internmap@1 - 2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009"
+ integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==
+
is-alphabetical@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b"
@@ -3037,6 +3174,11 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
longest-streak@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
@@ -4053,6 +4195,11 @@ react-is@^16.13.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+react-is@^18.3.1:
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
+ integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
+
react-number-format@^5.4.3:
version "5.4.3"
resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-5.4.3.tgz#e634df907da7742faf597afab3f25f9a59689d60"
@@ -4097,6 +4244,15 @@ react-remove-scroll@^2.6.2:
use-callback-ref "^1.3.3"
use-sidecar "^1.1.3"
+react-smooth@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-4.0.4.tgz#a5875f8bb61963ca61b819cedc569dc2453894b4"
+ integrity sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==
+ dependencies:
+ fast-equals "^5.0.1"
+ prop-types "^15.8.1"
+ react-transition-group "^4.4.5"
+
react-style-singleton@^2.2.2, react-style-singleton@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388"
@@ -4114,7 +4270,7 @@ react-textarea-autosize@8.5.6:
use-composed-ref "^1.3.0"
use-latest "^1.2.1"
-react-transition-group@4.4.5:
+react-transition-group@4.4.5, react-transition-group@^4.4.5:
version "4.4.5"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
@@ -4134,6 +4290,27 @@ react@^19.0.0:
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
+recharts-scale@^0.4.4:
+ version "0.4.5"
+ resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.5.tgz#0969271f14e732e642fcc5bd4ab270d6e87dd1d9"
+ integrity sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==
+ dependencies:
+ decimal.js-light "^2.4.1"
+
+recharts@^2.12.7:
+ version "2.15.3"
+ resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.15.3.tgz#b94d05e91e3a5df1b02368ef64400dec9e9a77d4"
+ integrity sha512-EdOPzTwcFSuqtvkDoaM5ws/Km1+WTAO2eizL7rqiG0V2UVhTnz0m7J2i0CjVPUCdEkZImaWvXLbZDS2H5t6GFQ==
+ dependencies:
+ clsx "^2.0.0"
+ eventemitter3 "^4.0.1"
+ lodash "^4.17.21"
+ react-is "^18.3.1"
+ react-smooth "^4.0.4"
+ recharts-scale "^0.4.4"
+ tiny-invariant "^1.3.1"
+ victory-vendor "^36.6.8"
+
recma-build-jsx@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz#c02f29e047e103d2fab2054954e1761b8ea253c4"
@@ -4675,6 +4852,11 @@ three@^0.174.0:
resolved "https://registry.yarnpkg.com/three/-/three-0.174.0.tgz#53f46d6fd27515231b2af321f798f1e0ecf3f905"
integrity sha512-p+WG3W6Ov74alh3geCMkGK9NWuT62ee21cV3jEnun201zodVF4tCE5aZa2U122/mkLRmhJJUQmLLW1BH00uQJQ==
+tiny-invariant@^1.3.1:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
+ integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
+
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
@@ -4991,6 +5173,26 @@ vfile@^6.0.0:
"@types/unist" "^3.0.0"
vfile-message "^4.0.0"
+victory-vendor@^36.6.8:
+ version "36.9.2"
+ resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.9.2.tgz#668b02a448fa4ea0f788dbf4228b7e64669ff801"
+ integrity sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==
+ dependencies:
+ "@types/d3-array" "^3.0.3"
+ "@types/d3-ease" "^3.0.0"
+ "@types/d3-interpolate" "^3.0.1"
+ "@types/d3-scale" "^4.0.2"
+ "@types/d3-shape" "^3.1.0"
+ "@types/d3-time" "^3.0.0"
+ "@types/d3-timer" "^3.0.0"
+ d3-array "^3.1.6"
+ d3-ease "^3.0.1"
+ d3-interpolate "^3.0.1"
+ d3-scale "^4.0.2"
+ d3-shape "^3.1.0"
+ d3-time "^3.0.0"
+ d3-timer "^3.0.1"
+
vite-node@^3.0.4:
version "3.0.9"
resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.0.9.tgz#97d0b062d3857fb8eaeb6cc6a1d400f847d4a15d"