altair icon indicating copy to clipboard operation
altair copied to clipboard

formatLocale when exporting to png/svg

Open MarcoBaroncini opened this issue 2 years ago • 9 comments

Hi everyone,

I've been looking for a while for a way to export a chart to png/svg while preserving formatLocale settings. As far as I cloud understand, right now this is not possible (or at least I couldn't find any information about it anywhere). To me this would be a very important feature: while I can format numeric data before showing it on the chart via mark_text(), with axis labels is pretty impossible in most scenarios.

I think this might be a useful feature for all the people using Altair with any locale different from US-UK to print charts to image files.

MarcoBaroncini avatar Nov 10 '23 17:11 MarcoBaroncini

Hi @MarcoBaroncini! Excellent feature request.

The following is an example spec that will render successfully with both a locale format and time-format in a notebook:

import altair as alt
from vega_datasets import data
from urllib import request
import json

source = data.stocks.url

# fetch & enable Italy format and time-format locale.
url_format_it = 'https://unpkg.com/d3-format/locale/it-IT.json'
url_time_format_it = 'https://unpkg.com/d3-time-format/locale/it-IT.json'

with request.urlopen(url_format_it) as f:
    format_it = json.load(f)

with request.urlopen(url_time_format_it) as f:
    time_format_it = json.load(f)

alt.renderers.set_embed_options(timeFormatLocale=time_format_it, formatLocale=format_it)

alt.Chart(source).mark_area().transform_filter('year(datum.date) == 2009').encode(
    x='date:T',
    y='price:Q',
    tooltip=['date:T', 'symbol:N', alt.Tooltip('price:Q', format="$,")],
    color='symbol:N'
)

But you are completely right that upon exporting to both html/svg/png the locale definitions are not included anymore. This might be something more in scope of https://github.com/vega/vl-convert, tagging @jonmmease.

For now we can leave this issue open to track this on the altair side as well. Thanks again for raising!

Cross linking

  • https://github.com/vega/vega-embed/issues/170
  • https://github.com/altair-viz/altair/issues/505

It might be worth adding some convenience functions to Altair and put some examples in the documentation.


Edit. After discovering xReverse, that reverse the x-axis, for example for languages that are read from right-to-left (here ae-EG) trying to see if it is possible to do it as well for other elements of the chart, placing the y-axis on the right and placing the legend on the left (I was not yet able to find out how to place the colors in the legend on the right side of the labels).

.configure_scale(
    xReverse=True
).configure_axisY(
    orient='right'
).configure_legend(
    orient='left'
)
image

mattijn avatar Nov 10 '23 19:11 mattijn

@mattijn, do you have thoughts on what the API for setting locales should look like for the purpose of saving to static images?

I wonder if the embed options set with alt.renderers.set_embed_options should become the default value of the embed_options argument to chart.save, that way you would only need to set it once for the purpose of displaying and saving charts.

jonmmease avatar Nov 10 '23 21:11 jonmmease

That makes very much sense. I just realized there is the possibility to set this setting when saving to html, see https://github.com/altair-viz/altair/blob/main/altair/utils/save.py#L159. But it's not connected to the alt.renderers.set_embed_options. I was wondering here, where are these embed-settings stored? Since there also is this userMeta option, that is utilized by setting a theme using alt.themes.enable('dark').

mattijn avatar Nov 10 '23 21:11 mattijn

I see already: https://github.com/altair-viz/altair/blob/main/altair/utils/html.py#L158, the embed_options are directly set on vega-embed. So it seems there are two routes to accomplish this. I think I've read some discussions where is argued that this type of aesthetics should be part of the specification. I've no real preference here.

mattijn avatar Nov 10 '23 22:11 mattijn

Thanks @mattijn for the explanations and to @jonmmease for the quick feedback. Hope to be more confident with Altair code next time and provide a bit more help.

One last thing: do you think it may be a good idea to add some documentation on how to set formatLocale and timeFormatLocale? Maybe a section in Customizing Renderers page?

MarcoBaroncini avatar Nov 11 '23 16:11 MarcoBaroncini

Hi @MarcoBaroncini, I just published vl-convert-python 1.1.0 that includes support for format and time-format locales. We'll need to make some updates to Altair to have the locales flow through nicely, but here's how you can use it today.

pip install -U vl-convert-python

Make the chart and provide locale objects to alt.renderers.set_embed_options. This makes the locale info display properly in the notebook.

import altair as alt
from vega_datasets import data
from urllib import request
import json

source = data.stocks.url

# fetch & enable Italy format and time-format locale.
url_format_it = 'https://unpkg.com/d3-format/locale/it-IT.json'
url_time_format_it = 'https://unpkg.com/d3-time-format/locale/it-IT.json'

with request.urlopen(url_format_it) as f:
    format_it = json.load(f)

with request.urlopen(url_time_format_it) as f:
    time_format_it = json.load(f)

alt.renderers.set_embed_options(timeFormatLocale=time_format_it, formatLocale=format_it)

chart = alt.Chart(source).mark_area().transform_filter('year(datum.date) == 2009').encode(
    x='date:T',
    y=alt.Y('price:Q', axis=alt.Axis(format="$.0f")),
    tooltip=['date:T', 'symbol:N', alt.Tooltip('price:Q', format="$,")],
    color='symbol:N'
)
chart

visualization

Then save to PNG using vl-convert-python manually. Do this instead of chart.save("chart.png") for now.

import vl_convert as vlc
png = vlc.vegalite_to_png(
    chart.to_dict(), 
    scale=2,
    format_locale=format_it, 
    time_format_locale=time_format_it
)
with open("chart.png", "wb") as f:
    f.write(png)

One last thing: do you think it may be a good idea to add some documentation on how to set formatLocale and timeFormatLocale? Maybe a section in Customizing Renderers page?

Yes, this is definitely something we should document!

jonmmease avatar Nov 11 '23 23:11 jonmmease

@mattijn, let's keep this issue open until we update Altair to pass locale info through to vl-convert in chart.save(), and have some documentation on how to use locales in general.

jonmmease avatar Nov 11 '23 23:11 jonmmease

Hi! I’m sorry I haven’t been able to test it yet. Hope to di it soon. Thanks again for all the help!

MarcoBaroncini avatar Nov 17 '23 14:11 MarcoBaroncini

Hi, I've tested conversion via vl_converter and it worked without problems! Great work!

MarcoBaroncini avatar Nov 24 '23 06:11 MarcoBaroncini

Documentation of this feature request is here: https://altair-viz.github.io/user_guide/customization.html#localization

mattijn avatar May 05 '24 04:05 mattijn