Skip to content

Improve tooltip and chart chrome customizability - #311

Merged
Alek99 merged 4 commits into
mainfrom
agent/improve-tooltip-chrome-customizability
Jul 26, 2026
Merged

Improve tooltip and chart chrome customizability#311
Alek99 merged 4 commits into
mainfrom
agent/improve-tooltip-chrome-customizability

Conversation

@Alek99

@Alek99 Alek99 commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

  • add xy.tooltip(labels={...}) for readable presentation names without changing source-field lookup, formatting keys, title placeholders, or event payloads
  • support labels for explicit fields= and the default x/y/color/size rows
  • expose tooltip_title, tooltip_row, tooltip_label, tooltip_value, legend_title, and legend_label DOM slots
  • keep tooltip labels and values text-only and revalidate directly constructed or mutated public Tooltip dataclasses before serialization
  • refresh canvas/SVG paint when a host changes an ancestor data-theme attribute
  • publish the Chrome Slots guide and make the palette playground genuinely editable with accessible Primary/Secondary/Accent inputs, Custom state, and Reset
  • correct stale custom-tooltip and renderer-neutral palette documentation

Why

The existing customization surface was strong at the chart and container level but inconsistent inside browser chrome:

  • built-in tooltip lines were flat strings separated by <br>, so labels and values could not be aligned or styled independently
  • source column identifiers were also the presentation labels
  • legend titles used an inline weight and legend labels were bare text nodes, leaving no stable hooks
  • the theme observer watched only class and inline style, missing the common data-theme pattern
  • the detailed slot guide was hidden from navigation, and the palette playground demonstrated presets rather than user-selected colors

User impact

Users can now keep stable data schemas while presenting readable tooltip copy, independently style tooltip and legend typography/layout through the same slot API as other chart chrome, and rely on data-theme switches to repaint non-DOM chart surfaces. The docs now expose these capabilities and provide an editable playground rather than workaround-oriented examples.

Evidence

The same chart, data, dimensions, hovered point, and viewport were used in both captures.

Before

Before: raw source identifiers in indivisible tooltip lines

The tooltip exposed raw source identifiers and each line was one indivisible text fragment.

After

After: readable labels and independently styled semantic rows

The source fields now have presentation labels, with title, rows, labels, and values independently styleable through stable slots.

Compatibility and safety

  • Tooltip.labels is appended after the released dataclass fields, preserving positional construction compatibility.
  • Factory arguments remain keyword-only.
  • Formatting and title interpolation continue to use source field names.
  • Built-in and custom Reflex tooltips keep their existing integration boundary.
  • User-provided labels and values use textContent; hostile markup remains inert.
  • Default categorical tooltip output is unchanged unless a custom label is supplied.

Validation

  • 159 passed — component API, public type surface, and static-client security tests
  • 31 passed — tooltip/legend interaction, styling, and responsive-layout browser regressions in headless Chrome
  • 92 passed, 1 xfailed — complete docs-app suite
  • node js/build.mjs — TypeScript check and both browser bundles
  • Ruff format/check and git diff --check

The repository-wide quick gate was also attempted in the restricted workspace: 2,361 tests passed. Its remaining failures were blocked Chrome/loopback-socket launches plus the existing asset assertion that searches for unminified function spellings in the intentionally minified generated bundle; the affected focused browser suites were rerun outside the sandbox and passed.

Follow-up opportunities from the audit

  • explicit hover metadata for source columns that are not resident render channels
  • kernel SVG/PNG parity for axis(format=...) and host-computed CSS themes
  • keyboard/ARIA semantics for interactive legend rows
  • finer-grained modebar menu/group/item slots

Summary by CodeRabbit

  • New Features
    • Added xy.tooltip(labels=...) to customize tooltip field text while keeping the same field lookup and formatting behavior, with label content treated as text (not HTML).
    • Added independent styling hooks for tooltip title/row/label/value and legend title/label.
    • Theme refresh now responds to changes in an ancestor data-theme.
    • Enhanced the palette playground with editable Primary/Secondary/Accent color pickers and better theme-driven chart snippets.
  • Documentation
    • Updated tooltip/legend/chrome-slots styling guides, added the Chrome Slots page, and refreshed capability-matrix counts.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Alek99, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b2a38ab8-c3f7-4749-bdb3-0183422684ab

📥 Commits

Reviewing files that changed from the base of the PR and between ef5555b and a2fad1a.

📒 Files selected for processing (1)
  • spec/api/export.md
