p3 improvements

This commit is contained in:
2026-04-11 08:21:41 -04:00
parent 1125105152
commit 9e9bde33b8
8 changed files with 397 additions and 43 deletions

BIN
.coverage

Binary file not shown.

View File

@@ -1,10 +1,11 @@
# Impakt -- Project Status # Impakt -- Project Status
**Date:** 2026-04-10 **Date:** 2026-04-11
**Version:** 0.1.0 **Version:** 0.1.0
**Tests:** 181 passing **Tests:** 240 passing (69.7% coverage)
**Source:** ~11,000 lines (py+js+css+html) | ~2,150 lines tests **Source:** ~10,300 lines (py) | ~2,700 lines tests
**Tooling:** uv (Python 3.12.12), hatchling build backend **Quality:** 78.3/100 (Grade B) -- see `docs/QA-*.md`
**Tooling:** uv (Python 3.12.12), hatchling build backend, ruff, mypy strict
--- ---
@@ -13,7 +14,7 @@
```bash ```bash
cd /Users/noise/Code/impakt cd /Users/noise/Code/impakt
uv sync --dev # install all dependencies uv sync --dev # install all dependencies
uv run pytest tests/ # run all 181 tests uv run pytest tests/ # run all 240 tests (with coverage)
uv run impakt info tests/mme_data/3239 # show test metadata uv run impakt info tests/mme_data/3239 # show test metadata
uv run impakt serve tests/mme_data/3239 # launch web UI on :8050 uv run impakt serve tests/mme_data/3239 # launch web UI on :8050
``` ```
@@ -211,13 +212,59 @@ Every selected channel has a stable color index (position in selection order). T
--- ---
## Next Steps (Priority 3) ## Roadmap
1. **Annotations** -- text on plots, measurement lines, highlight regions Informed by competitive landscape survey (`research/landscape.md`). No open-source web-based tool covers this domain end-to-end. See `BRAINSTORM.md` for full feature ideas with priority tiers.
2. **Comparison mode** -- side-by-side tests, delta plots, synced cursors
3. **Report builder** -- drag-and-drop report composer, PDF preview ### Priority 3 — Performance & Rendering
4. **Keyboard shortcuts** -- Ctrl+O, Ctrl+S, 1-9 pane switch, F fullscreen, R reset zoom
5. **Consider Python/WASM frontend** -- NiceGUI or Solara for pure-Python UI (no JS) Goal: handle large datasets (500+ channels, 100kHz sample rates) without lag.
1. **plotly-resampler integration** -- Drop-in `FigureResampler` wrapper for Plotly figures. Handles 110M+ points via LTTB downsampling. Works natively with Dash. Repo cloned at `research/repos/plotly-resampler/`. This is the single highest-impact performance improvement.
2. **Synchronized zoom/pan** -- When plotting multiple subplots, zoom/pan syncs across all panes sharing an X axis. Most-requested feature in crash test visualization. Implement via shared `xaxis` config or callback-based range sync.
3. **Lazy channel loading** -- Load `.dat` files on first access, not at `Session.open()`. Load headers eagerly, data lazily. Keeps startup fast for tests with 500+ channels.
4. **Channel sparklines** -- Tiny inline sparklines in the channel grid sidebar. Engineers visually scan 100+ channels before selecting. A 60px-wide sparkline column is transformative for signal browsing.
### Priority 4 — Data Format Expansion
Goal: read the world's crash test data, not just ISO MME.
5. **UDS reader plugin** -- NHTSA's proprietary binary format. Required to access the largest public crash test database. The NHTSA-Tools Fortran source (`research/repos/NHTSA-Tools/`) documents the UDS spec.
6. **ASAM MDF reader plugin** -- Standard for ECU/CAN bus measurement data. Many labs record vehicle bus data alongside crash instrumentation. asammdf (`research/repos/asammdf/`) is a mature library — add as optional dependency.
7. **Flexible CSV reader** -- Column mapping, delimiter detection, header conventions. Engineers frequently receive data as CSV exports from other tools.
### Priority 5 — Comparison & Reporting
Goal: make multi-test comparison and deliverable generation effortless.
8. **Quick comparison mode** -- Two tests side-by-side with synchronized cursors. One-click "compare" button. Color-by-test with channel differentiation via line dash.
9. **Multi-page PDF reports** -- Combine plots + injury summary + protocol rating into a single PDF with table of contents. Currently each report type is standalone.
10. **Excel export** -- Criteria results and cursor values to .xlsx. Engineers live in spreadsheets.
11. **Static HTML export** -- Bundle data + Plotly.js into a self-contained HTML file. Opens in any browser without a Python server. Learned from FalCon's CustomerView distribution model.
### Priority 6 — Video & Advanced Analysis
Goal: close the biggest remaining gap vs. commercial tools.
12. **Video synchronization** -- Link high-speed camera footage with channel data. Scrubbing video moves the time cursor; moving the cursor seeks the video. Every major commercial competitor (measX, DIAdem, Kistler, FalCon) has this. Foxglove and Rerun demonstrate web-native approaches.
13. **Frequency spectrum viewer** -- FFT / PSD alongside time-domain plots. Diagnose noise, verify CFC filter behavior.
14. **Integration / differentiation transforms** -- Acceleration -> velocity -> displacement with cumulative unit tracking.
15. **Data quality dashboard** -- Automated polarity check, sensor sanity, missing channel detection, completeness scoring. No commercial competitor is strong here — opportunity to differentiate.
### Priority 7 — Simulation Correlation & Ecosystem
Goal: bridge the gap between physical test and CAE simulation.
16. **LS-DYNA data import** via lasso-python (`research/repos/lasso-python/`). Enables test-vs-simulation overlay — a premium feature in Altair HyperGraph and Siemens Simcenter.
17. **ISO/TS 18571 CORA correlation** -- Quantitative rating of test-vs-simulation agreement. Standard metric for model validation.
18. **Additional injury criteria** -- BrIC, DAMAGE, TTI, pedestrian criteria, OLC. Required for broader Euro NCAP coverage.
19. **Additional NCAP programs** -- J-NCAP, C-NCAP, K-NCAP, ANCAP, Latin NCAP as protocol plugins.
20. **Jupyter integration** -- `_repr_html_` on Session, Channel, ProtocolResult for rich notebook output.
### Validation (ongoing)
- **Cross-validate CFC filter** against PyAvia's J211_2pole (`research/repos/pyavia/`) and NHTSA-Tools' BwFilt. PyAvia's author notes that scipy's generic `sosfiltfilt` may differ from the SAE J211 Appendix C digital Butterworth algorithm for CFC 60 and 180.
- **Cross-validate injury criteria** against NHTSA-Tools Fortran reference implementations, pyisomme, and EPFL crash-tests-service-robots. Four independent codebases available in `research/repos/`.
--- ---
@@ -238,7 +285,8 @@ Every selected channel has a stable color index (position in selection order). T
Core: numpy, scipy, plotly, dash, dash-bootstrap-components, pandas, pyyaml, jinja2, weasyprint, pydantic Core: numpy, scipy, plotly, dash, dash-bootstrap-components, pandas, pyyaml, jinja2, weasyprint, pydantic
Dev: pytest, pytest-cov, ruff, mypy Dev: pytest, pytest-cov, ruff, mypy
Optional: nptdms (for future TDMS reader plugin) Optional: nptdms (TDMS reader plugin)
Planned: plotly-resampler (P3), asammdf (P4), openpyxl (P5), lasso-python (P7)
--- ---
@@ -249,4 +297,29 @@ Optional: nptdms (for future TDMS reader plugin)
3. **DataTable deprecation warning** -- Dash recommends migrating to dash-ag-grid. 3. **DataTable deprecation warning** -- Dash recommends migrating to dash-ag-grid.
4. **Cursor poll interval (80ms)** -- slight latency in cursor grid updates. 4. **Cursor poll interval (80ms)** -- slight latency in cursor grid updates.
5. **Chest deflection auto-detect** skips DS channels with peak > 150mm to avoid steering column displacement. 5. **Chest deflection auto-detect** skips DS channels with peak > 150mm to avoid steering column displacement.
6. **Dead files** -- `cursors.py` and `inspector.py` were replaced by `channel_values.py` and deleted; `inspector_callbacks.py` deleted. If old `.pyc` files cause issues, run `find src -name __pycache__ -type d | xargs rm -rf`. 6. **CFC filter implementation** uses scipy `sosfiltfilt` which may diverge from SAE J211 Appendix C for CFC 60/180. Needs cross-validation against PyAvia and NHTSA-Tools reference implementations.
---
## Quality Assurance
Automated QA scoring is configured:
- **Scoring agent:** `.claude/agents/quality-scorer.md` -- collects metrics, applies rubrics, writes report
- **Improvement agent:** `.claude/agents/qa-improver.md` -- reads QA report, auto-fixes mechanical issues
- **Methodology:** `docs/QA-INSTRUCTIONS.md` -- reproducible 8-dimension rubric
- **Reports:** `docs/QA-*.md` -- timestamped scorecards with deltas
- **Scripts:** `scripts/qa-score.sh` (score only), `scripts/qa-improve.sh` (score -> fix -> re-score)
---
## Competitive Landscape
Full survey at `research/landscape.md` with 11 cloned open-source repos in `research/repos/`.
**Key finding:** No existing tool combines open-source + web-based + ISO-MME + CFC + injury criteria + protocol scoring + templates + reports. Commercial tools (measX X-Crash, NI DIAdem, Kistler) do this but are expensive and Windows-only. Impakt occupies a genuinely unserved niche.
**Most actionable libraries:**
- plotly-resampler (performance) -- `research/repos/plotly-resampler/`
- asammdf (MDF format) -- `research/repos/asammdf/`
- lasso-python (LS-DYNA) -- `research/repos/lasso-python/`
- PyAvia, NHTSA-Tools (validation) -- `research/repos/pyavia/`, `research/repos/NHTSA-Tools/`

