📊 Update OECD Time Use Database and refresh static viz - #6678
📊 Update OECD Time Use Database and refresh static viz#6678paarriagadap wants to merge 21 commits into
Conversation
|
Quick links (staging server):
Login: chart-diff: ❌
data-diff: ✅ no differencesNo differences found. Automatically updated datasets matching excess_mortality|covid|fluid|flunet|country_profile|garden/ihme_gbd/2019/gbd_risk are not included. Run locally with Edited: 2026-08-17 19:27:43 UTC |
Replace the private migrated 2020 Gender Data Portal dataset with a public snapshot → meadow → garden → grapher chain built on the OECD Time Use Database 2026 edition (published 2026-04-30): 35 countries, 30 detailed activities, and newer surveys for 12 countries (US and Mexico 2024, Poland 2023, Canada, Germany and Norway 2022, Croatia 2022/23, Japan 2021, Austria 2021/22, Estonia, Finland and Bulgaria). Garden also builds the display buckets the "How do people spend their time?" chart uses. The grouping is verified numerically against the previous edition of that chart and asserted for China 2008, whose survey has not changed. The export://static_viz step renders the refreshed chart at the static-chart templates' proportions, desktop and mobile, for the Figma handoff.
…ategories Order the ten display groups so each of the OECD's four top-level categories is contiguous, colour each family from one hue, and bracket each category above the bars. On the narrow mobile frame, where the bracket cannot fit, list the same names by category above the chart. Group labels are now placed by a solver rather than by hand: it assigns tiers, wraps and nudges labels, and routes each leader through a corridor its neighbours leave free, asserting that no label, leader or bracket collides. The header therefore survives a data update that changes the top row's proportions, which hand-tuned offsets would not.
…up last Category names now bracket the bars from above and the group names are listed by category below them. Ten group names and four category names could not share one strip: the category-contiguous ordering packs six group names into the right third of the bar, where their labels run several times wider than the segments they name, so the solver had to stack them five tiers deep. Splitting the two halves leaves the top clear, gives every row about a tenth more height, and lets desktop and mobile explain the chart the same way. Within a category, named activities come first and a residual 'other' group comes last, with the deep hue leading and tints following in bar order. An assertion keeps it that way.
A category name wider than the bars it covers now wraps onto a second line before it is moved to a row of its own, and a wide name only keeps its one-line form if the narrowest form of every category to its right still fits beside it. Without that lookahead the widest name took the room and its neighbour was the one bumped, which is backwards. So 'Unpaid work & other' wraps and 'Leisure' returns to the same baseline as the other three, where it sits beside its own bracket and needs no stem.
|
@codex review |
|
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Each category's activities are now listed inside its own bracket, stacked one per line, so every name stands over the run of bars it belongs to instead of in a legend the reader has to carry back to the chart. Inside the bracket the category is already named, so the residual buckets read as just 'Other'; that alone took the header from five lines to three, and what the two least self-explanatory groups contain moved to the Note, where there is room for the words. Labelling each activity over its own segment was tried first and dropped. The top row is Japan's, whose 'Seeing friends' is the narrowest segment in the dataset at 4px, and threading ten names past each other there needed elbow leaders, a search over placement orders and a budget for how many leaders may cross — for a header no easier to read than this one. What it needed is gone with it. Values inside the segments are now drawn per activity only where three quarters of countries can hold one, so none carries numbers on a handful of rows. Education fitted on 1 of 35, and that one number said nothing except that Korea's segment happened to be wide enough. The ranking is an explicit constant that also accepts a category, and the sort is stable, so the four tied countries keep the source's order between runs instead of churning the SVG. Paid work stays: it is the original chart's ranking, and the one column education cannot distort, since education time is depressed wherever the survey's age floor excludes teenagers. Also stops the mobile legend running into the 'Total leisure' column header, with an assertion so a longer legend fails the build instead of overprinting it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
The desktop template's license slot is 263px at 11px and shares its row with the 467px tagline inside 818px of content, so it holds about fifty characters. Two author names do not fit: the line measured 387px and printed on top of the tagline. Phrasing gives rather than names — 'by <names>' instead of 'by the authors <names>' is 329px and clears by 22px. Also removes LABEL_WRAP_WIDTHS, which fed the positional label solver deleted in e8271c7 and had been left behind with a comment about leader corridors. Ruff does not flag unused module-level constants, so nothing caught it; the rebuild after removing it produced byte-identical art, which is what proves it was dead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The plot's band came from this step's own text metrics, and this step draws its title, subtitle and footer smaller than the template does — so the header ink sat flush under its own subtitle and, once the frame carried the template's larger text, cleared it by only 7px where the design asks for 12-16. The band now comes from the template's own text edges, inset by BAND_INSET at each end. Both edges are ink, not frames: the footer frame already starts 14px above its note, so insetting from the frame would inset twice. The right-hand column is right-aligned on the content edge rather than left-aligned at a fixed gap past the bars, so the total-leisure numbers, the logo above them and the note below all share one vertical. The left already lined up: right-aligned country labels put the widest one on the margin. Separators between activity names are their own run in one neutral color. Appended to the name before them they inherited that name's fill, so they changed color down the list and all but vanished after a pale tint. The space before a separator rides with the name, because TextPath measures ink and drops a leading space from a run's advance while matplotlib still draws it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…p can't move it The step drew its copies of the template's text slots smaller than the template does. Nothing in the frame uses them — the import drops them — but the plot's band is derived from where they end, so the render showed a hole the frame did not have, and each round of review spent itself on spacing that was only wrong in the preview. It now fills each slot at the template's own size, line height and position, so the render previews the frame instead of only its proportions. The band follows from the templates' auto-layout rhythm rather than from their shipped positions, which describe placeholder text nobody has: a title row hugging whichever is taller of the title and the logo, a 6px gap, the subtitle. Two consequences worth naming. A one-line title cannot shrink the header past the logo, which is why the band's top is 82.47 here and not the 67 arithmetic alone suggests. And the footer is pinned to the frame's bottom margin, so this Note taking three lines at the template's 12px — where the step's smaller footer took two — costs the chart a row's height rather than moving the rows beneath it. Labels are now anchored where they have to stay rather than where they start, since Figma re-renders them in Lato: middle over a bracket or a segment, end on the content edge, and one call per line for a stacked label, which otherwise carries no anchor at all. A run's trailing space is kept in the layout and out of the glyphs, because SVG centres the trimmed ink. Row text sits on an explicit baseline half a cap-height below the row's centre; `va="center"` splits the font's line box instead, which reserves descender room digits never use and left every value sitting a tenth of a bar high. The license row is drawn as runs so the license and the names it credits can be bold, as the templates set their own. The total-leisure column is derived from its widest value plus one gap — the slack in it was the distance between the numbers and the bars they belong to — and spells the unit out where that still leaves the column a small share of the frame. Its header is centred over those numbers. Wrapping is predicted with a measured allowance per face: the template's Lato sets 2-3% narrower than the font this step measures in, Playfair Display 3% wider. The single conservative margin that preceded it broke both footer rows onto second lines the frame does not have. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The title row hugs whichever is taller, the title or the logo beside it, and both are top-aligned — so with a one-line title the logo's surplus height lands between the title and the subtitle, and the gap comes out at 18px where every finished page in the Charts file shows 6. The templates were only ever exercised with two-line titles, which are taller than the logo. The frame now takes the logo out of its auto-layout, which keeps it exactly where it is and stops it padding the block, so `logo_px` is 0 here and the derived band follows the header up: the plot starts 12px higher and gains that much height. Mobile keeps the logo in the flow. Raising that header would put the subtitle's first line at the logo's height, and mobile's subtitle runs the full 508px — its first line reaches x=493 against a logo starting at 476. Desktop is only safe because its first line ends at 588 with the logo at 770. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…the smallest group The four categories now come from the OWID palette rather than from seaborn positions mapped by hand: Coral, Denim, Copper and Dark Olive Green, bound to their Chart colors library styles in the frame. Personal care had been carrying a color that is not in the palette at all, which is what prompted this. Which category takes which color is the part worth explaining. The best-scoring set puts a near-black green somewhere, and on personal care — half of every bar — that made the chart a green chart. Leisure is a fifth of the bar, so the blue and the green are swapped: every audit number is identical, since it is the same ten fills, and the heaviest one now sits on the smallest family. The tint weights move with the dark base for a related reason. The seams that merged in print were between a base and its own tints, not between categories — 1.46:1 and 1.52:1 against a 1.6:1 floor — so the family carrying the dark base takes the wider spread (0.42/0.78) and the other keeps 0.3/0.68. Together with the palette change that takes the color-vision floor from dE 6.4 to 14.2 and leaves no seam merging. Red beside green is worth the usual suspicion, and the answer is in the lightness: the red and the green here differ 2.39:1 in grayscale, where the red and the mid-green that scored well on paper differ 1.01:1 and duly fail protanopia. The two longest row labels are shortened to US and UK, the forms the style guide sanctions. The row labels set their column's width, so that is 15px of bar on desktop and 13px on mobile — the gap between those two names and "New Zealand". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nning the frame The ten-segment chart resolves more than the harmonization can support. Measured across the 35 countries, the residual buckets inside each category vary two- to threefold — other unpaid work runs 39 minutes in France to 132 in Ireland, other leisure 78 in Bulgaria to 179 in Japan — while the categories themselves vary far less: personal care is 665 minutes give or take 31, a coefficient of variation of 0.05 against 0.25 for its own residual. Aggregating to the four top-level categories takes the mean CV across the segments from 0.22 to 0.12. So most of what the detailed split shows at that level is where each survey drew its coding lines, not how people differ, and this adds the four-category chart as a candidate rather than a replacement. The workings are in `ai/time_use_comparability/`. Two things the aggregation does not fix, and one worry it retires. It cannot help where a boundary runs *between* categories — childcare against leisure with children, eating at work — and it cannot touch the age ranges, which is why the Note still carries them. But the survey years, spread over 1999-2024, turn out not to bias the ranking at all: the correlation between a country's survey year and any of the four categories is +0.09 at most. The chart is a third layout on the same step, not a copy, so the template machinery has one implementation. `GROUPS` and `CATEGORIES` are now read off the layout, and the two shipped charts came out byte-identical afterwards, which is the only proof worth having that a refactor of this size changed nothing. Each layout also ranks by its own leading segment, which for the detailed pair is the same key as before. Three things the new chart needed, each opt-in so the shipped pair is untouched: a category name wraps when it overhangs the segment it names rather than only when it would hit a neighbour; a segment's values take one form per column, so a row that cannot fit the long form does not read as a mistake; and every value is hours and minutes, compactly, because one category set differently from its neighbours reads as a difference in kind when the only difference is that its bar is wider. The Note fix is a bug in the chart that already shipped. Wrapping it against the slot *times* the font slack allowed lines of 832.0 and 821.8 pixels against a content width of 817.57 — two of its three lines printed past the frame's edge. That slack exists to predict how many lines the template's narrower Lato takes; applying it to ink this step actually draws is what let it overrun. It now wraps to the content width, still three lines, so the band does not move. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The pre-commit formatter rewrapped this after the previous commit was assembled, so it lands on its own rather than as a force-push over a pushed commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…efresh # Conflicts: # dag/archive/migrated.yml
Three changes to the four-category chart, and one that reaches the other two. Only surveys from 2010 on are drawn. The source gives one survey per country, so this drops countries rather than years, and 2010 is where that costs least: six countries sit on 2010 itself, so the cut lands on a cluster rather than slicing mid-run, and it buys eleven years of recency for nine countries. It also removes every age-of-reference exception, because Australia (15+), China (15-74) and Lithuania (20-64) are all pre-2010 surveys — so the remaining 26 countries are 15 to 64 throughout, and the Note lost a clause it had carried since the first draft. What it costs is India and China, and with them most of the coverage outside high-income Europe. The cutoff is one constant, applied where the table loads so all three layouts draw the same countries; None restores all 35. The legend names what each category holds — seventeen activities, ordered by the minutes they take. Which activities get named is a data question rather than a layout one: several are reported by a minority of countries (job search by 10 of 35, other unpaid work by 12, childcare by 28), so naming all 22 would imply detail most bars do not have. The Note now carries that caveat instead of the "covers ..." clauses the legend has taken over. Each list hangs off the bars rather than off the top of the band. Top-aligned, a short list ended two lines above the plot while the deepest reached down to it; now every list ends level with the bars and the air sits under the category name, where half a line of it reads as space beneath a heading. The subtitle states the survey window, with the years read from the data so it cannot drift from what is drawn. It says "Average", not "Averages of", for a reason worth keeping: in Lato the longer opening measured 826px against an 817.57px slot, so the frame wrapped a subtitle this step had drawn on one line, and the plot would have been laid over it. This step's font is a percent or two off Lato in either direction depending on the string, so a slot filled past about 97% is a coin flip. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…er's bar opacity The palette is the Default Palette's first four — Denim, Rusty Orange, Camel, Light Teal — with the middle two swapped, and the fills carry grapher's own bar opacity of 0.8 (GRAPHER_AREA_OPACITY_DEFAULT, which both its stacked and its discrete bar chart apply, labels at 1). The swap is because the library's order puts two same-lightness pairs side by side: Denim beside Rusty Orange at 1.14:1 and Camel beside Light Teal at 1.08:1, against a 1.6:1 floor. That reads fine in colour and vanishes in black and white. Swapping costs no colour — which category carries which is free, since the colour-vision numbers are identical for any arrangement of the same four — and takes the opaque seams to 1.86 / 2.12 / 2.28. Three deviations are recorded in the step, all measured at the opacity the bars are actually drawn with, because the composite over the canvas is what a reader sees and not one of these numbers survives being read off the library hex. Seams come out 1.57 / 1.86 / 1.95, the first 2% under the floor. The colour-vision floor drops from 19.2 to 15.3, Camel against Light Teal being the weak pair. And the in-bar labels lose the 4.5:1 they need at 12.15px regular: the best available colour measures 3.74:1 on Denim and 4.30:1 on Rusty Orange, where at full opacity both clear it in white. That last one is the cost of the opacity rather than of the palette — grapher can afford 0.8 because it puts no labels inside its stacked segments, and this chart puts one in every segment. At 0.9 they measure 4.46 and 5.20. Two things had to change for a palette this light to be possible at all. A category's colour is also the colour its legend name and member list print in at 11px, which rules out every light entry in the palette — Camel measures 2.8:1 as text and Light Teal 2.6:1. The library's answer is its "Line and Slope Charts" group, a darker variant of each light fill, every one of which measures exactly 4.4:1 on this cream; the four colours now name a fill and, where needed, that variant, and the frame binds both. And the in-bar label colour is now chosen by measuring white and dark against the composited fill rather than by a luminance cutoff, which had put white on a fill at 4.48:1 where the dark scored 4.68:1. These four also name library colours outright instead of the seaborn placeholders the ten-group version uses. The reason for placeholders is that the fonts cannot be reproduced here; colours can, so a render showing the real ones is simply a truer preview of the frame. The SVG's fill census now matches the frame's node census exactly. The subtitle no longer runs under the logo. On the 850-wide template the frame takes the logo out of the header's auto-layout, which is what keeps the title and subtitle 6px apart — but it leaves the logo hanging into the subtitle's own band, ending at y=57.5 where the subtitle's line box starts at 51.2. So the subtitle has to stop short of it sideways, and the template now says so: `logo_reserve_px` is the logo's width plus a gap, and the subtitle wraps against the slot minus that. The four-category subtitle also drops its age clause, which the Note already carries, so it fits on one line — 134px of clearance where it had been overlapping by 47px. Mobile keeps the logo in the flow and carries the ages in its own note line instead. Last, the two font allowances become one measured ratio each, because one constant was answering two different questions. This step measures in DejaVu Sans, since neither Lato nor Playfair Display is installed, and probe nodes set in the Charts file put DejaVu at 1.15x Lato Regular, 1.26x Lato Bold and 1.10x Playfair SemiBold — not the 2-3% recorded before, which I could not reproduce. Wrapping is judged in DejaVu against the slot itself, so a line that fits here fits the frame with room to spare. Whether a design fits the template is a fact about the frame, so it is judged in Lato: the footer's tagline-and-license row needs 838px of an 818px row in DejaVu and 792px of it in Lato, and the old constant rejected a row that sets correctly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…abels
Keeps the version without subcategory segments and drops the other two. The ten-group
desktop chart and the 540x824 mobile one are gone — renders, layouts and the machinery
only they reached — and the survivor takes the plain name, since "main_categories" no
longer distinguishes it from anything.
The cut is 523 lines: the listed and flowed legends (mobile's header), the total-leisure
column, the bracket rule, the `full_footer` / `category_side` / `group_labels`
alternatives, five functions and seven constants that had no caller left. **The rendered
SVG is byte-identical through every one of those removals** — the approved render was kept
aside and diffed after each pass, which is the only proof worth having that a cut this
size cut nothing.
`GROUPS` and `CATEGORIES` stay, in a smaller role: garden still hands over ten display
groups, so they are the recipe for summing them into four and nothing else. If this
version ships, that sum belongs in garden.
Two legend entries now say what they are, which came out of re-reading the workbook's
"Activity categories & sources" sheet rather than our regrouping of it. Neither was the
source's residual; we had relabelled them:
3.3 "personal, household, and medical services + travel related to personal care"
-> Grooming & health (61 min/day, 9% of personal care)
4.5 "Other leisure activities", which the country mappings show is games, hobbies,
arts and crafts, reading and leisure travel
-> Hobbies & other (96 min/day, 33% of leisure, second only to TV and radio)
One "Other" is left, in the category whose own name already says "& other".
The source's five top-level categories were considered and four kept, which is worth
recording because the fifth is a real thing the chart folds away. Category 5 is 18.5
min/day of religious, civic and unclassified time, counted here within unpaid work.
Drawn as its own segment it is 7.8px wide on average and 2.1px on seven countries, so it
can hold neither a value nor a legend column; adding a fifth colour takes the composited
colour-vision floor from 15.3 to 14.9 and no arrangement of five clears the grayscale
seam (best 1.18:1 against 1.6); and two-thirds of it is the source's own "other (no
categories)". The category name discloses the fold, which is the honest part.
Also here, from following the design team's template rebuild (verified with
create-figma-chart's `verify_templates.js`, which returns ok): the header wrappers lost
their inner padding and the logo became a sibling on both families, so `origin_y` is 16,
`logo_px` is 0 and a one-line title takes the band top from 82.5 to 70. That dissolved
the subtitle/logo collision, so the age clause is back in the subtitle and the width
reserve is gone.
And the measurement fix underneath it: `sns.set_style` installs an Arial-first stack but
runs after the title and subtitle are wrapped, so the step measured in DejaVu and drew in
Arial. Measuring in the stack it draws with puts the ratios back where the skill records
them — Playfair 3.2% wider, Lato Regular 0.8% narrower — with one addition: Arial Bold
sets 6.6% wider than Lato Bold, which is why the footer's mixed-weight row needs its own
allowance and why it was rejecting a row that sets correctly in the frame.
The step also carries a Figma handoff recipe now, which it never had.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ebuilt footer holds Both come from lessons master added this week. A link given in chat is lost by the next session, so the file, the page and the frame go in the docstring as deep links, with the point the lesson turns on: the node ids are a convenience and the frame NAME is the durable join. It is the kebab-case slug the website exports the PNG by, so it is the one string shared by the layer panel, the exported file and this step — and re-cloning a rebuilt template mints new ids, which is exactly the moment someone comes looking for the frame. The second lesson found a real error here. These rebuilt footers are pinned by their TOP (`constraints.vertical: MIN`) and grow downward, while this step's comment said the rows are pinned to the frame's bottom margin and its band arithmetic grows the Note upward into the chart. The two agree at the template's own two lines, which is why nothing looked wrong, and diverge past them: a third line would leave the frame's licence row 2px from the bottom edge where the template puts 16. So the Note's cap comes down from three lines to two, and both the comment and the assertion now say why, and what to change together if a longer Note is ever wanted — re-pin the footer in the frame and raise the cap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Refreshes the OECD Time Use Database to the 2026 edition and rebuilds the "How do people spend their time?" static visualization on top of it.
The previous version of this dataset was a legacy backport (
oecd/2020-11-05/time_use_across_activities__oecd_gender_data__2020, private, no catalog path). It is replaced by a normal public ETL chain, so the data is now in the catalog and the chart is reproducible from a step rather than from a one-off file.The chain
Snapshot is the OECD's own workbook, published 2026-04-30, accessed 2026-08-14.
Garden emits two tables
time_usesurvey_yearandage_of_referenceper rowtime_use_chart_groupstotal_leisure, for the chartBoth cover 35 countries × 3 breakdowns (total, men, women). Survey years run 1999–2024 and differ by country, so each row carries its own
survey_yearrather than the table pretending to a single reference year.The regrouping of the OECD's 30 detailed activities into the 10 display groups lives in garden, documented and asserted there, so the static-viz step only lays out what it is given.
The static visualization
One frame, 850×1095, on the vertical static-chart template, as SVG and PNG. Each bar is a country's
day split into the OECD's four top-level categories, ranked by paid work or study, with the activities
each category holds named above it.
Only surveys from 2010 on — 26 countries, 2010–2024. The source gives one survey per country, so a
cutoff drops countries rather than years, and 2010 is where that costs least: six countries sit on 2010
itself, and it buys eleven years of recency for nine others. It also removes every age-of-reference
exception (Australia 15+, China 15–74, Lithuania 20–64 are all pre-2010), so the remaining countries are
15 to 64 throughout. What it costs is India and China, and with them most of the coverage outside
high-income Europe. One constant;
Nonerestores all 35.The step fills the template's slots at the template's own sizes, positions and line heights, so the
render previews the frame rather than only its proportions. The chart band is derived from the
templates' auto-layout rhythm rather than recorded, because every position in the template describes its
placeholder text. The design team rebuilt those headers in August: the wrappers lost their inner padding
and the logo became a sibling rather than a child of the title row, so a one-line title genuinely shrinks
the header and this frame's band top went from 82.5 to 70. Re-verified with
/create-figma-chart'sverify_templates.js, which returnsok.Labels are anchored where they must stay, not where they start, because Figma re-renders them in
Lato: middle over a segment, end on the content edge, one call per line for a stacked label (a
multi-line label carries no
text-anchorat all). Row text sits on an explicit baseline half acap-height below the row's centre —
va="center"splits the font's line box and left every value atenth of a bar high.
Four categories, not the source's ten display groups
This is the substantive decision in the PR. The ten resolve more than the harmonization supports:
the residual buckets inside each category vary two- to threefold across countries (other unpaid work
runs 39 minutes in France to 132 in Ireland) while the categories themselves vary far less — personal
care is 665 minutes ± 31. Aggregating takes the mean coefficient of variation across segments from
0.22 to 0.12, so most of what the finer split resolves is where each survey drew its coding lines,
not how people differ. A ten-group version and a 540×824 mobile one were built and dropped; the workings
are in
ai/time_use_comparability/.Two things aggregating does not fix, and one worry it retires:
still moves minutes. It stays in the Note.
year and any of the four categories is +0.09 at most.
Five categories were considered and four kept. The source publishes five (paid work or study, unpaid
work, personal care, leisure, other) and this chart folds the fifth — religious, civic and unclassified
time, 18.5 min/day and up to 40 — into unpaid work, which is what the category's "& other" name
discloses. Drawn as its own segment it is 7.8px wide on average and 2.1px on seven countries, so it
can carry neither a value nor a legend column; adding a fifth colour takes the composited colour-vision
floor from 15.3 to 14.9 and no arrangement of five clears the grayscale seam (best 1.18:1 against
1.6); and two-thirds of it is the source's own "other (no categories)".
The legend names what the source names
Seventeen activities, ordered by the minutes they take. Which ones get named is a data question rather
than a layout one: several are reported by a minority of countries (job search by 10 of 35, other unpaid
work by 12), so naming all 22 would imply detail most bars do not have.
Re-reading the workbook's "Activity categories & sources" sheet then showed that two of the three
"Other" lines were not the source's residuals at all — we had relabelled them:
One "Other" is left, in the category whose own name already says "& other".
Colors, and the color-vision check
The Default Palette's first four, bound to the
[Chart Colors] Library— Denim, Camel, Rusty Orange,Light Teal — with the middle two swapped so touching segments differ in lightness, and drawn at grapher's
own bar opacity of 0.8 (
GRAPHER_AREA_OPACITY_DEFAULT, which both its stacked and its discrete barchart apply; labels stay at 1). The library's order puts two same-lightness pairs side by side (Denim
beside Rusty Orange at 1.14:1, Camel beside Light Teal at 1.08:1, against a 1.6:1 floor) — fine in colour,
invisible in black and white. Swapping costs no colour, since the CVD numbers are identical for any
arrangement of the same four.
Two constraints shaped the set, and the second is easy to miss:
exists: everything light in the palette sits at L 60–65, where two of them have no seam at all.
2.8:1 as text and Light Teal 2.6:1. The library's answer is its "Line and Slope Charts" group, a darker
variant of each light fill, every one of which measures exactly 4.4:1 on this cream — so the colour
spec names a fill and, where needed, that variant, and the frame binds both.
Three accepted deviations, all measured at the opacity the bars are drawn with, since the composite
over the canvas is what a reader sees:
Those labels are 12.15px Lato Regular, so 4.5:1 applies with no large-text allowance. The label contrast
is the cost of the opacity, not of the palette — grapher can afford 0.8 because it puts no labels inside
its stacked segments, and this chart puts one in every segment. At 0.9 they measure 4.46 and 5.20.
In Figma
One frame,
how-do-people-spend-their-time,on page 20260817 How do people spend their time? (Pablo A),
cloned from the rebuilt
Static Chart Template_Verticalwith its unstyled import parked to the left. Thefull recipe — import mechanics, the exact scale factor, every text slot and its bold ranges, the colour
keys, the restyle order — is in the step's docstring, so a later session can redo it from the file alone.
Retiring the old dataset
The migrated dataset's steps and backport snapshot mirrors are deleted, its dag entry removed, and it is recorded in
dag/archive/migrated.ymlwith the commit where it was last active.Verification
make checkgreen;tests/test_static_viz.pypasses (31 tests); the contract verifier reports 0 clippaths and 267 named layers
lines — the listed and flowed legends, the total-leisure column, the bracket rule, three layout
switches, five functions and seven constants — and the approved SVG was diffed after every pass
line clear of the logo by 134px, 104 segments at 0.8 opacity, every coloured fill bound to a library
style
Two corrections worth noting, both caught by measuring rather than by review:
sns.set_styleinstalls an Arial-first stack butruns after the title and subtitle are wrapped. Measuring in the stack it draws with puts the slot
allowances back where the skill records them (Playfair 3.2% wider, Lato Regular 0.8% narrower), plus
one the skill does not: Arial Bold sets 6.6% wider than Lato Bold, which is why the footer's
mixed-weight row needs its own allowance.
They agree at two lines and diverge past them, so the Note is capped at two.
Open before merge
Raising it to 0.9 fixes both (4.46 and 5.20) and keeps most of the softening. Needs a call.
into four; now that four is what ships, the aggregate belongs in the catalog.
from the source's own labels
time-women-and-men-spend-on-leisure) — remapped on staging to the new variable IDs(
1207880 → 1296121,1207882 → 1296123); chart diff shows it and needs approval, which is theonly thing keeping CI red
2026 edition spans 1999–2024
2018→2024, Japan 2016→2021, Mexico 2014→2024, and nine others), and Japan now tops paid work