Compare time series and datasets with explainable structural similarity.
EchoTime is an explainable time-series similarity package for humans and agents. It is built for the moment when a raw distance score is not enough: compare trajectories, compare datasets at the structural level, and hand the result to another person or another agent.
What it is: EchoTime compares time series and time-series datasets, explains why they match or differ, and emits compact JSON plus shareable HTML reports.
What it is not: a forecasting library, a classifier library, a fastest-possible DTW engine, or a motif-mining toolkit.
- Package name:
echotime - Core promise: EchoTime compares time series and time-series datasets, explains why they match or differ, and emits compact JSON plus shareable HTML reports.
- Best for: analog search, regime comparison, irregular longitudinal data, and dataset-level similarity handoff
- Primary outputs: plain-English summaries, shareable HTML reports, and compact agent-ready JSON
- Live docs and homepage: https://zipengwu365.github.io/EchoTime/
- Repository: https://github.com/ZipengWu365/EchoTime
pip install echotime
python -c "import numpy as np; from echotime import compare_series; x=np.sin(np.linspace(0,8*np.pi,128)); y=np.sin(np.linspace(0,8*np.pi,128)+0.2); print(compare_series(x,y).to_summary_card_markdown())"Expected output starts like this:
# EchoTime similarity summary
overall similarity: ...
top components: shape similarity, trend similarity, spectral similarity
If you already have a file, start by matching it to one of these shapes:
| your data | what EchoTime expects | first API |
|---|---|---|
| one numeric series | a 1D array or one numeric pandas column | profile_series(...) |
| wide table | one timestamp column plus one or more numeric columns |
profile_dataset(df, domain=...) |
| irregular long table | subject, timestamp, channel, value columns |
profile_dataset(df, domain=...) |
| two series to compare | two arrays or two numeric columns | compare_series(left, right) |
Tabular inputs are auto-detected from names such as timestamp / time, value / measurement, channel / sensor / metric, and subject / patient / participant. If your file uses different names, rename them first. Sparse event tables can also use timestamp, event_type, value, and optional subject.
from pathlib import Path
import pandas as pd
from echotime import profile_series
df = pd.read_csv("my_signal.csv")
series = pd.to_numeric(df["load_kw"], errors="coerce").dropna().to_numpy()
profile = profile_series(series, domain="energy")
print(profile.to_summary_card_markdown())
Path("my_signal_report.html").write_text(profile.to_html_report(), encoding="utf-8")from pathlib import Path
import pandas as pd
from echotime import profile_dataset
df = pd.read_csv("my_timeseries.csv")
df = df.rename(columns={"date": "timestamp"}) # only needed if your time column has a different name
profile = profile_dataset(df, domain="energy")
print(profile.to_summary_card_markdown())
Path("my_dataset_report.html").write_text(profile.to_html_report(), encoding="utf-8")All remaining numeric columns are treated as channels or measurements in the same dataset.
from pathlib import Path
import pandas as pd
from echotime import profile_dataset
df = pd.read_csv("patient_vitals.csv")
df = df.rename(columns={
"patient_id": "subject",
"charttime": "timestamp",
"lab_name": "channel",
"lab_value": "value",
})
profile = profile_dataset(df, domain="clinical")
print(profile.to_summary_card_markdown())
Path("patient_vitals_report.html").write_text(profile.to_html_report(), encoding="utf-8")Each (subject, channel) stream can stay irregular; EchoTime keeps the gaps instead of forcing a fake regular grid.
from pathlib import Path
import pandas as pd
from echotime import compare_series
df = pd.read_csv("load_by_region.csv")
report = compare_series(df["north_load_mw"], df["south_load_mw"])
print(report.to_summary_card_markdown())
Path("north_vs_south_similarity.html").write_text(report.to_html_report(), encoding="utf-8")If you want a file you can edit in place, start with examples/integrations/pandas_notebook_template.py.
Because many time-series teams do not just need a distance score. They need to know whether two curves are similar enough to compare, whether two datasets are structurally similar enough to transfer intuition, and why the package thinks that.
- plain-English similarity summaries
- time-series and dataset-level structural comparison
- shareable HTML reports with visuals
- rolling similarity and component breakdowns
- compact agent JSON with stable envelopes
- starter datasets, notebooks, and GitHub Pages-ready similarity demos
- a local live demo server for pasted arrays and quick comparisons
- compatibility presets and environment doctor guidance for mixed scientific stacks
The extracted elastic similarity functions now support two operating modes:
mode="exact"keeps the full scoring behavior and remains the default for final reporting.mode="fast"is for screening and shortlist workflows where speed matters more than exact-path fidelity.edr_distance,erp_distance, andtwed_distancealso acceptwindowso you can bound the dynamic-programming path when needed.- A practical pattern is: run
mode="fast"across many candidate pairs, then rerun only the shortlist withmode="exact"before you publish or defend the result. - If you already know the alignment should stay local, pass
window=...so the elastic path does not wander across the whole grid.
-
Static playground - Preview similarity reports, visuals, and flagship cases without installing Python or starting a server.
-
Colab quickstart - Open a starter notebook in a hosted notebook environment.
-
uvx CLI - Run the CLI in an isolated ephemeral environment when packaging allows it.
-
Local demo server - Run a tiny local web app that turns pasted values into similarity verdicts on your own machine.
-
GitHub Pages-ready showcase - open
docs/index.htmlor publish the included Pages bundle. -
Local live demo server - run
echotime-demo --open-browserfor real similarity analysis on pasted arrays. -
Local static preview - open
playground.htmllocally and switch between flagship similarity cases. -
Compatibility presets - export a constraints file before installing into a mixed scientific stack.
- Single-column CSV -> similarity-ready signal - Show that one numeric column is enough to try the package.
- Timestamps + missingness -> why irregularity matters - Show why explicit timestamps and gaps can change a similarity verdict.
- Two curves -> similarity verdict - Show the simplest possible similarity workflow without ontology jargon.
- Inflation + search interest -> regime similarity - Show a macro-adjacent beginner case without assuming a finance background.
- Single sensor drift -> structural watchouts - Show how slow drift changes what a meaningful analog looks like in engineering data.
- Daily survey sentiment -> irregularity and burstiness - Show how sparse observational signals differ from smooth telemetry.
- OpenClaw-style GitHub breakout analogs - Ask whether a new repo looks like a durable breakout or a short viral spike.
- BTC vs gold vs oil under shocks - Ask which assets become more similar during macro or geopolitical stress.
- Heatwave vs grid load - Ask which load curves drift or switch regime under extreme weather.
import numpy as np
from echotime import compare_series, explain_similarity, ts_compare
x = np.sin(np.linspace(0, 8*np.pi, 128))
y = np.sin(np.linspace(0, 8*np.pi, 128) + 0.2)
print(compare_series(x, y).to_summary_card_markdown())
print(explain_similarity(x, y))
print(ts_compare(x, y))- Weekly website traffic HTML report
- Irregular patient vitals HTML report
- GitHub breakout similarity HTML report
- BTC vs gold similarity HTML report
- Energy load vs heatwave HTML report
- Wearable recovery HTML report
- Maintainer: Zipeng Wu
- Email: zxw365@student.bham.ac.uk
- Affiliation: The University of Birmingham
- Repository: https://github.com/ZipengWu365/EchoTime
- Documentation: https://zipengwu365.github.io/EchoTime/
- Starter datasets
- Compatibility guide
- Environment doctor
- Example gallery
- Similarity method atlas
- Notebooks
- Integration templates
- Decision stories
- Static playground
- Local live demo guide
- Routing contracts
This version exposes compare-first stable wrappers:
ts_profilets_comparets_route
All wrappers ship an explicit input contract and a stable success/error envelope. They are meant to be the smallest useful tool surface for function calling, MCP, and multi-agent handoff.
See:
- Zero-install guide
- GitHub Pages deployment
- Playground guide
- Local live demo guide
- PyPI long description
Use EchoTime first when you need explainable structural similarity and comparison.
Pair it with other libraries when you move into:
- feature extraction (
tsfresh) - forecasting (
Darts,sktime,aeon,Kats) - learning pipelines (
aeon,sktime,tslearn) - DTW alignment (
DTAIDistance) - motif / discord mining (
STUMPY)
- Primary: series similarity, dataset similarity, similarity reports, agent context
- Complementary: structural profiling, benchmark curation, modelling handoff
- Out of scope: estimator training, backtesting, low-level DTW paths, subsequence mining
- pandas / parquet pipelines
- xarray-style data
- Jupyter notebooks
- CLI batch workflows
- OpenAI function calling
- MCP tool wrappers
- GitHub Pages static showcase
- LICENSE
- CONTRIBUTING.md
- CODE_OF_CONDUCT.md
- SECURITY.md
- CITATION.cff
- beta-level agent schemas
- beginner and flagship notebooks
- Pages-ready demo bundle
- social cards and GIFs
- reproducible decision-impact benchmark
MIT.