View File

@@ -35,6 +35,8 @@ dependencies = [
"jinja2>=3.1", "jinja2>=3.1",
"weasyprint>=60.0", "weasyprint>=60.0",
"pydantic>=2.0", "pydantic>=2.0",
"plotly-resampler>=0.11.0",
"pytz>=2026.1.post1",
] ]
[project.optional-dependencies] [project.optional-dependencies]

View File

@@ -5,17 +5,24 @@ support for corridors, dual X-cursors, and export.
The PlotEngine is the **single rendering path** — both the scripting The PlotEngine is the **single rendering path** — both the scripting
API and the web UI construct PlotSpec objects and delegate here. API and the web UI construct PlotSpec objects and delegate here.
When ``resample=True``, wraps the figure in a plotly-resampler
``FigureResampler`` for dynamic LTTB downsampling on zoom/pan.
""" """
from __future__ import annotations from __future__ import annotations
import logging
from typing import Any from typing import Any
import plotly.graph_objects as go import plotly.graph_objects as go
from plotly_resampler import FigureResampler
from impakt.channel.model import Channel from impakt.channel.model import Channel
from impakt.plot.spec import Corridor, CursorValues, PlotSpec from impakt.plot.spec import Corridor, CursorValues, PlotSpec
logger = logging.getLogger(__name__)
# Default color palette (colorblind-friendly) # Default color palette (colorblind-friendly)
DEFAULT_COLORS = [ DEFAULT_COLORS = [
"#1f77b4", # blue "#1f77b4", # blue
@@ -39,11 +46,32 @@ class PlotEngine:
- **Compact** (``spec.compact=True``): Web UI mode with no legend, no - **Compact** (``spec.compact=True``): Web UI mode with no legend, no
hover tooltips, tight margins, smaller axis labels. Cursor tracking hover tooltips, tight margins, smaller axis labels. Cursor tracking
is handled by external JS. is handled by external JS.
When ``resample=True``, the figure is wrapped in a
``FigureResampler`` that dynamically downsamples traces via LTTB
aggregation on zoom/pan events.
""" """
def render(self, spec: PlotSpec) -> go.Figure: def render(
"""Render a PlotSpec into an interactive Plotly figure.""" self, spec: PlotSpec, *, resample: bool = False
fig = go.Figure() ) -> go.Figure | FigureResampler:
"""Render a PlotSpec into an interactive Plotly figure.
Args:
spec: The plot specification.
resample: If True, wrap in FigureResampler for dynamic
downsampling. The caller must handle ``relayoutData``
callbacks to trigger resampling on zoom/pan.
Returns:
A ``go.Figure`` (default) or ``FigureResampler`` (when
``resample=True``).
"""
fig: go.Figure | FigureResampler
if resample:
fig = FigureResampler(go.Figure(), default_n_shown_samples=1500)
else:
fig = go.Figure()
if not spec.channels: if not spec.channels:
fig.update_layout( fig.update_layout(
@@ -67,7 +95,7 @@ class PlotEngine:
# Add corridor fills first (behind data traces) # Add corridor fills first (behind data traces)
for corridor in spec.corridors: for corridor in spec.corridors:
self._add_corridor(fig, corridor) self._add_corridor(fig, corridor, resample=resample)
# Add channel traces # Add channel traces
for i, ch_ref in enumerate(spec.channels): for i, ch_ref in enumerate(spec.channels):
@@ -84,8 +112,6 @@ class PlotEngine:
label = style.label or ch_ref.label label = style.label or ch_ref.label
trace_kwargs: dict[str, Any] = { trace_kwargs: dict[str, Any] = {
"x": ch.time,
"y": ch.data,
"mode": "lines", "mode": "lines",
"name": label, "name": label,
"line": dict( "line": dict(
@@ -101,7 +127,18 @@ class PlotEngine:
f"{label}<br>t=%{{x:.6f}}s<br>%{{y:.4f}} {ch.unit}<extra></extra>" f"{label}<br>t=%{{x:.6f}}s<br>%{{y:.4f}} {ch.unit}<extra></extra>"
) )
fig.add_trace(go.Scatter(**trace_kwargs)) if resample:
# FigureResampler: pass full-resolution data via hf_x/hf_y
# and use Scattergl for WebGL-accelerated rendering
fig.add_trace(
go.Scattergl(**trace_kwargs),
hf_x=ch.time,
hf_y=ch.data,
)
else:
trace_kwargs["x"] = ch.time
trace_kwargs["y"] = ch.data
fig.add_trace(go.Scatter(**trace_kwargs))
# Add cursor lines # Add cursor lines
if spec.x_cursors: if spec.x_cursors:
@@ -181,33 +218,43 @@ class PlotEngine:
return fig return fig
def _add_corridor(self, fig: go.Figure, corridor: Corridor) -> None: def _add_corridor(
self,
fig: go.Figure | FigureResampler,
corridor: Corridor,
*,
resample: bool = False,
) -> None:
"""Add a corridor (tolerance band) to the figure.""" """Add a corridor (tolerance band) to the figure."""
style = corridor.style style = corridor.style
fig.add_trace( upper_trace = go.Scatter(
go.Scatter( x=corridor.time,
x=corridor.time, y=corridor.upper,
y=corridor.upper, mode="lines",
mode="lines", name=f"{corridor.name} (upper)",
name=f"{corridor.name} (upper)", line=dict(color=style.line_color, width=style.line_width, dash=style.line_dash),
line=dict(color=style.line_color, width=style.line_width, dash=style.line_dash), showlegend=False,
showlegend=False,
)
) )
fig.add_trace( lower_trace = go.Scatter(
go.Scatter( x=corridor.time,
x=corridor.time, y=corridor.lower,
y=corridor.lower, mode="lines",
mode="lines", name=f"{corridor.name} (lower)",
name=f"{corridor.name} (lower)", line=dict(color=style.line_color, width=style.line_width, dash=style.line_dash),
line=dict(color=style.line_color, width=style.line_width, dash=style.line_dash), fill="tonexty",
fill="tonexty", fillcolor=style.fill_color,
fillcolor=style.fill_color, showlegend=True,
showlegend=True,
)
) )
if resample:
# Corridors are small — pass through without downsampling
fig.add_trace(upper_trace, limit_to_view=False)
fig.add_trace(lower_trace, limit_to_view=False)
else:
fig.add_trace(upper_trace)
fig.add_trace(lower_trace)
def to_image(self, spec: PlotSpec, format: str = "png", scale: float = 2.0) -> bytes: def to_image(self, spec: PlotSpec, format: str = "png", scale: float = 2.0) -> bytes:
"""Render to a static image.""" """Render to a static image."""
fig = self.render(spec) fig = self.render(spec)

View File

@@ -6,17 +6,23 @@ scripting API renders the web UI plots.
Transform application uses TransformChain, making the pipeline Transform application uses TransformChain, making the pipeline
serializable and reproducible. serializable and reproducible.
The plot figure is wrapped in a ``FigureResampler`` for dynamic LTTB
downsampling on zoom/pan events. A separate ``relayoutData`` callback
triggers resampling when the user interacts with the axes.
""" """
from __future__ import annotations from __future__ import annotations
import logging
from collections import defaultdict from collections import defaultdict
from typing import Any from typing import Any
import dash import dash
import numpy as np import numpy as np
import plotly.graph_objects as go import plotly.graph_objects as go
from dash import Input, Output, State from dash import Input, Output, State, no_update
from plotly_resampler import FigureResampler
from impakt.channel.model import Channel from impakt.channel.model import Channel
from impakt.plot.engine import DEFAULT_COLORS, PlotEngine from impakt.plot.engine import DEFAULT_COLORS, PlotEngine
@@ -27,9 +33,15 @@ from impakt.transform.cfc import CFCFilter
from impakt.transform.resultant import resultant_from_channels from impakt.transform.resultant import resultant_from_channels
from impakt.web.state import AppState from impakt.web.state import AppState
logger = logging.getLogger(__name__)
# Module-level engine instance (stateless, safe to reuse) # Module-level engine instance (stateless, safe to reuse)
_engine = PlotEngine() _engine = PlotEngine()
# Server-side storage for the current FigureResampler instance.
# Single-user desktop app — no multi-tenant isolation needed.
_current_resampler: FigureResampler | None = None
def _build_transform_chain( def _build_transform_chain(
cfc_value: str, cfc_value: str,
@@ -201,6 +213,7 @@ def _build_plot_spec(
def register_plot_callbacks(app: dash.Dash, app_state: AppState) -> None: def register_plot_callbacks(app: dash.Dash, app_state: AppState) -> None:
"""Register all plot-related callbacks.""" """Register all plot-related callbacks."""
global _current_resampler
@app.callback( @app.callback(
Output({"type": "plot-graph", "index": 0}, "figure"), Output({"type": "plot-graph", "index": 0}, "figure"),
@@ -231,6 +244,8 @@ def register_plot_callbacks(app: dash.Dash, app_state: AppState) -> None:
corridors_data: list[dict[str, Any]] | None, corridors_data: list[dict[str, Any]] | None,
x_align_value: float | None, x_align_value: float | None,
) -> go.Figure: ) -> go.Figure:
global _current_resampler
if not selected_keys: if not selected_keys:
selected_keys = [] selected_keys = []
@@ -245,4 +260,25 @@ def register_plot_callbacks(app: dash.Dash, app_state: AppState) -> None:
) )
spec = _build_plot_spec(channels, cursor_x1, cursor_x2, corridors_data) spec = _build_plot_spec(channels, cursor_x1, cursor_x2, corridors_data)
return _engine.render(spec) fig = _engine.render(spec, resample=True)
# Store the resampler for relayoutData callbacks
if isinstance(fig, FigureResampler):
_current_resampler = fig
return fig
@app.callback(
Output({"type": "plot-graph", "index": 0}, "figure", allow_duplicate=True),
Input({"type": "plot-graph", "index": 0}, "relayoutData"),
prevent_initial_call=True,
)
def resample_on_zoom(relayout_data: dict[str, Any] | None) -> Any:
"""Resample traces when the user zooms or pans.
FigureResampler intercepts relayoutData events and returns a
Patch that updates only the visible trace data — no full re-render.
"""
if _current_resampler is None or relayout_data is None:
return no_update
return _current_resampler.construct_update_data_patch(relayout_data)

View File

@@ -13,17 +13,59 @@ without reordering.
from __future__ import annotations from __future__ import annotations
import base64
import fnmatch import fnmatch
from typing import Any from typing import Any
import dash_bootstrap_components as dbc import dash_bootstrap_components as dbc
import numpy as np
from dash import dash_table, dcc, html from dash import dash_table, dcc, html
from impakt.channel.lookup import MAIN_LOCATIONS, MEASUREMENTS from impakt.channel.lookup import MAIN_LOCATIONS, MEASUREMENTS
from impakt.channel.model import Channel
from impakt.plot.engine import DEFAULT_COLORS from impakt.plot.engine import DEFAULT_COLORS
from impakt.web.state import AppState from impakt.web.state import AppState
def _sparkline_svg(ch: Channel, width: int = 60, height: int = 16) -> str:
"""Generate a tiny inline SVG sparkline for a channel.
Returns a base64-encoded data URI suitable for use in a Dash
DataTable markdown cell: ``![](data:image/svg+xml;base64,...)``.
"""
data = ch.data
n = len(data)
if n < 2:
return ""
# Downsample to ~60 points for the sparkline
if n > 60:
indices = np.linspace(0, n - 1, 60, dtype=int)
data = data[indices]
n = 60
# Normalize to SVG coordinate space
dmin = float(np.min(data))
dmax = float(np.max(data))
drange = dmax - dmin
if drange == 0:
drange = 1.0
xs = np.linspace(1, width - 1, n)
ys = height - 1 - ((data - dmin) / drange) * (height - 2)
# Build SVG polyline path
points = " ".join(f"{x:.1f},{y:.1f}" for x, y in zip(xs, ys))
svg = (
f'<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="{height}">'
f'<polyline points="{points}" fill="none" stroke="#6c757d" stroke-width="1"/>'
f"</svg>"
)
encoded = base64.b64encode(svg.encode()).decode()
return f'<img src="data:image/svg+xml;base64,{encoded}" />'
def _build_channel_rows(app_state: AppState) -> list[dict[str, Any]]: def _build_channel_rows(app_state: AppState) -> list[dict[str, Any]]:
"""Build flat row data for the channel grid. """Build flat row data for the channel grid.
@@ -63,6 +105,7 @@ def _build_channel_rows(app_state: AppState) -> list[dict[str, Any]]:
"test_id": test_id if multi_test else "", "test_id": test_id if multi_test else "",
"iso_code": ch.name, "iso_code": ch.name,
"description": desc, "description": desc,
"spark": _sparkline_svg(ch),
"unit": ch.unit, "unit": ch.unit,
"min": f"{float(ch.data.min()):.2f}", "min": f"{float(ch.data.min()):.2f}",
"max": f"{float(ch.data.max()):.2f}", "max": f"{float(ch.data.max()):.2f}",
@@ -115,6 +158,7 @@ def build_channel_grid(app_state: AppState) -> dbc.Card:
{"name": "#", "id": "ch_num", "type": "numeric"}, {"name": "#", "id": "ch_num", "type": "numeric"},
{"name": "ISO Code", "id": "iso_code"}, {"name": "ISO Code", "id": "iso_code"},
{"name": "Description", "id": "description"}, {"name": "Description", "id": "description"},
{"name": "", "id": "spark", "presentation": "markdown"},
{"name": "Unit", "id": "unit"}, {"name": "Unit", "id": "unit"},
{"name": "Min", "id": "min", "type": "numeric"}, {"name": "Min", "id": "min", "type": "numeric"},
{"name": "Max", "id": "max", "type": "numeric"}, {"name": "Max", "id": "max", "type": "numeric"},
@@ -207,6 +251,7 @@ def build_channel_grid(app_state: AppState) -> dbc.Card:
id="channel-grid", id="channel-grid",
columns=columns, columns=columns,
data=rows, data=rows,
markdown_options={"html": True},
row_selectable="multi", row_selectable="multi",
selected_rows=[], selected_rows=[],
sort_action="native", sort_action="native",
@@ -255,6 +300,12 @@ def build_channel_grid(app_state: AppState) -> dbc.Card:
"width": "50px", "width": "50px",
"textAlign": "center", "textAlign": "center",
}, },
{
"if": {"column_id": "spark"},
"width": "68px",
"textAlign": "center",
"padding": "2px 4px",
},
{"if": {"column_id": "min"}, "width": "65px", "textAlign": "right"}, {"if": {"column_id": "min"}, "width": "65px", "textAlign": "right"},
{"if": {"column_id": "max"}, "width": "65px", "textAlign": "right"}, {"if": {"column_id": "max"}, "width": "65px", "textAlign": "right"},
{"if": {"column_id": "test_id"}, "width": "60px"}, {"if": {"column_id": "test_id"}, "width": "60px"},

145
uv.lock generated
View File

@@ -535,7 +535,9 @@ dependencies = [
{ name = "numpy" }, { name = "numpy" },
{ name = "pandas" }, { name = "pandas" },
{ name = "plotly" }, { name = "plotly" },
{ name = "plotly-resampler" },
{ name = "pydantic" }, { name = "pydantic" },
{ name = "pytz" },
{ name = "pyyaml" }, { name = "pyyaml" },
{ name = "scipy" }, { name = "scipy" },
{ name = "weasyprint" }, { name = "weasyprint" },
@@ -563,7 +565,9 @@ requires-dist = [
{ name = "numpy", specifier = ">=1.24" }, { name = "numpy", specifier = ">=1.24" },
{ name = "pandas", specifier = ">=2.0" }, { name = "pandas", specifier = ">=2.0" },
{ name = "plotly", specifier = ">=5.18" }, { name = "plotly", specifier = ">=5.18" },
{ name = "plotly-resampler", specifier = ">=0.11.0" },
{ name = "pydantic", specifier = ">=2.0" }, { name = "pydantic", specifier = ">=2.0" },
{ name = "pytz", specifier = ">=2026.1.post1" },
{ name = "pyyaml", specifier = ">=6.0" }, { name = "pyyaml", specifier = ">=6.0" },
{ name = "scipy", specifier = ">=1.10" }, { name = "scipy", specifier = ">=1.10" },
{ name = "weasyprint", specifier = ">=60.0" }, { name = "weasyprint", specifier = ">=60.0" },
@@ -932,6 +936,74 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/04/74/f4c001f4714c3ad9ce037e18cf2b9c64871a84951eaa0baf683a9ca9301c/numpy-2.4.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119", size = 12509075, upload-time = "2026-03-29T13:21:57.644Z" }, { url = "https://files.pythonhosted.org/packages/04/74/f4c001f4714c3ad9ce037e18cf2b9c64871a84951eaa0baf683a9ca9301c/numpy-2.4.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119", size = 12509075, upload-time = "2026-03-29T13:21:57.644Z" },
] ]
[[package]]
name = "orjson"
version = "3.11.8"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/9d/1b/2024d06792d0779f9dbc51531b61c24f76c75b9f4ce05e6f3377a1814cea/orjson-3.11.8.tar.gz", hash = "sha256:96163d9cdc5a202703e9ad1b9ae757d5f0ca62f4fa0cc93d1f27b0e180cc404e", size = 5603832, upload-time = "2026-03-31T16:16:27.878Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/67/41/5aa7fa3b0f4dc6b47dcafc3cea909299c37e40e9972feabc8b6a74e2730d/orjson-3.11.8-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:003646067cc48b7fcab2ae0c562491c9b5d2cbd43f1e5f16d98fd118c5522d34", size = 229229, upload-time = "2026-03-31T16:14:50.424Z" },
{ url = "https://files.pythonhosted.org/packages/0a/d7/57e7f2458e0a2c41694f39fc830030a13053a84f837a5b73423dca1f0938/orjson-3.11.8-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:ed193ce51d77a3830cad399a529cd4ef029968761f43ddc549e1bc62b40d88f8", size = 128871, upload-time = "2026-03-31T16:14:51.888Z" },
{ url = "https://files.pythonhosted.org/packages/53/4a/e0fdb9430983e6c46e0299559275025075568aad5d21dd606faee3703924/orjson-3.11.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30491bc4f862aa15744b9738517454f1e46e56c972a2be87d70d727d5b2a8f8", size = 132104, upload-time = "2026-03-31T16:14:53.142Z" },
{ url = "https://files.pythonhosted.org/packages/08/4a/2025a60ff3f5c8522060cda46612d9b1efa653de66ed2908591d8d82f22d/orjson-3.11.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6eda5b8b6be91d3f26efb7dc6e5e68ee805bc5617f65a328587b35255f138bf4", size = 130483, upload-time = "2026-03-31T16:14:54.605Z" },
{ url = "https://files.pythonhosted.org/packages/2d/3c/b9cde05bdc7b2385c66014e0620627da638d3d04e4954416ab48c31196c5/orjson-3.11.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee8db7bfb6fe03581bbab54d7c4124a6dd6a7f4273a38f7267197890f094675f", size = 135481, upload-time = "2026-03-31T16:14:55.901Z" },
{ url = "https://files.pythonhosted.org/packages/ff/f2/a8238e7734de7cb589fed319857a8025d509c89dc52fdcc88f39c6d03d5a/orjson-3.11.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d8b5231de76c528a46b57010bbd83fb51e056aa0220a372fd5065e978406f1c", size = 146819, upload-time = "2026-03-31T16:14:57.548Z" },
{ url = "https://files.pythonhosted.org/packages/db/10/dbf1e2a3cafea673b1b4350e371877b759060d6018a998643b7040e5de48/orjson-3.11.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58a4a208a6fbfdb7a7327b8f201c6014f189f721fd55d047cafc4157af1bc62a", size = 132846, upload-time = "2026-03-31T16:14:58.91Z" },
{ url = "https://files.pythonhosted.org/packages/f8/fc/55e667ec9c85694038fcff00573d221b085d50777368ee3d77f38668bf3c/orjson-3.11.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f8952d6d2505c003e8f0224ff7858d341fa4e33fef82b91c4ff0ef070f2393c", size = 133580, upload-time = "2026-03-31T16:15:00.519Z" },
{ url = "https://files.pythonhosted.org/packages/7e/a6/c08c589a9aad0cb46c4831d17de212a2b6901f9d976814321ff8e69e8785/orjson-3.11.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0022bb50f90da04b009ce32c512dc1885910daa7cb10b7b0cba4505b16db82a8", size = 142042, upload-time = "2026-03-31T16:15:01.906Z" },
{ url = "https://files.pythonhosted.org/packages/5c/cc/2f78ea241d52b717d2efc38878615fe80425bf2beb6e68c984dde257a766/orjson-3.11.8-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ff51f9d657d1afb6f410cb435792ce4e1fe427aab23d2fcd727a2876e21d4cb6", size = 423845, upload-time = "2026-03-31T16:15:03.703Z" },
{ url = "https://files.pythonhosted.org/packages/70/07/c17dcf05dd8045457538428a983bf1f1127928df5bf328cb24d2b7cddacb/orjson-3.11.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6dbe9a97bdb4d8d9d5367b52a7c32549bba70b2739c58ef74a6964a6d05ae054", size = 147729, upload-time = "2026-03-31T16:15:05.203Z" },
{ url = "https://files.pythonhosted.org/packages/90/6c/0fb6e8a24e682e0958d71711ae6f39110e4b9cd8cab1357e2a89cb8e1951/orjson-3.11.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5c370674ebabe16c6ccac33ff80c62bf8a6e59439f5e9d40c1f5ab8fd2215b7", size = 136425, upload-time = "2026-03-31T16:15:07.052Z" },
{ url = "https://files.pythonhosted.org/packages/b2/35/4d3cc3a3d616035beb51b24a09bb872942dc452cf2df0c1d11ab35046d9f/orjson-3.11.8-cp311-cp311-win32.whl", hash = "sha256:0e32f7154299f42ae66f13488963269e5eccb8d588a65bc839ed986919fc9fac", size = 131870, upload-time = "2026-03-31T16:15:08.678Z" },
{ url = "https://files.pythonhosted.org/packages/13/26/9fe70f81d16b702f8c3a775e8731b50ad91d22dacd14c7599b60a0941cd1/orjson-3.11.8-cp311-cp311-win_amd64.whl", hash = "sha256:25e0c672a2e32348d2eb33057b41e754091f2835f87222e4675b796b92264f06", size = 127440, upload-time = "2026-03-31T16:15:09.994Z" },
{ url = "https://files.pythonhosted.org/packages/e8/c6/b038339f4145efd2859c1ca53097a52c0bb9cbdd24f947ebe146da1ad067/orjson-3.11.8-cp311-cp311-win_arm64.whl", hash = "sha256:9185589c1f2a944c17e26c9925dcdbc2df061cc4a145395c57f0c51f9b5dbfcd", size = 127399, upload-time = "2026-03-31T16:15:11.412Z" },
{ url = "https://files.pythonhosted.org/packages/01/f6/8d58b32ab32d9215973a1688aebd098252ee8af1766c0e4e36e7831f0295/orjson-3.11.8-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1cd0b77e77c95758f8e1100139844e99f3ccc87e71e6fc8e1c027e55807c549f", size = 229233, upload-time = "2026-03-31T16:15:12.762Z" },
{ url = "https://files.pythonhosted.org/packages/a9/8b/2ffe35e71f6b92622e8ea4607bf33ecf7dfb51b3619dcfabfd36cbe2d0a5/orjson-3.11.8-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:6a3d159d5ffa0e3961f353c4b036540996bf8b9697ccc38261c0eac1fd3347a6", size = 128772, upload-time = "2026-03-31T16:15:14.237Z" },
{ url = "https://files.pythonhosted.org/packages/27/d2/1f8682ae50d5c6897a563cb96bc106da8c9cb5b7b6e81a52e4cc086679b9/orjson-3.11.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76070a76e9c5ae661e2d9848f216980d8d533e0f8143e6ed462807b242e3c5e8", size = 131946, upload-time = "2026-03-31T16:15:15.607Z" },
{ url = "https://files.pythonhosted.org/packages/52/4b/5500f76f0eece84226e0689cb48dcde081104c2fa6e2483d17ca13685ffb/orjson-3.11.8-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54153d21520a71a4c82a0dbb4523e468941d549d221dc173de0f019678cf3813", size = 130368, upload-time = "2026-03-31T16:15:17.066Z" },
{ url = "https://files.pythonhosted.org/packages/da/4e/58b927e08fbe9840e6c920d9e299b051ea667463b1f39a56e668669f8508/orjson-3.11.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:469ac2125611b7c5741a0b3798cd9e5786cbad6345f9f400c77212be89563bec", size = 135540, upload-time = "2026-03-31T16:15:18.404Z" },
{ url = "https://files.pythonhosted.org/packages/56/7c/ba7cb871cba1bcd5cd02ee34f98d894c6cea96353ad87466e5aef2429c60/orjson-3.11.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14778ffd0f6896aa613951a7fbf4690229aa7a543cb2bfbe9f358e08aafa9546", size = 146877, upload-time = "2026-03-31T16:15:19.833Z" },
{ url = "https://files.pythonhosted.org/packages/0b/5d/eb9c25fc1386696c6a342cd361c306452c75e0b55e86ad602dd4827a7fd7/orjson-3.11.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea56a955056a6d6c550cf18b3348656a9d9a4f02e2d0c02cabf3c73f1055d506", size = 132837, upload-time = "2026-03-31T16:15:21.282Z" },
{ url = "https://files.pythonhosted.org/packages/37/87/5ddeb7fc1fbd9004aeccab08426f34c81a5b4c25c7061281862b015fce2b/orjson-3.11.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53a0f57e59a530d18a142f4d4ba6dfc708dc5fdedce45e98ff06b44930a2a48f", size = 133624, upload-time = "2026-03-31T16:15:22.641Z" },
{ url = "https://files.pythonhosted.org/packages/22/09/90048793db94ee4b2fcec4ac8e5ddb077367637d6650be896b3494b79bb7/orjson-3.11.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9b48e274f8824567d74e2158199e269597edf00823a1b12b63d48462bbf5123e", size = 141904, upload-time = "2026-03-31T16:15:24.435Z" },
{ url = "https://files.pythonhosted.org/packages/c0/cf/eb284847487821a5d415e54149a6449ba9bfc5872ce63ab7be41b8ec401c/orjson-3.11.8-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3f262401086a3960586af06c054609365e98407151f5ea24a62893a40d80dbbb", size = 423742, upload-time = "2026-03-31T16:15:26.155Z" },
{ url = "https://files.pythonhosted.org/packages/44/09/e12423d327071c851c13e76936f144a96adacfc037394dec35ac3fc8d1e8/orjson-3.11.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8e8c6218b614badf8e229b697865df4301afa74b791b6c9ade01d19a9953a942", size = 147806, upload-time = "2026-03-31T16:15:27.909Z" },
{ url = "https://files.pythonhosted.org/packages/b3/6d/37c2589ba864e582ffe7611643314785c6afb1f83c701654ef05daa8fcc7/orjson-3.11.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:093d489fa039ddade2db541097dbb484999fcc65fc2b0ff9819141e2ab364f25", size = 136485, upload-time = "2026-03-31T16:15:29.749Z" },
{ url = "https://files.pythonhosted.org/packages/be/c9/135194a02ab76b04ed9a10f68624b7ebd238bbe55548878b11ff15a0f352/orjson-3.11.8-cp312-cp312-win32.whl", hash = "sha256:e0950ed1bcb9893f4293fd5c5a7ee10934fbf82c4101c70be360db23ce24b7d2", size = 131966, upload-time = "2026-03-31T16:15:31.687Z" },
{ url = "https://files.pythonhosted.org/packages/ed/9a/9796f8fbe3cf30ce9cb696748dbb535e5c87be4bf4fe2e9ca498ef1fa8cf/orjson-3.11.8-cp312-cp312-win_amd64.whl", hash = "sha256:3cf17c141617b88ced4536b2135c552490f07799f6ad565948ea07bef0dcb9a6", size = 127441, upload-time = "2026-03-31T16:15:33.333Z" },
{ url = "https://files.pythonhosted.org/packages/cc/47/5aaf54524a7a4a0dd09dd778f3fa65dd2108290615b652e23d944152bc8e/orjson-3.11.8-cp312-cp312-win_arm64.whl", hash = "sha256:48854463b0572cc87dac7d981aa72ed8bf6deedc0511853dc76b8bbd5482d36d", size = 127364, upload-time = "2026-03-31T16:15:34.748Z" },
{ url = "https://files.pythonhosted.org/packages/66/7f/95fba509bb2305fab0073558f1e8c3a2ec4b2afe58ed9fcb7d3b8beafe94/orjson-3.11.8-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3f23426851d98478c8970da5991f84784a76682213cd50eb73a1da56b95239dc", size = 229180, upload-time = "2026-03-31T16:15:36.426Z" },
{ url = "https://files.pythonhosted.org/packages/f6/9d/b237215c743ca073697d759b5503abd2cb8a0d7b9c9e21f524bcf176ab66/orjson-3.11.8-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:ebaed4cef74a045b83e23537b52ef19a367c7e3f536751e355a2a394f8648559", size = 128754, upload-time = "2026-03-31T16:15:38.049Z" },
{ url = "https://files.pythonhosted.org/packages/42/3d/27d65b6d11e63f133781425f132807aef793ed25075fec686fc8e46dd528/orjson-3.11.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97c8f5d3b62380b70c36ffacb2a356b7c6becec86099b177f73851ba095ef623", size = 131877, upload-time = "2026-03-31T16:15:39.484Z" },
{ url = "https://files.pythonhosted.org/packages/dd/cc/faee30cd8f00421999e40ef0eba7332e3a625ce91a58200a2f52c7fef235/orjson-3.11.8-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:436c4922968a619fb7fef1ccd4b8b3a76c13b67d607073914d675026e911a65c", size = 130361, upload-time = "2026-03-31T16:15:41.274Z" },
{ url = "https://files.pythonhosted.org/packages/5c/bb/a6c55896197f97b6d4b4e7c7fd77e7235517c34f5d6ad5aadd43c54c6d7c/orjson-3.11.8-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ab359aff0436d80bfe8a23b46b5fea69f1e18aaf1760a709b4787f1318b317f", size = 135521, upload-time = "2026-03-31T16:15:42.758Z" },
{ url = "https://files.pythonhosted.org/packages/9c/7c/ca3a3525aa32ff636ebb1778e77e3587b016ab2edb1b618b36ba96f8f2c0/orjson-3.11.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f89b6d0b3a8d81e1929d3ab3d92bbc225688bd80a770c49432543928fe09ac55", size = 146862, upload-time = "2026-03-31T16:15:44.341Z" },
{ url = "https://files.pythonhosted.org/packages/3c/0c/18a9d7f18b5edd37344d1fd5be17e94dc652c67826ab749c6e5948a78112/orjson-3.11.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29c009e7a2ca9ad0ed1376ce20dd692146a5d9fe4310848904b6b4fee5c5c137", size = 132847, upload-time = "2026-03-31T16:15:46.368Z" },
{ url = "https://files.pythonhosted.org/packages/23/91/7e722f352ad67ca573cee44de2a58fb810d0f4eb4e33276c6a557979fd8a/orjson-3.11.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b895b781b3e395c067129d8551655642dfe9437273211d5404e87ac752b53", size = 133637, upload-time = "2026-03-31T16:15:48.123Z" },
{ url = "https://files.pythonhosted.org/packages/af/04/32845ce13ac5bd1046ddb02ac9432ba856cc35f6d74dde95864fe0ad5523/orjson-3.11.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:88006eda83858a9fdf73985ce3804e885c2befb2f506c9a3723cdeb5a2880e3e", size = 141906, upload-time = "2026-03-31T16:15:49.626Z" },
{ url = "https://files.pythonhosted.org/packages/02/5e/c551387ddf2d7106d9039369862245c85738b828844d13b99ccb8d61fd06/orjson-3.11.8-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:55120759e61309af7fcf9e961c6f6af3dde5921cdb3ee863ef63fd9db126cae6", size = 423722, upload-time = "2026-03-31T16:15:51.176Z" },
{ url = "https://files.pythonhosted.org/packages/00/a3/ecfe62434096f8a794d4976728cb59bcfc4a643977f21c2040545d37eb4c/orjson-3.11.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:98bdc6cb889d19bed01de46e67574a2eab61f5cc6b768ed50e8ac68e9d6ffab6", size = 147801, upload-time = "2026-03-31T16:15:52.939Z" },
{ url = "https://files.pythonhosted.org/packages/18/6d/0dce10b9f6643fdc59d99333871a38fa5a769d8e2fc34a18e5d2bfdee900/orjson-3.11.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:708c95f925a43ab9f34625e45dcdadf09ec8a6e7b664a938f2f8d5650f6c090b", size = 136460, upload-time = "2026-03-31T16:15:54.431Z" },
{ url = "https://files.pythonhosted.org/packages/01/d6/6dde4f31842d87099238f1f07b459d24edc1a774d20687187443ab044191/orjson-3.11.8-cp313-cp313-win32.whl", hash = "sha256:01c4e5a6695dc09098f2e6468a251bc4671c50922d4d745aff1a0a33a0cf5b8d", size = 131956, upload-time = "2026-03-31T16:15:56.081Z" },
{ url = "https://files.pythonhosted.org/packages/c1/f9/4e494a56e013db957fb77186b818b916d4695b8fa2aa612364974160e91b/orjson-3.11.8-cp313-cp313-win_amd64.whl", hash = "sha256:c154a35dd1330707450bb4d4e7dd1f17fa6f42267a40c1e8a1daa5e13719b4b8", size = 127410, upload-time = "2026-03-31T16:15:57.54Z" },
{ url = "https://files.pythonhosted.org/packages/57/7f/803203d00d6edb6e9e7eef421d4e1adbb5ea973e40b3533f3cfd9aeb374e/orjson-3.11.8-cp313-cp313-win_arm64.whl", hash = "sha256:4861bde57f4d253ab041e374f44023460e60e71efaa121f3c5f0ed457c3a701e", size = 127338, upload-time = "2026-03-31T16:15:59.106Z" },
{ url = "https://files.pythonhosted.org/packages/6d/35/b01910c3d6b85dc882442afe5060cbf719c7d1fc85749294beda23d17873/orjson-3.11.8-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ec795530a73c269a55130498842aaa762e4a939f6ce481a7e986eeaa790e9da4", size = 229171, upload-time = "2026-03-31T16:16:00.651Z" },
{ url = "https://files.pythonhosted.org/packages/c2/56/c9ec97bd11240abef39b9e5d99a15462809c45f677420fd148a6c5e6295e/orjson-3.11.8-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:c492a0e011c0f9066e9ceaa896fbc5b068c54d365fea5f3444b697ee01bc8625", size = 128746, upload-time = "2026-03-31T16:16:02.673Z" },
{ url = "https://files.pythonhosted.org/packages/3b/e4/66d4f30a90de45e2f0cbd9623588e8ae71eef7679dbe2ae954ed6d66a41f/orjson-3.11.8-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:883206d55b1bd5f5679ad5e6ddd3d1a5e3cac5190482927fdb8c78fb699193b5", size = 131867, upload-time = "2026-03-31T16:16:04.342Z" },
{ url = "https://files.pythonhosted.org/packages/19/30/2a645fc9286b928675e43fa2a3a16fb7b6764aa78cc719dc82141e00f30b/orjson-3.11.8-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5774c1fdcc98b2259800b683b19599c133baeb11d60033e2095fd9d4667b82db", size = 124664, upload-time = "2026-03-31T16:16:05.837Z" },
{ url = "https://files.pythonhosted.org/packages/db/44/77b9a86d84a28d52ba3316d77737f6514e17118119ade3f91b639e859029/orjson-3.11.8-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7381c83dd3d4a6347e6635950aa448f54e7b8406a27c7ecb4a37e9f1ae08b", size = 129701, upload-time = "2026-03-31T16:16:07.407Z" },
{ url = "https://files.pythonhosted.org/packages/b3/ea/eff3d9bfe47e9bc6969c9181c58d9f71237f923f9c86a2d2f490cd898c82/orjson-3.11.8-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14439063aebcb92401c11afc68ee4e407258d2752e62d748b6942dad20d2a70d", size = 141202, upload-time = "2026-03-31T16:16:09.48Z" },
{ url = "https://files.pythonhosted.org/packages/52/c8/90d4b4c60c84d62068d0cf9e4d8f0a4e05e76971d133ac0c60d818d4db20/orjson-3.11.8-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa72e71977bff96567b0f500fc5bfd2fdf915f34052c782a4c6ebbdaa97aa858", size = 127194, upload-time = "2026-03-31T16:16:11.02Z" },
{ url = "https://files.pythonhosted.org/packages/8d/c7/ea9e08d1f0ba981adffb629811148b44774d935171e7b3d780ae43c4c254/orjson-3.11.8-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7679bc2f01bb0d219758f1a5f87bb7c8a81c0a186824a393b366876b4948e14f", size = 133639, upload-time = "2026-03-31T16:16:13.434Z" },
{ url = "https://files.pythonhosted.org/packages/6c/8c/ddbbfd6ba59453c8fc7fe1d0e5983895864e264c37481b2a791db635f046/orjson-3.11.8-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14f7b8fcb35ef403b42fa5ecfa4ed032332a91f3dc7368fbce4184d59e1eae0d", size = 141914, upload-time = "2026-03-31T16:16:14.955Z" },
{ url = "https://files.pythonhosted.org/packages/4e/31/dbfbefec9df060d34ef4962cd0afcb6fa7a9ec65884cb78f04a7859526c3/orjson-3.11.8-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:c2bdf7b2facc80b5e34f48a2d557727d5c5c57a8a450de122ae81fa26a81c1bc", size = 423800, upload-time = "2026-03-31T16:16:16.594Z" },
{ url = "https://files.pythonhosted.org/packages/87/cf/f74e9ae9803d4ab46b163494adba636c6d7ea955af5cc23b8aaa94cfd528/orjson-3.11.8-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ccd7ba1b0605813a0715171d39ec4c314cb97a9c85893c2c5c0c3a3729df38bf", size = 147837, upload-time = "2026-03-31T16:16:18.585Z" },
{ url = "https://files.pythonhosted.org/packages/64/e6/9214f017b5db85e84e68602792f742e5dc5249e963503d1b356bee611e01/orjson-3.11.8-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cdbc8c9c02463fef4d3c53a9ba3336d05496ec8e1f1c53326a1e4acc11f5c600", size = 136441, upload-time = "2026-03-31T16:16:20.151Z" },
{ url = "https://files.pythonhosted.org/packages/24/dd/3590348818f58f837a75fb969b04cdf187ae197e14d60b5e5a794a38b79d/orjson-3.11.8-cp314-cp314-win32.whl", hash = "sha256:0b57f67710a8cd459e4e54eb96d5f77f3624eba0c661ba19a525807e42eccade", size = 131983, upload-time = "2026-03-31T16:16:21.823Z" },
{ url = "https://files.pythonhosted.org/packages/3f/0f/b6cb692116e05d058f31ceee819c70f097fa9167c82f67fabe7516289abc/orjson-3.11.8-cp314-cp314-win_amd64.whl", hash = "sha256:735e2262363dcbe05c35e3a8869898022af78f89dde9e256924dc02e99fe69ca", size = 127396, upload-time = "2026-03-31T16:16:23.685Z" },
{ url = "https://files.pythonhosted.org/packages/c0/d1/facb5b5051fabb0ef9d26c6544d87ef19a939a9a001198655d0d891062dd/orjson-3.11.8-cp314-cp314-win_arm64.whl", hash = "sha256:6ccdea2c213cf9f3d9490cbd5d427693c870753df41e6cb375bd79bcbafc8817", size = 127330, upload-time = "2026-03-31T16:16:25.496Z" },
]
[[package]] [[package]]
name = "packaging" name = "packaging"
version = "26.0" version = "26.0"
@@ -1110,6 +1182,23 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl", hash = "sha256:ac8aca1c25c663a59b5b9140a549264a5badde2e057d79b8c772ae2920e32ff0", size = 9898444, upload-time = "2026-04-09T20:36:39.812Z" }, { url = "https://files.pythonhosted.org/packages/90/ad/cba91b3bcf04073e4d1655a5c1710ef3f457f56f7d1b79dcc3d72f4dd912/plotly-6.7.0-py3-none-any.whl", hash = "sha256:ac8aca1c25c663a59b5b9140a549264a5badde2e057d79b8c772ae2920e32ff0", size = 9898444, upload-time = "2026-04-09T20:36:39.812Z" },
] ]
[[package]]
name = "plotly-resampler"
version = "0.11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "dash" },
{ name = "numpy" },
{ name = "orjson" },
{ name = "pandas" },
{ name = "plotly" },
{ name = "tsdownsample" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0f/5c/e3990691542d789b8c07a5c021ace489b5b046d7ff66357c67536c535fe4/plotly_resampler-0.11.0.tar.gz", hash = "sha256:e3f9ceeb5749de9a85d39755f50711a7d6a28eb1b284da250251c8896ccc1cfd", size = 57400, upload-time = "2025-08-29T12:15:49.574Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/77/df/921eff232a2a8da7bdf84688b8cacfd9cef1bdc8fe695c547f7994804bee/plotly_resampler-0.11.0-py3-none-any.whl", hash = "sha256:5ce05a2b7eac5ec00379b219249ea583715077db9268fd4f4423715ce90cf653", size = 82684, upload-time = "2025-08-29T12:15:48.027Z" },
]
[[package]] [[package]]
name = "pluggy" name = "pluggy"
version = "1.6.0" version = "1.6.0"
@@ -1309,6 +1398,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
] ]
[[package]]
name = "pytz"
version = "2026.1.post1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" },
]
[[package]] [[package]]
name = "pyyaml" name = "pyyaml"
version = "6.0.3" version = "6.0.3"
@@ -1580,6 +1678,53 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" },
] ]
[[package]]
name = "tsdownsample"
version = "0.1.4.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/4b/bf/7590ae93ee6970876a79ab08602e4098a0c00db4b19f813d87935bb16607/tsdownsample-0.1.4.1.tar.gz", hash = "sha256:cc2e2fc0031a5fb75c0f5204b498e86eae0333bcc19da481c0859f1943690f3b", size = 555937, upload-time = "2025-01-29T13:13:25.185Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/35/57/1b0fb3bfd1ddd4bb97490e8fe5494b592028ec9fed98079d872ecb135226/tsdownsample-0.1.4.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d93a7de6e684e2f314444f75d2100e43dc76deed5e6cfd94bf6ecff0a2270383", size = 1266928, upload-time = "2025-01-29T13:10:56.332Z" },
{ url = "https://files.pythonhosted.org/packages/6c/9a/1b1327238914ffb5e8ce4001b744df0e36a903fdfe0796e0309e86cfe1cd/tsdownsample-0.1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c2569bffb94a24c781623ded653a1e50ef9f2ab102cc0be091add3dfd534338e", size = 1166982, upload-time = "2025-01-29T13:10:59.257Z" },
{ url = "https://files.pythonhosted.org/packages/ed/9e/ebdcc469bbe9e7d2decbc23cb835043c927acd7b8e8103cafced54e722cb/tsdownsample-0.1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab0d54355b292be0426ec97a36cf8ebdd22d69b0f9e08154d7a81eea30074d52", size = 1237143, upload-time = "2025-01-29T13:11:01.218Z" },
{ url = "https://files.pythonhosted.org/packages/31/a5/497f68a50e8e1fd7828af74e9534c591a36e8ab24a20814f47a1708115b2/tsdownsample-0.1.4.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:814eca271f2a8178ad5f614c13b6093e477fa905c61f00f292bcb77e152f2139", size = 1332403, upload-time = "2025-01-29T13:11:03.469Z" },
{ url = "https://files.pythonhosted.org/packages/b0/6e/b0239c632d110f0fde3289b1730543286397fb18c2a04572e74aef7fa51a/tsdownsample-0.1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97538b126a733ca88b00466580ac6f123e9a639c297058628791e05d9512369d", size = 1322541, upload-time = "2025-01-29T13:11:05.21Z" },
{ url = "https://files.pythonhosted.org/packages/6d/b7/83ec7fac8396fad3918bb71baf9286107b4d6335e06417fae244b1250a8a/tsdownsample-0.1.4.1-cp311-cp311-manylinux_2_24_armv7l.whl", hash = "sha256:1c6e1c2422b93ec2c3962e04fb10595709b894483918ef7977d2f84f37d6acf7", size = 1258659, upload-time = "2025-01-29T13:11:08.778Z" },
{ url = "https://files.pythonhosted.org/packages/0e/a3/8e9ff9f0191aece44581dc0b94a03ee3fe48cfb8650a32a1cec4948043e2/tsdownsample-0.1.4.1-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:8af543398045920bc3e7078eab627934069ba74d99a49d3dd62dda5c5c5c8499", size = 1269297, upload-time = "2025-01-29T13:11:11.044Z" },
{ url = "https://files.pythonhosted.org/packages/12/1b/e077b7c4b4813ac40c9b9e429138afcaf35037303207c3cf065746630d24/tsdownsample-0.1.4.1-cp311-cp311-manylinux_2_24_s390x.whl", hash = "sha256:036e783d81e773ddba377a45ac19489b365b6aac16e915ed31fe6f5260b588c8", size = 1448877, upload-time = "2025-01-29T13:11:15.36Z" },
{ url = "https://files.pythonhosted.org/packages/07/df/fef81e7b9f86d68f704824527bbc5d064059a94b03d46635cdfc8d42e534/tsdownsample-0.1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0afc76e88ad51a0887323823dd96cbe1a49300c543c9baa7cb93456c4bf69e11", size = 1398147, upload-time = "2025-01-29T13:11:17.866Z" },
{ url = "https://files.pythonhosted.org/packages/69/ce/779747b031404739977f5996260e7386298c983c3820c5f79fd4b28257b6/tsdownsample-0.1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46a109da21a3be8ef81cc3b988824309bbf1ea89e6385468911f46ee6f308d85", size = 1523919, upload-time = "2025-01-29T13:11:21.484Z" },
{ url = "https://files.pythonhosted.org/packages/cb/af/e847569c61bc58bd9ba41f24493d5159d8d42fdbd36a2e0039255196107a/tsdownsample-0.1.4.1-cp311-cp311-win32.whl", hash = "sha256:d6232c1c0e0e5cf49e57de2a860bb0c6e1279da4e1d360ab2bd456b25fef6a7d", size = 773506, upload-time = "2025-01-29T13:11:23.735Z" },
{ url = "https://files.pythonhosted.org/packages/19/aa/a3d611c83b2c647451ffbbbce3d589c377f9de990a616eda17c459a74d83/tsdownsample-0.1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:3378ef3ac19557191400697c8fb2586917fd42cc73099eab32a8a7874a48c417", size = 1034102, upload-time = "2025-01-29T13:11:27.735Z" },
{ url = "https://files.pythonhosted.org/packages/01/5c/1bc005378e4a7f0738c5ca093f7b2893eac932d44a59be6331b373119c88/tsdownsample-0.1.4.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:13aa99d40f0e25e49a28fd540fe13759cc19ade788013d46922a1cb60f475ff1", size = 1252185, upload-time = "2025-01-29T13:11:29.508Z" },
{ url = "https://files.pythonhosted.org/packages/3f/0e/4b12eeb6119389c83a7618e7bbfb9b3f6fc2ae6fa271d978982ebabede7f/tsdownsample-0.1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d177219c46d9499e28a9b637a6f2d87ccbeb82e1cf57d9a5e68c5fe85df33fe", size = 1166653, upload-time = "2025-01-29T13:11:32.104Z" },
{ url = "https://files.pythonhosted.org/packages/c9/3d/52e84bc71b1f7f497953563055c82f7a8bf975291f13f248f219f94cedc9/tsdownsample-0.1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fbed20c6dbbe029ae380cc01cc5ddc0db74aa65d57b26302ec4c3f92744efdd8", size = 1231341, upload-time = "2025-01-29T13:11:34.044Z" },
{ url = "https://files.pythonhosted.org/packages/a6/63/150984d8abef039ca48562cc8ef8dbf6a955aeba88a48dc9bb4f5e15f86a/tsdownsample-0.1.4.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d7b780d155e2ef47b36db09b9c166512c153c533fe22ff24d5b351cdab9a76b1", size = 1312409, upload-time = "2025-01-29T13:11:36.904Z" },
{ url = "https://files.pythonhosted.org/packages/5b/25/52552bfe812c872660875d82e7a142558d917e0c25196c8c7a6d54d6eb67/tsdownsample-0.1.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f941f9da83d436516546251ca4145e5748b7fa20f1f5f76d49bb924f2af87b35", size = 1325040, upload-time = "2025-01-29T13:11:41.191Z" },
{ url = "https://files.pythonhosted.org/packages/71/71/39181f51b37c864decbfb8f778b7ebf78f54048fb701fabb800fd62b0930/tsdownsample-0.1.4.1-cp312-cp312-manylinux_2_24_armv7l.whl", hash = "sha256:49ce60fa007e25b9a4889110a24a10ea96a0f568647d74e263cf7dd325c746d1", size = 1260784, upload-time = "2025-01-29T13:11:43.025Z" },
{ url = "https://files.pythonhosted.org/packages/76/fe/dc9efb88c8913149439b7ede45b6e4ca5cc3d585edded50c850f9a8a7abf/tsdownsample-0.1.4.1-cp312-cp312-manylinux_2_24_ppc64le.whl", hash = "sha256:656f7b1c27ba457fb2af2b87451925887bce4c7990a1cc43e8b58bcbe56ab729", size = 1286794, upload-time = "2025-01-29T13:11:45.768Z" },
{ url = "https://files.pythonhosted.org/packages/6c/fb/3546fbf09a6dddbf6362b252ee01cd9ee2a2695828991dae0611f51f19d0/tsdownsample-0.1.4.1-cp312-cp312-manylinux_2_24_s390x.whl", hash = "sha256:498c99c512bccc8cb77c823340b73ba2f0b07c392f0091f17ce172a426eeb007", size = 1444825, upload-time = "2025-01-29T13:11:49.202Z" },
{ url = "https://files.pythonhosted.org/packages/13/fb/39cd6067bb833a1d478560070002fa2737785a9dd8fc3fe231cafae5b0b7/tsdownsample-0.1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:24d6e29cc89fa1ab836df9c9590fd4f26088c661e3ed9f5add966c5b076df6fd", size = 1392808, upload-time = "2025-01-29T13:11:51.152Z" },
{ url = "https://files.pythonhosted.org/packages/4a/31/0db2e5a3ff868f6b09a1ba4e87d565c4552596e6f2c16e15c3fe29f6000b/tsdownsample-0.1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9afa84ec630081ce87060d2f0c294df084da2627ac2b623d36dfcfaef02005a", size = 1527173, upload-time = "2025-01-29T13:11:53.485Z" },
{ url = "https://files.pythonhosted.org/packages/70/cf/3a407a40ac6b9e08f6e59846b5a4b5a68797f0c604219deace02a5c9fe16/tsdownsample-0.1.4.1-cp312-cp312-win32.whl", hash = "sha256:128abd5c326f7a41436ec3f450c9ab128558498bf0abc67a760a94d2ac3a68b4", size = 767553, upload-time = "2025-01-29T13:11:55.966Z" },
{ url = "https://files.pythonhosted.org/packages/3e/6b/d80ef005f1ccbb5a325d4daf9e48d09f39ffcb20c65108f4eafb89b88510/tsdownsample-0.1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:9138b330c0172211bdd34fca24947fb35648784046f4d08e32f7fb97d775ad96", size = 1029860, upload-time = "2025-01-29T13:11:58.474Z" },
{ url = "https://files.pythonhosted.org/packages/c5/d8/b59fde996a4371e719a2cdb8bc16990beaed737b97de71e716a186c8546a/tsdownsample-0.1.4.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0a3dcac6f49f9543c5e12caab5b3c5ed78dafd76afeb70ea71453b5821f0fede", size = 1252057, upload-time = "2025-01-29T13:12:01.235Z" },
{ url = "https://files.pythonhosted.org/packages/8d/6f/3f8f18fa5f4b1b899c4a81b0eadb4ba22014adc70d22f2c9eff1ba3e0c80/tsdownsample-0.1.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2a3b690075a240478de70d512b50db165e7ef98b9e6f7d55e101146dbf3a09b1", size = 1166465, upload-time = "2025-01-29T13:12:02.866Z" },
{ url = "https://files.pythonhosted.org/packages/53/2c/253e00fa376ca3cc8b6eb42fee144be70824e80150742d9fae5323533421/tsdownsample-0.1.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263fd9259e8a6541d5c1e2744e90b38c8d6f98f343b03a19951fbf94fb10cb43", size = 1231028, upload-time = "2025-01-29T13:12:04.724Z" },
{ url = "https://files.pythonhosted.org/packages/88/be/0ff315a337d176737f6ffc05af4190f8cf9d344d71b64e2eb81bb2ca7347/tsdownsample-0.1.4.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fec09afa83d162a560fb902a60ec4f5b4cbcbbe3eb595c5c75bc28571dcf03c", size = 1311979, upload-time = "2025-01-29T13:12:06.664Z" },
{ url = "https://files.pythonhosted.org/packages/a4/31/7a572efe29e678c2bb172bf93f14a7fa14f4ecc421e36700a48447f99b96/tsdownsample-0.1.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92629086cf799f0364e8e70996de9e3724f738ab2ab323d9228fc1275c8c0adb", size = 1325055, upload-time = "2025-01-29T13:12:08.579Z" },
{ url = "https://files.pythonhosted.org/packages/c7/05/7c3e32662f6059b3c739c6528d3c1eece57ff3955168dc483a37a6a1b576/tsdownsample-0.1.4.1-cp313-cp313-manylinux_2_24_armv7l.whl", hash = "sha256:a917c885998c851eb1e6ca58e8f19a2f2f4e09dc6b6719bd1755bcc6247e98eb", size = 1259867, upload-time = "2025-01-29T13:12:11.362Z" },
{ url = "https://files.pythonhosted.org/packages/b7/e6/1e97e37cc4cec3ee1e5ad1934ea75d83e41a8258686adc7b2309bf32ca84/tsdownsample-0.1.4.1-cp313-cp313-manylinux_2_24_ppc64le.whl", hash = "sha256:e93179108e9721d637151f0645e3b4f50819446e4458156103472b35ffaa026d", size = 1286896, upload-time = "2025-01-29T13:12:13.502Z" },
{ url = "https://files.pythonhosted.org/packages/2e/bd/f93db320eb21660a443e849174423aa9324dc5cba016c096255bdc3c17a7/tsdownsample-0.1.4.1-cp313-cp313-manylinux_2_24_s390x.whl", hash = "sha256:26e74a6a9591bc52310ce16c316efe59a2443f7718188d459c5a2e5fb58883a9", size = 1445464, upload-time = "2025-01-29T13:12:15.415Z" },
{ url = "https://files.pythonhosted.org/packages/7f/0f/2711e5e24071b55fa653b13bbbbafad08f96832d92094c3c6f3368d986a3/tsdownsample-0.1.4.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c3953f484205b70e7a4e8473e2cc96a3ef6a24eb6600b89980f47447cbff4492", size = 1392698, upload-time = "2025-01-29T13:12:17.836Z" },
{ url = "https://files.pythonhosted.org/packages/07/5e/a7cce9d82017b5bbf3629acab08e58dafedd24f602b603c3c7f528bd8dd6/tsdownsample-0.1.4.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:fd5b786931d6500938942398e0aadb44046366ac28460ea008181ea75fb6dd52", size = 1527159, upload-time = "2025-01-29T13:12:19.687Z" },
{ url = "https://files.pythonhosted.org/packages/08/0c/49aac73ea3702bab30c6c4e29344ccfe3fcfbc20df739e3bbda4e571c258/tsdownsample-0.1.4.1-cp313-cp313-win32.whl", hash = "sha256:e7720aad79b6b76a1cdd20c2931e8e60e0465b437dc07c567d090493f39c36a5", size = 767855, upload-time = "2025-01-29T13:12:21.465Z" },
{ url = "https://files.pythonhosted.org/packages/ab/a3/8e4b211b81559fa6ae3bb98dc08bfa68e7b5e60e5ad394da12064951e8d0/tsdownsample-0.1.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:7985be2da94507bc507982c3f868b34b8bb70c84ab80ca53a9e8756ca91758c8", size = 1029209, upload-time = "2025-01-29T13:12:24.842Z" },
]
[[package]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.15.0" version = "4.15.0"