Skip to content

Rank semantic type: Bar Table encodes the ordinal as a bar length, inverting the ranking (Bar Chart handles it correctly) #85

Description

@mordechaipotash

What happens

The Rank semantic type's documented behaviour is honoured by the Bar Chart template but ignored by Bar Table, which encodes the ordinal as a bar length and a sequential colour ramp. The result is a chart that reads as the inverse of the data: rank 1 gets the shortest, palest bar and the last-placed item gets the longest, darkest one.

The agent skill documents (flint://agent-skill):

Rank → reversed axis (1 on top), discrete color

Neither template emits a reverse, and Bar Table additionally applies a sequential colour scale rather than a discrete one.

validate_chart returns valid: true with zero warnings in both cases, so nothing in the toolchain flags it.

Reproduction

flint-chart-mcp@0.4.1, backend vegalite.

{
  "data": { "values": [
    { "Engine": "Inworld TTS-2",     "Rank": 1 },
    { "Engine": "xAI leo",           "Rank": 2 },
    { "Engine": "Kokoro am_michael", "Rank": 3 },
    { "Engine": "Gemini",            "Rank": 4 },
    { "Engine": "Inworld 1.5-max",   "Rank": 5 }
  ]},
  "semantic_types": { "Engine": "Name", "Rank": "Rank" },
  "chart_spec": {
    "chartType": "Bar Table",
    "encodings": { "y": { "field": "Engine" }, "x": { "field": "Rank" } },
    "baseSize": { "width": 560, "height": 280 }
  }
}

Swapping chartType to "Bar Chart" with everything else identical produces a sensible ordinal rendering — equal-sized marks positioned by rank, correct row order, no magnitude encoding. That contrast is what makes this look like a template gap rather than intended behaviour.

Inspecting the compiled Vega-Lite:

sort reverse
Bar Table null absent
Bar Chart null, "ascending" absent

Why it matters

An ordinal is not a magnitude — "how much better is 1st than 2nd" has no answer, so any length encoding of it is unfounded. This is the failure mode that is hardest to catch downstream, because the output is well-formed, passes validation, and is confidently wrong in a direction a reader will not question.

Suggested fix

Either honour the documented Rank behaviour in the Bar Table template (discrete colour, no length encoding, 1 first), or have validate_chart warn when an ordinal semantic type (Rank, and arguably ID) is bound to a length-encoding channel.

A validator warning would be the more valuable of the two, since it generalises to any template that adds a magnitude encoding later.

Two smaller observations from the same session

  • Bar Table appears to apply no number formatting at all. Compiling identical data as Bar Chart emits "format": ",.12~g"; as Bar Table no format string is emitted, so Price produces no currency symbol and Percentage produces no percent sign. Both are documented as formatting behaviours of those types.
  • Long field names are altered in Bar Table headers: a field named Hits across 6 clips renders as Hits_across 6_clips when the header wraps.

Thanks for open-sourcing this — the compact-spec-plus-compiler split is the right shape, and the Bar Table template in particular is excellent for dense label+value data once the type behaves.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions