{# The chart macros. Every SVG on /progress comes through here, and every coordinate in it was computed by core/chart.py โ€” this file prints, it does not calculate. That split is the whole point: the geometry has tests (tests/test_chart.py), and a Jinja loop that builds polyline points out of `{% set %}` list mutation does not. ๐Ÿ”ด NO LIBRARY, AND NOT AS A SACRIFICE. The app's CSP is `default-src 'self'` and nothing on this box is fetched from anywhere. A line chart is a list of coordinates. ๐Ÿ”ด THE GAP RULE IS VISIBLE HERE: a series renders as SEVERAL polylines, one per run of consecutive measured points, plus dots for the runs of one. A single polyline through the lot would draw a confident line across a fortnight nobody measured. #} {% macro axes(c) %} {% for g in c.grid %} {{ g.label }} {% endfor %} {% for t in c.xticks %} {{ t.label }} {% endfor %} {% endmacro %} {% macro empty(c) %} {# A chart that cannot be drawn says so in words. Drawing it anyway yields a flat stroke, and a flat stroke reads as "steady" about a thing measured once. #}

{{ c.why }}

{% endmacro %} {% macro line(c, note="") %}
{% if not c.ok %}{{ empty(c) }}{% else %} {{ axes(c) }} {% for s in c.series %}{% if not s.empty %} {% for pts in s.runs %}{% endfor %} {% for d in s.dots %}{% endfor %} {% endif %}{% endfor %}
{% for s in c.series %} {{ s.label }} {{ s.range }}{% if not s.empty %} ยท {{ s.n }}/{{ c.n }} measured{% endif %} {% endfor %}
{% if c.normalise == 'each' %} {# ๐Ÿ”ด LOAD-BEARING SENTENCE, not a caveat. With each line scaled to its own range the vertical DISTANCE between two of them means nothing at all, and a reader who is not told that will read it as a comparison. The shared thing is the time axis. #}

Each line is scaled to its own range (shown above) so they fit one picture. Only the time axis is shared โ€” how far apart two lines sit means nothing.

{% endif %} {% if note %}

{{ note }}

{% endif %} {% endif %}
{% endmacro %} {% macro bar(c, note="", compact=false) %}
{% if not c.ok %}{{ empty(c) }}{% else %} {{ axes(c) }} {% for b in c.bars %} {% if b.known %} {{ b.label }} ยท {{ b.text }}{{ ' ยท ' ~ c.partial_note if b.partial }} {% else %} {# ๐Ÿ”ด NOT A ZERO BAR, AND NOT AN EMPTY SLOT EITHER. A week before the log began is a week nobody was watching; a zero-height bar there is visually identical to a week you did nothing, which is the exact confusion the None exists to prevent. It is drawn as a faint FULL-HEIGHT band, so the un-watched stretch reads as "off the chart" rather than as a run of zeros. #} {{ b.label }} ยท no data โ€” before this log began {% endif %} {% endfor %} {# `compact` drops the legend because the grid it sits in states it once. Three identical three-line legends under three small charts is noise, and it crowds out the charts themselves. #} {% if not compact %}
{{ c.title }} {% if c.partial is not none %}this week so far โ€” {{ c.partial_note }}{% endif %} {% if c.bars | rejectattr('known') | list %}before this log began{% endif %}
{% endif %} {% if note %}

{{ note }}

{% endif %} {% endif %}
{% endmacro %} {% macro panel(title, body, note="", doc="") %}

{{ title }}{% if doc %}๐Ÿ“–{% endif %}

{% if note %}

{{ note }}

{% endif %} {{ body }}
{% endmacro %}