Tatopenn's picture
Sync dashboard_core/ from v8.1.33
d2486ac verified
Raw
History Blame Contribute Delete
10.3 kB
"""
Shared matplotlib styling primitives: palette, axis styling, and the
time-series plot helpers used across the panel builders.
Split out of the former monolithic dashboard_core.py (Phase 1 of the
dashboard refactor). _series_plot/_series_enhanced/_energy_enhanced's
former redundancy was unified into a single _series_plot (Phase 2) --
same visual output, one parameterized function instead of three.
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.colors import LinearSegmentedColormap
C = dict(
bg = '#03050e',
panel = '#070b18',
grid = '#0f1628',
border = '#18243c',
title = '#e2eaf8',
label = '#4a6080',
tick = '#2e4a6a',
prob = '#38bdf8',
energy = '#00e0ff',
entropy = '#f43f7a',
purity = '#4ade80',
grad = '#fbbf24',
noise = '#fb923c',
theta = '#a78bfa',
dom = '#ffffff',
accent = '#00ff9d',
warn = '#ff6b35',
)
MONO = {'fontfamily': 'monospace'}
FILL_A = 0.08
_cmap_prob = LinearSegmentedColormap.from_list(
'tureq_prob', ['#0a1f3d', '#38bdf8', '#f43f7a'], N=256
)
BG_ART = '#030305'
PANEL_ART = '#07070a'
CYAN_N = '#00f3ff'
PINK_N = '#ff0055'
PURP_N = '#7a00ff'
GOLD_N = '#ffaa00'
# Repeated across build_panel_fisica/vqe_results/md_results/performance's
# plt.figure(facecolor=...) -- distinct from C['bg'] (a different literal
# in the original), centralized here (Phase 2) as one named constant
# instead of 5 duplicated string literals in panels.py.
FIG_BG_DARK = '#010409'
def _ax_style(ax, title='', xlabel='', ylabel='', spine_alpha=0.6):
ax.set_facecolor(C['panel'])
for sp in ax.spines.values():
sp.set_edgecolor(C['border'])
sp.set_linewidth(0.7)
sp.set_alpha(spine_alpha)
ax.tick_params(colors=C['tick'], which='both', length=3, width=0.5, labelsize=7.5)
ax.xaxis.label.set_color(C['label']); ax.xaxis.label.set_fontsize(8)
ax.yaxis.label.set_color(C['label']); ax.yaxis.label.set_fontsize(8)
ax.grid(True, ls='--', lw=0.30, alpha=0.25, color=C['grid'])
if title:
ax.set_title(title, color=C['title'], fontsize=9.5, fontweight='bold',
pad=6, loc='left', **MONO)
if xlabel: ax.set_xlabel(xlabel, **MONO)
if ylabel: ax.set_ylabel(ylabel, **MONO)
def _fill(ax, x, y, col):
ax.fill_between(x, y, alpha=FILL_A, color=col)
def _rolling(y, win):
return pd.Series(y).rolling(win, center=True, min_periods=1).mean().values
def _badge(ax, text, color):
"""Top-right value badge."""
ax.text(0.98, 0.97, text,
transform=ax.transAxes, ha='right', va='top',
fontsize=7.5, color=color, **MONO,
bbox=dict(boxstyle='round,pad=0.25',
facecolor=C['bg'], edgecolor=C['border'], alpha=0.72))
def _series_plot(ax, df, col, color, title, xlabel, ylabel, *,
show_raw=True, badge=False, badge_fmt='{:.4g}',
ref_line=None, detect_plateau=False,
mark_convergence=False):
"""Unified time-series: raw line + fill + rolling mean + last-value
annotation, with optional badge / reference-line / barren-plateau-span /
convergence-marker overlays.
Unifies what used to be three near-duplicate functions (_series_plot,
which this absorbs, plus _series_enhanced and _energy_enhanced, Phase 2
of the dashboard refactor) into one parameterized function -- same
visual output as each of the three original call shapes:
- old _series_plot(...) == _series_plot(...) (defaults)
- old _series_enhanced(..., ref_line=X) == _series_plot(..., badge=True, ref_line=X)
- old _energy_enhanced(ax, df) == _series_plot(ax, df, 'VQE_Energy',
C['energy'], 'VQE Energy', 'Epoch',
'E (Ha)', badge=True,
badge_fmt='Eₙ={:.4g} Ha',
mark_convergence=True)
"""
_ax_style(ax, title, xlabel, ylabel)
if df.empty or col not in df.columns:
ax.axis('off')
ax.text(0.5, 0.5, f'[ {col} — no data ]',
ha='center', va='center', color=C['label'],
fontsize=8.5, transform=ax.transAxes, **MONO)
return
x = df.index.values
y = df[col].values
if show_raw:
ax.plot(x, y, color=color, lw=1.4, alpha=0.7)
_fill(ax, x, y, color)
win = max(3, len(y) // 15)
rm = _rolling(y, win)
ax.plot(x, rm, color=C['title'], lw=1.1, alpha=0.6, ls='--',
label='rolling mean')
ax.annotate(f'{y[-1]:.4g}',
xy=(x[-1], y[-1]), xytext=(-4, 6),
textcoords='offset points',
color=color, fontsize=7.5, fontweight='bold',
ha='right', **MONO)
x_f = df.index.to_numpy(dtype=float)
if badge:
_badge(ax, badge_fmt.format(y[-1]), color)
if ref_line is not None:
ax.axhline(ref_line, color=color, lw=0.6, ls='--', alpha=0.28)
if detect_plateau:
_thr = 0.01 * np.abs(y).max() if np.abs(y).max() > 0 else 1e-9
_bp = np.abs(y) < _thr
if _bp.sum() > 3:
_edges = np.where(np.diff(_bp.astype(int)))[0]
if len(_edges) >= 2:
ax.axvspan(x_f[_edges[0]], x_f[_edges[1]],
alpha=0.11, color=C['warn'])
ax.text(
(x_f[_edges[0]] + x_f[_edges[1]]) / 2,
y.max() * 0.88,
'plateau', ha='center', fontsize=6.5,
color=C['warn'], alpha=0.80, **MONO,
)
if mark_convergence and len(y) > 2:
_conv = int(np.argmin(np.gradient(y)))
ax.axvline(x_f[_conv], color=C['warn'], lw=0.8, ls=':', alpha=0.55)
ax.annotate(
f'∇min@{_conv}',
xy=(x_f[_conv], y[_conv]),
xytext=(6, -14), textcoords='offset points',
color=C['warn'], fontsize=7.0,
arrowprops=dict(arrowstyle='-', color=C['warn'], lw=0.5),
**MONO,
)
def _interp_colour(c1_hex, c2_hex, t):
t = float(np.clip(t, 0, 1))
def h(s): return [int(s.lstrip('#')[i:i+2], 16) / 255 for i in (0, 2, 4)]
r1, g1, b1 = h(c1_hex)
r2, g2, b2 = h(c2_hex)
to_hex = lambda v: f'{int(v*255):02x}'
return f'#{to_hex(r1+(r2-r1)*t)}{to_hex(g1+(g2-g1)*t)}{to_hex(b1+(b2-b1)*t)}'
def _noise_profile_plot(ax, noise_model, noise_p, n_qubits,
prob_ideal, prob_noisy=None):
_ax_style(ax, 'Noise Analysis', '', '')
ax.set_xlim(0, 1); ax.set_ylim(-0.08, 1.08)
ax.axis('off')
model_col = C['warn'] if noise_model != 'ideal' else C['accent']
ax.text(0.5, 0.97, noise_model.upper().replace('_', ' '),
ha='center', va='top', color=model_col,
fontsize=16, fontweight='bold', transform=ax.transAxes, **MONO)
bar_y = 0.80
ax.add_patch(mpatches.FancyBboxPatch(
(0.05, bar_y - 0.025), 0.90, 0.05,
boxstyle='round,pad=0.005',
facecolor=C['grid'], edgecolor=C['border'], lw=0.8,
transform=ax.transAxes, zorder=2))
fill_w = 0.90 * min(noise_p / 0.10, 1.0)
if fill_w > 0:
fill_col = _interp_colour('#00ff9d', '#ff6b35', noise_p / 0.10)
ax.add_patch(mpatches.FancyBboxPatch(
(0.05, bar_y - 0.025), fill_w, 0.05,
boxstyle='round,pad=0.005',
facecolor=fill_col, edgecolor='none',
transform=ax.transAxes, zorder=3))
ax.text(0.5, bar_y + 0.06, f'p = {noise_p:.4f}',
ha='center', va='bottom', color=C['title'],
fontsize=11, fontweight='bold', transform=ax.transAxes, **MONO)
ax.text(0.05, bar_y - 0.07, '0', ha='left', va='top',
color=C['label'], fontsize=7.5, transform=ax.transAxes, **MONO)
ax.text(0.95, bar_y - 0.07, '0.10', ha='right', va='top',
color=C['label'], fontsize=7.5, transform=ax.transAxes, **MONO)
if prob_noisy is not None and noise_model != 'ideal':
fid_bc = float(np.sum(np.sqrt(np.maximum(prob_ideal, 0) *
np.maximum(prob_noisy, 0))))
tvd = float(0.5 * np.sum(np.abs(prob_ideal - prob_noisy)))
rows = [
('Bhattacharyya Fidelity', f'{fid_bc:.6f}', C['purity']),
('Total Variation Distance', f'{tvd:.6f}', C['entropy']),
('Noise Channel', noise_model.replace('_', ' '), C['noise']),
]
else:
rows = [
('Channel', 'ideal — no noise applied', C['accent']),
('Fidelity', '1.000000', C['purity']),
('TVD', '0.000000', C['label']),
]
for j, (k, v, col) in enumerate(rows):
yy = 0.58 - j * 0.14
ax.text(0.03, yy, k, ha='left', va='center', color=C['label'],
fontsize=8, transform=ax.transAxes, **MONO)
ax.text(0.97, yy, v, ha='right', va='center', color=col,
fontsize=8.5, fontweight='bold',
transform=ax.transAxes, **MONO)
ax.axhline(yy - 0.05, xmin=0.01, xmax=0.99, color=C['grid'], lw=0.35)
if noise_model in ('ideal', 'depolarizing'):
ins = ax.inset_axes([0.04, 0.04, 0.92, 0.26])
ins.set_facecolor(C['panel'])
for sp in ins.spines.values():
sp.set_edgecolor(C['border']); sp.set_linewidth(0.5)
ps = np.linspace(0, 0.1, 200)
d = 2 ** n_qubits
fid_curve = ((1.0 - ps * (d - 1) / d) ** n_qubits).clip(0, 1)
ins.plot(ps, fid_curve, color=C['purity'], lw=1.2)
ins.axvline(noise_p, color=C['warn'], lw=0.9, ls='--', alpha=0.8)
ins.fill_between(ps, fid_curve, alpha=0.07, color=C['purity'])
ins.set_xlim(0, 0.10); ins.set_ylim(0, 1.05)
ins.tick_params(colors=C['tick'], labelsize=6.5, length=2)
ins.set_xlabel('p', color=C['label'], fontsize=7, **MONO)
ins.set_ylabel('F(p)', color=C['label'], fontsize=7, **MONO)
ins.set_title('Theoretical Fidelity Curve',
color=C['label'], fontsize=7, pad=2, **MONO)
ins.grid(True, ls=':', lw=0.3, alpha=0.25, color=C['grid'])