📝 Walkthrough

Walkthrough

Tooltip labels with structured DOM slots, expanded chrome contracts for legend and tooltip sub-elements, theme refresh observation of data-theme attributes, Chrome Slots documentation publication, and an editable palette playground with theme-driven chart examples are implemented across Python, JavaScript, documentation, and tests.

Changes

Tooltip labels and structured rendering

Layer / File(s) Summary
Tooltip API and validation
python/xy/components.py, tests/test_components.py
Adds validated labels mapping parameter to Tooltip dataclass and tooltip() factory; revalidates tooltip nodes on mutation; emits labels in chart specifications alongside fields, title, and format.
Structured tooltip DOM rendering
js/src/52_tooltip.ts, tests/test_ui_issue_regressions.py
Replaces string-line tooltip generation with structured items; applies custom labels as safe .textContent; renders title/row/label/value through independent DOM slots; preserves field lookup and formatting semantics.
Tooltip documentation
docs/components/tooltips.md
Expands guidance on labels= (column-to-display mapping), clarifies format= vs labels= distinction, documents independent styling of tooltip subslots, and updates FAQ and integration examples.

Chrome slots and legend rendering

Layer / File(s) Summary
Public chrome slots contract
python/xy/dom.py, tests/test_type_surface.py, spec/api/styling.md, spec/design-dossier.md
Expands CHART_DOM_SLOTS with legend title/label and tooltip title/row/label/value sub-slots; validates tuple; specifies slot text-only insertion and labeling semantics.
Legend semantic rendering
js/src/50_chartview.ts, tests/test_ui_issue_regressions.py
Legend title and labels move to dedicated DOM slots via _applySlot; removes hardcoded inline styles; applies per-slot styling via CSS.
Theme refresh and stylesheet
js/src/50_chartview.ts, js/src/20_theme.ts, tests/test_static_client_security.py
MutationObserver watches data-theme attribute changes; adds default CSS styling for legend_title and tooltip_label slots with separator pseudo-content.

Chrome documentation and navigation

Layer / File(s) Summary
Chrome Slots publication and navigation
docs/app/xy_docs/config.py, docs/styling/chrome-slots.md, docs/api-reference/public-types.md
Adds Chrome Slots as published page under Styling navigation; removes legacy redirect; documents all legend, colorbar, and tooltip sub-slots with Tailwind examples and styling approaches.
Component styling and legend guidance
docs/styling/component-variations.md, docs/components/legends.md, docs/styling/customize.md
Updates legend styling table to include legend_title and legend_label; documents legend slots and direct xy.legend() styling; expands examples with per-slot CSS/class targeting.
Styling index and capability matrix
docs/styling/index.md, docs/styling/capabilities.md, spec/api/capability-matrix.md
Updates Tooltip entry wording to "field labels"; adds palette playground link; expands capability matrix from 23 to 29 stable browser chrome slots; documents slot-to-native-writer mappings.
Theme and export documentation
spec/api/export.md
Clarifies that client-side theme refresh observes data-theme and inline-style changes in addition to class mutations.

Editable palette playground

Layer / File(s) Summary
Palette state and controls
docs/app/xy_docs/playground.py
Adds ChartPlaygroundState event handlers for set_primary_color, set_secondary_color, set_accent_color; marks preset "Custom" on edits; adds _color_control() and _palette_controls() UI components with native hex inputs wired to state events.
Theme-driven chart examples and snippets
docs/app/xy_docs/playground.py
Removes _HIDDEN_AXIS_STYLE dictionaries; uses xy.theme(palette=[primary, secondary, accent]) for chart series in momentum, comparison, product mix, funnel, traffic share, channel mix; replaces complex axis styles with show=False and grid=True options; generates matching code snippets.
Playground documentation and tests
docs/styling/playground.md, docs/styling/examples.md, docs/app/tests/test_docs_site.py, docs/styling/customize.md
Expands playground description with editable Primary/Secondary/Accent, Custom, and Reset behavior; adds palette playground link; validates state wiring, preset/color handler counts, reset behavior, and custom-color literal palette requirement in spec.

Estimated code review effort: 4 (Complex) | ~50 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ChartPlaygroundState
  participant chart_playground
  participant xy_theme
  User->>ChartPlaygroundState: set primary/secondary/accent color
  ChartPlaygroundState->>ChartPlaygroundState: mark preset Custom
  chart_playground->>xy_theme: apply xy.theme(palette=[...])
  xy_theme->>User: render themed chart grid
Loading

