Plot arbitrary time-series data (non-calendar x-axis) into self-contained HTML using uPlot, with a pluggable parser system and expression-based derived traces.
- Loads one or more input files via auto-discovered parser plugins.
- Filters series by glob (
-F) or regex (-R) patterns. - Converts all data to base units and aligns traces to a common time grid.
- Evaluates derived traces from expressions (
-e "name=expr"), including chained expressions. - Renders interactive offline HTML plots with summary statistics and input/source metadata.
- Supports dual y-axes (up to two distinct y-units per plot).
- Sorts all traces by RMS (descending) for readability.
- Opens the result in your browser automatically.
- Python
>=3.14 uv
Install as a user tool (recommended):
uv tool install git+https://github.com/smprather/time-plotThen run anywhere:
time_plot --helpRender a single input file:
time_plot -f path/to/data.csvRender file with derived expressions:
time_plot -f sine.csv -e "sum=sine+sine" -e "rate=ddt(sum)"Running with no -f flags opens the built-in sine.csv example.
time_plot [OPTIONS] -f <files...> [-F <glob>] [-R <regex>] [-e <name=expr>] ...
-f <path...>: Load one or more source files. Repeatable. Shell globs work (e.g.,-f *.csv).-F <glob>: Glob filter on series names; binds to the preceding-fgroup. No glob chars → substring match (foo→*foo*).-R <regex>: Regex filter on series names; same binding semantics as-F. ANDed with-Fif both given.-e "name=expr": Define a named expression (see Expressions).-i, --case-insensitive: Apply-F/-Rfilters case-insensitively.
-o, --output FILE: Output HTML path. Defaults to/tmp/$USER/time_plot.html.--open-browser / --no-open-browser: Open the output in the default browser after writing (default:--open-browser).-l, --list-series: List available series for each file (with-F/-Rapplied) and exit.--rms-filter THRESHOLD: Exclude series whose RMS is below the threshold (same units as the data).--show-rms-histogram: Print an ASCII histogram of per-series RMS values and exit.--add-plugins-dir DIRECTORY: Additional plugin directory (repeatable; last given has highest precedence).--list-plugins: List all discovered plugins with short descriptions and exit.--plugin-help PLUGIN: Show detailed help for a named plugin and exit.--parser-options TEXT: Comma-separatedkey=valuepairs passed to parser plugins.
TIME_PLOT_EXTRA_PLUGINS_PATH: Colon-separated list of additional plugin directories.
time_plot -f signal.csv
time_plot -f data.ptiavg -F 'rtr_0*' -l
time_plot -f data.ptiavg -F 'rtr_0*' -e "total=sum(*|rtr_0*)"
time_plot -f a.ptiavg -F 'mac*' -f b.ptiavg -F 'cts*' -e "diff=mac|inst-cts|inst"Note: Positional arguments (without -f) are not accepted and will produce an error.
- Default output path:
/tmp/$USER/time_plot.html. - Plot HTML is self-contained (inlines
uPlotJS/CSS assets) — works offline. - Interactive chart with mousewheel zoom and closest-series highlighting.
- Summary statistics table (
Peak |y|,Average,RMS). - Source table showing input file paths or expression text per trace.
- All traces sorted by RMS (descending).
- Plugin ID:
voltage-or-current-vs-time - File type:
.csv - Two-column header:
time(<unit>),voltage(<unit>)ortime(<unit>),current(<unit>)
time(ns),voltage(mv)
0,0
1,0.5- Plugin ID:
spice-pwl - Parses SPICE netlists containing
pwlvoltage or current sources. - Supports line continuations with leading
+. - Each PWL source becomes one series.
- Parser option
naming_method:element_name(default, uses the SPICE element name, e.g.vclk) orpositive_node_name(uses the positive terminal name, e.g.clk).
time_plot -f spice_pwl.spi --parser-options naming_method=positive_node_nameSyntax: -e "name=<expression>"
Expressions are always named — the name is a simple Python identifier.
Series are referenced by pattern matching against loaded series names:
foo: matches any series whose name containsfoofile|foo: matches file containingfileand series containingfoo*|foo*: explicit glob syntax (any file, series starting withfoo)
+, -, *, /
Numeric constants are supported (e.g., -e "scaled=sine*2").
sum(*|pat)— aggregate matching series into a single summed traceaverage(x)— mean → scalar horizontal linerms(x)— RMS → scalar horizontal lineabs(x)— element-wise absolute valueddt(x)— finite-difference derivative (unit → unit/s)
Expressions can return:
- Series (
np.ndarray): a time-series trace - Scalar (
float): plotted as a horizontal line (e.g.,rms(x),average(x)) - Array-of-series (
list[np.ndarray]): expanded asname|1,name|2, ...
time_plot -f sine.csv -e "doubled=sine*2" -e "rate=ddt(doubled)"
time_plot -f data.ptiavg -F 'rtr_0*' -e "total=sum(*|rtr_0*)"+/-require matching units.*//produce composed unit strings (e.g.,v*v,v/s).ddt(x)→<unit>/s.
Plugins are discovered from time_plot/plugins/ in deterministic sorted order. The first plugin whose identify(path) returns True handles the file.
A plugin must provide:
identify(path: Path) -> boolparse(path: Path, options: dict[str, str], selected: list[str] | None) -> list[SeriesData]
Optional:
plugin_name() -> strlist_series(path: Path, options: dict[str, str]) -> list[str]— efficient pre-load series enumerationshort_description() -> str— one-line summary for--list-pluginslong_description() -> str— detailed help for--plugin-help
Plugin search order (highest precedence first):
--add-plugins-dirflags (last given = first checked)TIME_PLOT_EXTRA_PLUGINS_PATHentries- Built-in
time_plot/plugins/directory
git clone https://github.com/smprather/time-plot
cd time-plot
uv sync --group devRun tests:
uv run pytest -qLint and type check:
uv run ruff check .
uv run ty checkRegenerate example data:
uv run python scripts/generate_example_data.pyValidation:
uv run pytest -q
uv run time_plot --no-open-browser -f time_plot/example_data/sine.csv
uv run time_plot --no-open-browser -f time_plot/example_data/sine.csv -e "sum=sine+sine" -e "r=ddt(sum)"time_plot/: CLI, processing, plotting, units, plugin system, expression parser.time_plot/plugins/: parser plugins.time_plot/example_data/: bundled sample files.time_plot/vendor/: vendored third-party code (ascii-histogram).scripts/: developer utilities.tests/: automated tests.doc/: architecture and plugin docs.
Input file not found: check the path; generate sample files withuv run python scripts/generate_example_data.py.No plugin recognized file: check file format and suffix against supported plugins.Series reference matched no loaded series: verify the series name pattern matches loaded data. Use-lto list available series.At most two distinct y-axis units are supported: split traces into separatetime_plotinvocations.Unexpected argument: positional arguments are not supported. Use-fto specify source files.
MIT. See LICENSE.