Note
Go to the end to download the full example code
Compare dv/v from MWCS, Stretching, and WCT
Plots the network-level dv/v time series produced by the three available methods side by side — MWCS dt/t, Stretching, and Wavelet Cross-Transform (WCT) — so their agreement and systematic differences can be assessed at a glance.
This example is designed to run after the full MSNoise test workflow (all
compute steps completed). Each (components, mov_stack) combination for
which at least one method has results produces its own figure. Methods that
were not computed are silently skipped.
Each figure has two panels:
Top — dv/v time series for each available method, with a ±1σ shaded band.
Bottom — residuals relative to the first available method (e.g. MWCS − Stretching, MWCS − WCT) to highlight systematic offsets.
Traceback (most recent call last):
File "D:\PythonForSource\MSNoise_Stack\MSNoise\examples\plot_dvv_comparison.py", line 51, in <module>
db = connect()
File "D:\PythonForSource\MSNoise_Stack\MSNoise\msnoise\core\db.py", line 104, in connect
engine = get_engine(inifile)
File "D:\PythonForSource\MSNoise_Stack\MSNoise\msnoise\core\db.py", line 67, in get_engine
dbini = read_db_inifile(inifile)
File "D:\PythonForSource\MSNoise_Stack\MSNoise\msnoise\core\db.py", line 156, in read_db_inifile
raise DBConfigNotFoundError(
msnoise.DBConfigNotFoundError: No db.ini file in this directory, please run 'msnoise db init' in this folder to initialize it as an MSNoise project folder.
import os
if "SPHINX_DOC_BUILD" in os.environ:
if "MSNOISE_DOC" in os.environ:
os.chdir(os.environ["MSNOISE_DOC"])
import matplotlib
matplotlib.use("agg")
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import pandas as pd
from msnoise.api import connect
from msnoise.results import MSNoiseResult
from msnoise.core.config import lineage_to_plot_tag, build_plot_outfile
# ── palette & style ──────────────────────────────────────────────────────────
plt.style.use("ggplot")
METHOD_STYLE = {
"mwcs_dtt_dvv": dict(color="#1f77b4", label="MWCS", lw=1.8, zorder=3),
"stretching_dvv": dict(color="#d62728", label="Stretching", lw=1.8, zorder=2),
"wavelet_dtt_dvv": dict(color="#2ca02c", label="WCT", lw=1.8, zorder=1),
}
# ── connect ───────────────────────────────────────────────────────────────────
db = connect()
# ── discover available DVV results ───────────────────────────────────────────
results_by_method = {}
for category in ("mwcs_dtt_dvv", "stretching_dvv", "wavelet_dtt_dvv"):
found = MSNoiseResult.list(db, category)
if found:
results_by_method[category] = found[0]
tag = lineage_to_plot_tag(found[0].lineage_names)
print(f" {category}: {tag}")
else:
print(f" {category}: not computed — skipping")
if not results_by_method:
print("No DVV results found — run the full pipeline first.")
db.close()
raise SystemExit(0)
PAIR_TYPE = "CC"
# ── collect all (components, mov_stack) combinations across methods ───────────
all_keys = set()
raw = {}
for category, result in results_by_method.items():
data = result.get_dvv(pair_type=PAIR_TYPE)
filtered = {(comp, ms): ds
for (pt, comp, ms), ds in data.items()
if pt == PAIR_TYPE}
raw[category] = filtered
all_keys |= set(filtered.keys())
if not all_keys:
print("No CC DVV data found.")
db.close()
raise SystemExit(0)
# ── one figure per (components, mov_stack) ────────────────────────────────────
for comp, ms in sorted(all_keys):
ms_label = f"{ms[0]}-{ms[1]}"
title = f"dv/v comparison | comp={comp} | mov_stack={ms_label}"
# Collect time series (converted to %)
series = {}
for category in ("mwcs_dtt_dvv", "stretching_dvv", "wavelet_dtt_dvv"):
if category not in raw or (comp, ms) not in raw[category]:
continue
ds = raw[category][(comp, ms)]
if "mean" not in ds:
continue
mean_da = ds["mean"]
std_da = ds.get("std", ds.get("weighted_std", None))
times = pd.DatetimeIndex(mean_da.coords["times"].values)
mean_s = pd.Series(mean_da.values * 100.0, index=times, name=category)
std_s = (pd.Series(std_da.values * 100.0, index=times)
if std_da is not None else None)
series[category] = (mean_s, std_s)
if not series:
print(f" No data for comp={comp}, mov_stack={ms_label} — skipping")
continue
# ── figure: 2 rows ────────────────────────────────────────────────────────
fig = plt.figure(figsize=(12, 7))
gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1], hspace=0.08)
ax_dvv = fig.add_subplot(gs[0])
ax_res = fig.add_subplot(gs[1], sharex=ax_dvv)
# Top panel
reference_s = None
for category, (mean_s, std_s) in series.items():
style = METHOD_STYLE[category]
ax_dvv.plot(mean_s.index, mean_s.values,
color=style["color"], lw=style["lw"],
label=style["label"], zorder=style["zorder"])
if std_s is not None:
ax_dvv.fill_between(mean_s.index,
mean_s.values - std_s.values,
mean_s.values + std_s.values,
color=style["color"], alpha=0.15,
zorder=style["zorder"] - 1)
if reference_s is None:
reference_s = mean_s
ax_dvv.axhline(0, color="k", lw=0.8, ls="--", alpha=0.5)
ax_dvv.set_ylabel("dv/v (%)")
ax_dvv.set_title(title)
ax_dvv.legend(loc="upper right", framealpha=0.9)
ax_dvv.tick_params(labelbottom=False)
# Bottom panel — residuals vs first method
ref_label = METHOD_STYLE[next(iter(series))]["label"]
has_residual = False
for category, (mean_s, _) in series.items():
if mean_s is reference_s:
continue
style = METHOD_STYLE[category]
common = reference_s.index.intersection(mean_s.index)
if len(common) == 0:
continue
resid = reference_s.loc[common] - mean_s.loc[common]
ax_res.plot(resid.index, resid.values,
color=style["color"], lw=1.4,
label=f"{ref_label} \u2212 {style['label']}",
zorder=style["zorder"])
has_residual = True
ax_res.axhline(0, color="k", lw=0.8, ls="--", alpha=0.5)
ax_res.set_ylabel("Residual (%)")
ax_res.set_xlabel("Date")
if has_residual:
ax_res.legend(loc="upper right", framealpha=0.9, fontsize=8)
fig.autofmt_xdate()
# ── save ──────────────────────────────────────────────────────────────────
first_result = next(iter(results_by_method.values()))
outfile = build_plot_outfile(
"?.png", "dvv_comparison",
first_result.lineage_names,
components=comp,
mov_stack=ms,
)
print(f" Saving: {outfile}")
plt.savefig(outfile, dpi=150, bbox_inches="tight")
plt.show()
db.close()
# EOF
Total running time of the script: ( 0 minutes 0.009 seconds)