altair icon indicating copy to clipboard operation
altair copied to clipboard

Save to PNG and SVG fails on charts with images in them

Open lazarillo opened this issue 4 years ago • 4 comments

Problem

When saving ~~a multi-plot~~ an image-based plot ~~created in various means~~, it cannot save in PNG or SVG formats

Details

myplot = alt.hconcat(line_plot, logo)
myplot.save('chart.png') # or 'chart.svg'

fails with the following traceback:

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
 in 
     15 
     16 myplot = alt.hconcat(line_plot, logo)
---> 17 myplot.save('chart.png') # or 'chart.svg'
     18 #line_plot2 | logo
     19 

/usr/local/Caskroom/miniconda/base/envs/sdfe/lib/python3.8/site-packages/altair/vegalite/v4/api.py in save(self, fp, format, override_data_transformer, scale_factor, vegalite_version, vega_version, vegaembed_version, **kwargs)
    474         if override_data_transformer:
    475             with data_transformers.disable_max_rows():
--> 476                 result = save(**kwds)
    477         else:
    478             result = save(**kwds)

/usr/local/Caskroom/miniconda/base/envs/sdfe/lib/python3.8/site-packages/altair/utils/save.py in save(chart, fp, vega_version, vegaembed_version, format, mode, vegalite_version, embed_options, json_kwds, webdriver, scale_factor, **kwargs)
    110         write_file_or_filename(fp, mimebundle["text/html"], mode="w")
    111     elif format in ["png", "svg"]:
--> 112         mimebundle = spec_to_mimebundle(
    113             spec=spec,
    114             format=format,

/usr/local/Caskroom/miniconda/base/envs/sdfe/lib/python3.8/site-packages/altair/utils/mimebundle.py in spec_to_mimebundle(spec, format, mode, vega_version, vegaembed_version, vegalite_version, **kwargs)
     58                 "see http://github.com/altair-viz/altair_saver/".format(fmt=format)
     59             )
---> 60         return altair_saver.render(spec, format, mode=mode, **kwargs)
     61     if format == "html":
     62         html = spec_to_html(

/usr/local/Caskroom/miniconda/base/envs/sdfe/lib/python3.8/site-packages/altair_saver/_core.py in render(chart, fmts, mode, embed_options, method, **kwargs)
    255         Saver = _select_saver(method, mode=mode, fmt=fmt)
    256         saver = Saver(spec, mode=mode, embed_options=embed_options, **kwargs)
--> 257         mimebundle.update(saver.mimebundle(fmt))
    258 
    259     return mimebundle

/usr/local/Caskroom/miniconda/base/envs/sdfe/lib/python3.8/site-packages/altair_saver/savers/_saver.py in mimebundle(self, fmts)
     88                 vegalite_version=self._package_versions["vega-lite"],
     89             )
---> 90             bundle[mimetype] = self._serialize(fmt, "mimebundle")
     91         return bundle
     92 

/usr/local/Caskroom/miniconda/base/envs/sdfe/lib/python3.8/site-packages/altair_saver/savers/_node.py in _serialize(self, fmt, content_type)
    112 
    113         if self._mode == "vega-lite":
--> 114             spec = self._vl2vg(spec)
    115 
    116         if fmt == "vega":

/usr/local/Caskroom/miniconda/base/envs/sdfe/lib/python3.8/site-packages/altair_saver/savers/_node.py in _vl2vg(self, spec)
     63         vl2vg = exec_path("vl2vg")
     64         vl_json = json.dumps(spec).encode()
---> 65         vg_json = check_output_with_stderr(
     66             [vl2vg], input=vl_json, stderr_filter=self._stderr_filter
     67         )

/usr/local/Caskroom/miniconda/base/envs/sdfe/lib/python3.8/site-packages/altair_saver/_utils.py in check_output_with_stderr(cmd, shell, input, stderr_filter)
    196     """
    197     try:
--> 198         ps = subprocess.run(
    199             cmd,
    200             shell=shell,

/usr/local/Caskroom/miniconda/base/envs/sdfe/lib/python3.8/subprocess.py in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    510         retcode = process.poll()
    511         if check and retcode:
--> 512             raise CalledProcessError(retcode, process.args,
    513                                      output=stdout, stderr=stderr)
    514     return CompletedProcess(process.args, retcode, stdout, stderr)

CalledProcessError: Command '['/usr/local/Caskroom/miniconda/base/envs/sdfe/bin/vl2vg']' returned non-zero exit status 1.

If I try to save in either JSON or HTML, it works fine. If I try to save just one of the plots (ie, in this case just saving line_plot), it works.

I have not delved too deeply because I do not understand Altair's (or Vega's) inner workings well enough, but I see that it is actually altair_saver that is failing, when it calls the vl2vg executable.


My computer details:

  • Mac OS X Catalina, powerbook
  • Jupyter or via normal Python script

Reproduce

I was able to reproduce with any of the following combinations:

Multi-Plot Type:

  • HConcatChart
  • VConcatChart
  • LayerChart

Save File Type:

  • SVG
  • PNG

Again, HTML and JSON are able to run without a problem. I looked at the rendered solution (eg, opening up the HTML file in a browser), and they looked fine.

lazarillo avatar Jul 14 '20 10:07 lazarillo

Actually, when digging deeper, it seems to me, this is not due to multi-charts, but instead due to ingesting images. The other chart in my example above - the chart labelled logo, is actually an image (the logo of a company).

If I try to save a "chart" with just the logo, it also fails. All else above is correct: it only fails on SVG and PNG, etc.

lazarillo avatar Jul 14 '20 11:07 lazarillo

I've seen this before reported on Vega-Lite, but I can't find the issue reference right now.

jakevdp avatar Jul 14 '20 16:07 jakevdp

Hi @lazarillo, could you able to find the solution? I am facing the same issue is there any work around for this problem? Thank you very much.

arjunkumarp9 avatar May 01 '21 08:05 arjunkumarp9

Hi @arjunkumarp9 , I am sorry. I have not been using Altair much in the last few months. I did not find a solution.

I am happy to help solve the issue, if a core member of the Altair project can help point me to where the problem might lie. I don't want to comb through everything in that long stack trace to understand the problem without at least some help from an expert. :)

lazarillo avatar May 04 '21 14:05 lazarillo

Saving an Altair chart with remote and local images should work well with vl-convert instead of altair-saver, see https://altair-viz.github.io/user_guide/saving_charts.html#png-svg-and-pdf-format. Feel free to reopen the issue and provide a reproducible code example in case this does not solve it for you!

binste avatar May 26 '23 16:05 binste