lerobot/robot-learning-tutorial
508
1import plotly.graph_objects as go2import plotly.io as pio3import numpy as np4import datetime as dt5import os6 7"""8Calendar-like heatmap (GitHub-style) over the last 52 weeks.9Minimal, responsive, transparent background; suitable for Distill.10"""11 12# Parameters13NUM_WEEKS = 5214DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]15 16# Build dates matrix (7 rows x NUM_WEEKS columns)17today = dt.date.today()18# Align to start of current week (Monday)19start = today - dt.timedelta(days=(today.weekday())) # Monday of current week20weeks = [start - dt.timedelta(weeks=w) for w in range(NUM_WEEKS-1, -1, -1)]21dates = [[weeks[c] + dt.timedelta(days=r) for c in range(NUM_WEEKS)] for r in range(7)]22 23# Generate values (synthetic) — smooth seasonal pattern + noise24def gen_value(d: dt.date) -> float:25 day_of_year = d.timetuple().tm_yday26 base = 0.5 + 0.45 * np.sin(2 * np.pi * (day_of_year / 365.0))27 noise = np.random.default_rng(hash(d) % 2**32).uniform(-0.15, 0.15)28 return max(0.0, min(1.0, base + noise))29 30z = [[gen_value(d) for d in row] for row in dates]31custom = [[d.isoformat() for d in row] for row in dates]32 33# Colors aligned with other charts (slate / blue / gray)34colorscale = [35 [0.00, "#e5e7eb"], # light gray background for low36 [0.40, "#64748b"], # slate-50037 [0.75, "#2563eb"], # blue-60038 [1.00, "#4b5563"], # gray-600 (high end accent)39]40 41fig = go.Figure(42 data=go.Heatmap(43 z=z,44 x=[w.isoformat() for w in weeks],45 y=DAYS,46 colorscale=colorscale,47 showscale=False,48 hovertemplate="Date: %{customdata}<br>Value: %{z:.2f}<extra></extra>",49 customdata=custom,50 xgap=2,51 ygap=2,52 )53)54 55fig.update_layout(56 autosize=True,57 paper_bgcolor="rgba(0,0,0,0)",58 plot_bgcolor="rgba(0,0,0,0)",59 margin=dict(l=28, r=12, t=8, b=28),60 xaxis=dict(61 showgrid=False,62 zeroline=False,63 showline=False,64 ticks="",65 showticklabels=False,66 fixedrange=True,67 ),68 yaxis=dict(69 showgrid=False,70 zeroline=False,71 showline=False,72 ticks="",73 tickfont=dict(size=12, color="rgba(0,0,0,0.65)"),74 fixedrange=True,75 ),76)77 78post_script = """79(function(){80 var plots = document.querySelectorAll('.js-plotly-plot');81 plots.forEach(function(gd){82 function round(){83 try {84 var root = gd && gd.parentNode ? gd.parentNode : document;85 var rects = root.querySelectorAll('.hoverlayer .hovertext rect');86 rects.forEach(function(r){ r.setAttribute('rx', 8); r.setAttribute('ry', 8); });87 } catch(e) {}88 }89 if (gd && gd.on){90 gd.on('plotly_hover', round);91 gd.on('plotly_unhover', round);92 gd.on('plotly_relayout', round);93 }94 setTimeout(round, 0);95 });96})();97"""98 99html = pio.to_html(100 fig,101 include_plotlyjs=False,102 full_html=False,103 post_script=post_script,104 config={105 "displayModeBar": False,106 "responsive": True,107 "scrollZoom": False,108 "doubleClick": False,109 "modeBarButtonsToRemove": [110 "zoom2d", "pan2d", "select2d", "lasso2d",111 "zoomIn2d", "zoomOut2d", "autoScale2d", "resetScale2d",112 "toggleSpikelines"113 ],114 },115)116 117fig.write_html("../app/src/content/fragments/heatmap.html", 118 include_plotlyjs=False, 119 full_html=False, 120 config={121 'displayModeBar': False,122 'responsive': True, 123 'scrollZoom': False,124 })125 126 