posit-dev / posit-dev/ggsql

Scale expansion is computed in linear data space and then clipped, collapsing log domains

Open
#512 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug plot building
Dominant language
Rust
Stars
554
Forks
30
Avg merge
17h 27m
Merged PRs (30d)
8

Description

This issue came out of work on the Hephaestus writer

Summary

resolve_common_steps expands a continuous scale's input range with expand_numeric_range_selective — plain linear arithmetic on the untransformed values — and only afterwards calls clip_to_transform_domain (src/plot/scale/scale_type/mod.rs:2017-2018, same order in src/plot/scale/types.rs:233). When the padded minimum crosses the transform's valid boundary, the clip replaces it with the boundary's smallest representable value rather than a sensible padded bound. For log that is f64::MIN_POSITIVE, which turns a 3-decade axis into a 311-decade one.

Reproduction
SELECT * FROM (VALUES (1), (10), (100), (1000)) AS t(v)
VISUALISE v AS x, v AS y
DRAW point
SCALE y VIA log

Resolved y scale in the Vega-Lite output:

"scale": { "type": "log", "base": 10, "domain": [2.2250738585072014e-308, 1049.95], "zero": false }
"axis": { "values": [4.999999999999997e-308, 1.999999999999999e-256, 9.999999999999996e-205,
                     9.999999999999996e-153, 4.999999999999999e-101, 2e-49, 1000.0] }

The data occupies the top ~1% of the axis, and the label expression VL emits for those breaks is 2498 characters of denormal decimal literals.

Expansion is not broken for log in general — it works whenever the padded bound stays positive (body_mass VIA log on ggsql:penguins resolves [2520, 6480], a real 5% pad). The trigger is min − mult·span − add <= 0, i.e. data spanning decades.

Impact

Both writers, differently:

  • Vega-Lite — every point crushed against the top of the panel, plus the 2498-char axis.labelExpr above.
  • hephaestus — an essentially empty figure: chrome consumes the layout and only the y title survives.
Suggested fix

Expand in transform space: transform the range, apply the multiplicative and additive expansion there, then invert. The padded bound then stays inside the transform's domain by construction, and clip_to_transform_domain becomes a safety net instead of the thing producing the domain.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/plot/scale/scale_type/mod.rs around lines 2017-2018 and the corresponding ordering in src/plot/scale/types.rs:233, following resolve_common_steps, expand_numeric_range_selective, and clip_to_transform_domain. Reproduce the log-scale example and verify that expansion in transform space produces a sensible padded domain for both Vega-Lite and hephaestus, without the extreme axis labels or collapsed plot.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
data-visualization
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.