Possibly related PRs

  • reflex-dev/xy#280: Shares legend rendering and chrome theming updates in js/src/20_theme.ts and js/src/50_chartview.ts for legend title styling via slot-based DOM application.
  • reflex-dev/xy#310: Shares CHART_DOM_SLOTS expansion and capability-matrix updates documenting the new tooltip and legend sub-slots and their native writer coverage.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: making tooltip and chart chrome styling more customizable.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/improve-tooltip-chrome-customizability

Comment @coderabbitai help to get the list of available commands.

@Alek99
Alek99 marked this pull request as ready for review July 26, 2026 08:25
@codspeed-hq

codspeed-hq Bot commented Jul 26, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 103 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing agent/improve-tooltip-chrome-customizability (a2fad1a) with main (f7e314c)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@spec/api/export.md`:
- Around line 168-169: Update the stale source reference in the specification’s
description of the data-theme observer to point to the implementation range at
lines 476-482 instead of 50_chartview.ts:4037. Keep the surrounding explanation
about local browser refresh and observed data-theme/inline-style changes
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 780f4df2-51f6-4cbe-ab29-0efff8bc46dc

📥 Commits

Reviewing files that changed from the base of the PR and between f7e314c and 3e3e2ed.

⛔ Files ignored due to path filters (2)
  • spec/assets/tooltip-customizability-after.png is excluded by !**/*.png
  • spec/assets/tooltip-customizability-before.png is excluded by !**/*.png
📒 Files selected for processing (25)
  • CHANGELOG.md
  • docs/api-reference/public-types.md
  • docs/app/tests/test_docs_site.py
  • docs/app/xy_docs/config.py
  • docs/app/xy_docs/playground.py
  • docs/components/legends.md
  • docs/components/tooltips.md
  • docs/styling/chrome-slots.md
  • docs/styling/component-variations.md
  • docs/styling/customize.md
  • docs/styling/examples.md
  • docs/styling/index.md
  • docs/styling/playground.md
  • js/src/20_theme.ts
  • js/src/50_chartview.ts
  • js/src/52_tooltip.ts
  • python/xy/components.py
  • python/xy/dom.py
  • spec/api/export.md
  • spec/api/styling.md
  • spec/design-dossier.md
  • tests/test_components.py
  • tests/test_static_client_security.py
  • tests/test_type_surface.py
  • tests/test_ui_issue_regressions.py

Comment thread spec/api/export.md Outdated
@Alek99
Alek99 merged commit 56a7a90 into main Jul 26, 2026
28 checks passed
Alek99 added a commit that referenced this pull request Jul 27, 2026
Closing the `loc` vocabulary caught XY's own documentation: the
components/facets-and-layers page passes `loc="top left"`, which is not
Matplotlib's spelling, so the substring match found "left" but neither "upper"
nor "lower" and the page has been rendering a *center*-left legend. Refusing it
would be pedantry — `top` and `bottom` name the same edges as `upper` and
`lower`, and they are what CSS, Plotly and that doc page all say.

So the vocabulary normalizes what is unambiguous and refuses only what is
genuinely a guess: case and whitespace are free, `-`/`_` separate words, either
word order works, `right`/`left` alone mean the centered edges, and
`top`/`bottom` map to `upper`/`lower`. `northeast`, `outside right` and
`middle left` still raise, because there is no honest answer for them.

Also here, both surfaced by the same audit:

- A legend style written in ordinary kebab-case CSS — the spelling every doc
  example uses — lost its `box-shadow` and `border-radius` outright, because the
  writers key on the browser's camelCase property names. Folding the slot into
  the merged declaration block fixes it; pinned by a test that asserts the two
  spellings produce identical bytes.

- `docs/styling/chrome-slots.md` still published the pre-#311 slot count and the
  old all-dropped row.
Alek99 added a commit that referenced this pull request Jul 27, 2026
Closing the `loc` vocabulary caught XY's own documentation: the
components/facets-and-layers page passes `loc="top left"`, which is not
Matplotlib's spelling, so the substring match found "left" but neither "upper"
nor "lower" and the page has been rendering a *center*-left legend. Refusing it
would be pedantry — `top` and `bottom` name the same edges as `upper` and
`lower`, and they are what CSS, Plotly and that doc page all say.

So the vocabulary normalizes what is unambiguous and refuses only what is
genuinely a guess: case and whitespace are free, `-`/`_` separate words, either
word order works, `right`/`left` alone mean the centered edges, and
`top`/`bottom` map to `upper`/`lower`. `northeast`, `outside right` and
`middle left` still raise, because there is no honest answer for them.

Also here, both surfaced by the same audit:

- A legend style written in ordinary kebab-case CSS — the spelling every doc
  example uses — lost its `box-shadow` and `border-radius` outright, because the
  writers key on the browser's camelCase property names. Folding the slot into
  the merged declaration block fixes it; pinned by a test that asserts the two
  spellings produce identical bytes.

- `docs/styling/chrome-slots.md` still published the pre-#311 slot count and the
  old all-dropped row.
Alek99 added a commit that referenced this pull request Jul 27, 2026
* Let chart chrome keep its styling all the way into a file

XY publishes "five ways to style" a chart, and one of them stopped at the
browser. `styles={slot: {...}}` validated, shipped on the wire, and was then
dropped in full by the SVG, PNG and PDF writers — the capability inventory put
it at 2 of 29 slots styleable natively. A chart styled for its live view
exported unstyled, silently, which is the failure mode §28 exists to prevent.

The nine slots that name chrome a static file actually contains — title,
axis_title, tick_label, the three legend slots, the three colorbar slots — now
carry font-size, font-weight, font-style, font-family, letter-spacing, opacity
and the text paint into all three renderers. That is 10 of 29. The rest are
live-only chrome (tooltip, modebar, crosshair, selection, badge) with nothing
in a file to paint, and `class_names` cannot apply in a file at all: a class
selects a rule out of a stylesheet an export does not have.

The plumbing was already there — `spec["dom"]["styles"]` has always shipped —
so this is a read, not a protocol change. Unstyled output stays byte-identical;
a test pins that. The raster's baked atlas is one face, so it honors a slot's
size and paint and leaves the typeface properties to the vector writers, which
is the one divergence and is pinned too. Where two surfaces name the same
chrome the narrower selector wins: an axis's own label_color over the
chart-wide slot.

Three more gaps the same audit turned up, all in the same seam:

- The legend had three spellings that disagreed. `styles={"legend": ...}`,
  `xy.legend(style=...)` and `--chart-legend-bg` now merge into one declaration
  block before either writer sees it. The theme token is documented and public
  and neither static writer read it at all. An explicit `background` also
  painted at 8% opacity while the browser painted it opaque; the frame-alpha
  token stays the separate knob for the default grey frame.

- `loc="best"` — Matplotlib's default, so the first spelling users try — fell
  through the writers' substring match and parked the legend dead center, on
  top of the data. It is implemented now, scoring each candidate box by the
  fraction of sampled marks inside it. It resolves once at payload-build time,
  so the client and both writers receive a settled location and cannot
  disagree. The vocabulary is also closed: `"top-left"`, `"northeast"` and
  `"LOWER RIGHT"` used to land the legend somewhere arbitrary rather than fail.

- `theme()` accepted any keyword and emitted a CSS declaration no renderer
  reads, so `theme(grid_colour=...)` changed nothing and said nothing. Unknown
  tokens raise and name the accepted set — and the real `--chart-*` tokens
  (tooltip_bg, legend_bg, annotation_text, accent, focus, …) became reachable
  by name instead of being dead CSS.

Evidence: spec/assets/chrome-styling-before-after.png.

* Accept the legend-placement spellings that are unambiguous

Closing the `loc` vocabulary caught XY's own documentation: the
components/facets-and-layers page passes `loc="top left"`, which is not
Matplotlib's spelling, so the substring match found "left" but neither "upper"
nor "lower" and the page has been rendering a *center*-left legend. Refusing it
would be pedantry — `top` and `bottom` name the same edges as `upper` and
`lower`, and they are what CSS, Plotly and that doc page all say.

So the vocabulary normalizes what is unambiguous and refuses only what is
genuinely a guess: case and whitespace are free, `-`/`_` separate words, either
word order works, `right`/`left` alone mean the centered edges, and
`top`/`bottom` map to `upper`/`lower`. `northeast`, `outside right` and
`middle left` still raise, because there is no honest answer for them.

Also here, both surfaced by the same audit:

- A legend style written in ordinary kebab-case CSS — the spelling every doc
  example uses — lost its `box-shadow` and `border-radius` outright, because the
  writers key on the browser's camelCase property names. Folding the slot into
  the merged declaration block fixes it; pinned by a test that asserts the two
  spellings produce identical bytes.

- `docs/styling/chrome-slots.md` still published the pre-#311 slot count and the
  old all-dropped row.

* Score legend placement where the marks are actually drawn

Review of the previous two commits found four real defects, three of them in
code they introduced.

`loc="best"` scored occupancy in *value* space. On a log axis that is the wrong
space: 1..10000 is four evenly spaced decades on screen, but raw subtraction
puts them at 0, .001, .01, .1, 1 — so `best` saw a series crushed against one
edge and guarded a corner the marks do not occupy. Placement now applies the
axis display transform (`log`/`symlog`, matching `_svg._Scale`) before scoring.

Out-of-domain samples were clamped onto the plot edges with `np.clip`. Every
renderer clips those marks away, so clamping invented occupancy in a corner the
viewer sees as empty — a chart with a fixed `domain=` and a tail outside it
would refuse the corner that tail visibly vacated. They are dropped instead, and
a series with nothing visible left is not scored at all.

The raster writer applied the legend slot and the `--chart-legend-bg` token to
the *main* legend only; `_svg` applied them to every legend. So a chart with a
categorical color channel — which adds a second legend — styled correctly in
SVG and PDF and silently skipped that legend in PNG. Both writers now fold the
same declaration block into every legend.

`theme()` grew a `__name` escape hatch that mapped to `--name`, which quietly
reopened the dead-CSS hole the closed vocabulary exists to shut:
`theme(__grid_colour=...)` emitted `--grid-colour` and changed nothing. Removed;
`style=` is the documented, validated way to set a custom property.

Also, without changing pixels:

- `_SLOT_RASTER_PROPS` was dead and overstated. The glyph primitive takes a size
  and one RGBA paint, so `opacity` and `letter-spacing` are vector-only along
  with the typeface properties. Now `SLOT_RASTER_PROPS`, used by the tests, and
  the spec says which subset each writer reads instead of implying all three
  honor all eight.
- An unstyled colorbar renders 11px in SVG (inherited from the root) and 10px in
  the raster. That predates per-slot support and closing it would change the
  pixels of every existing unstyled colorbar, so it is registered as a known
  renderer divergence rather than silently left for someone to find.
- The generated matrix's one-line summary said the 10 native-reaching slots got
  there "through a channel other than per-slot styles" — true of `root` alone,
  and the opposite of what these commits ship for the other nine.
- The `best` sampling policy — 4096-point stride, 512-sample cap, display space,
  drop-not-clamp, candidate order, 0.02 tie band — is now normative in the spec
  (§28), not left for a reader to infer from the code.
- `xy.legend(style=...)` is canonicalized to the writers' property spelling like
  the slot already was. It reaches them through `chrome_styles` today, so this
  changes nothing now, but a legend built without that mirror would have lost
  its kebab-case declarations.

* Name the colorbar's font size instead of inheriting one

A second review pass found the earlier "known divergence" note was the wrong
call, and two of the tests added with it were vacuous.

The colorbar text size is not a divergence to document, it is an SVG bug. The
`colorbar` slot's stylesheet rule is `font-size:10px` and the raster writer
passes 10 explicitly; the SVG writer emitted no size at all and inherited the
root `<svg>`'s 11px, so it was the odd renderer out on every unstyled colorbar.
It names the size now, from a `COLORBAR_FONT_SIZE` both writers read, and the
divergence entry is removed because the divergence is gone. Every other slot
already agreed — colorbar was the single exception, which is what made it look
like a policy rather than a mistake.

The log and symlog tests did not test anything. Both fixtures were symmetric:
`test_best_scores_a_log_axis_in_display_space` put identical decades on both
axes, so value-space scoring saw the same diagonal and returned `"upper left"`
too, and the symlog case used `[-100, 0, 100]` on a symmetric domain, which is
invariant to the constant because symlog is odd. Both passed with the transform
removed. They now use a scatter whose display-space and value-space occupancy
genuinely disagree (`"lower left"` vs `"upper right"`) and interior asymmetric
symlog values with two explicit constants, and a guard test asserts the fixture
itself still discriminates. Verified by mutation: reverting the transform, the
constant, or drop-not-clamp each fails the tests that cover it.

Two smaller corrections:

- The spec claimed placement "costs O(1) on a large series". It is a fast path,
  not a bound — a sample with no finite pair falls back to scanning the full
  array, so the worst case is O(n) once at build time. Says so now.
- The generated matrix still told readers the native writers "read the
  chart-level `style=` token bag and nothing per-slot", which is what this
  branch stopped being true. It now describes the property subset the writers
  actually read, and why `class_names=` still reaches neither.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant