vega / vl-convert

Utilities for converting Vega-Lite specs from the command line and Python
BSD 3-Clause "New" or "Revised" License
96 stars 12 forks source link

label limit legend #30

Closed mattijn closed 10 months ago

mattijn commented 1 year ago

Given this python snippet:

import vl_convert as vlc
from IPython.display import Image
vl_spec = '''
{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "values": [
      {"a": "J", "b": 28, "c": "I am more than 18 characters"},
      {"a": "B", "b": 55},
      {"a": "C", "b": 43},
      {"a": "D", "b": 91},
      {"a": "E", "b": 81},
      {"a": "F", "b": 53},
      {"a": "G", "b": 19},
      {"a": "H", "b": 87},
      {"a": "I", "b": 52}
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "a", "type": "nominal"},
    "y": {"field": "b", "type": "quantitative"},
    "color": {"field": "c"}
  }
}
'''
png_data = vlc.vegalite_to_png(vl_spec=vl_spec)
Image(png_data)

Will return the following truncated legend label : image

Where the vega-editor render this as: image And in editor: Open the Chart in the Vega Editor

The default labelLimit within legend is 160 pixels, but this seems not being respected and changing this value has no positive effect on the image.

jonmmease commented 1 year ago

Thanks for the report!

jonmmease commented 1 year ago

Looking at this a little bit. When I specify the legend labelLimit as below, the full legend is displayed:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "values": [
      {"a": "J", "b": 28, "c": "I am more than 18 characters"},
      {"a": "B", "b": 55},
      {"a": "C", "b": 43},
      {"a": "D", "b": 91},
      {"a": "E", "b": 81},
      {"a": "F", "b": 53},
      {"a": "G", "b": 19},
      {"a": "H", "b": 87},
      {"a": "I", "b": 52}
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "a", "type": "nominal"},
    "y": {"field": "b", "type": "quantitative"},
    "color": {"field": "c", "legend": {"labelLimit": 240}}
  }
}

wide_text

This is a workaround at least, but I'm still not sure why there's a discrepancy. In general, the text width measurement matches really well between pure Vega and VlConvert, so I don't think text measurement is that far off.

I am wondering whether Vega's logic for determining whether to perform text truncation somehow ends up using the fallback text width estimation (which is generally larger than a proper measurement), rather than the precise usvg based measurement.

jonmmease commented 1 year ago

Another thing I checked. In this case VlConvert's width measurement of the "I am more than 18 characters" string is ~130px. This matches the width in screen pixels when I display the image at actual size.

Screen Shot 2023-01-04 at 7 14 37 AM

The tooltip doesn't show up in the screenshot, but this box measures 130x130px. So, it looks like some number other than this 130px is being compared to the 240px label limit 🤔

sergei-mironov commented 1 year ago

Hihi, I see the same issue. Unfortunately, setting labelLimit=240 or so does not help.

jonmmease commented 1 year ago

I think the core issue is this Vega snippet:

https://github.com/vega/vega/blob/d0b886881bd27da626b0d33f2db23bd17f6f4277/packages/vega-scenegraph/src/util/text.js#L77-L87

Here the textMetrics.width function that we override is not used directly to compute the text width for the sake of text truncation. And so it's falling back to the estimated text width.

jonmmease commented 1 year ago

Vega issue: https://github.com/vega/vega/issues/3715

jonmmease commented 11 months ago

Upstream fix proposed in https://github.com/vega/vega/pull/3792