holoviz / panel

Panel: The powerful data exploration & web app framework for Python
https://panel.holoviz.org
BSD 3-Clause "New" or "Revised" License
4.63k stars 505 forks source link

Image export issue with panel 0.8 #1080

Closed jlstevens closed 4 years ago

jlstevens commented 4 years ago

The .save method to export to .png doesn't seem to be working right now in panel 0.8, at least for some layouts.

Steps to reproduce are the same as in #1077 with a few extra steps (note, these issues aren't related otherwise!):

  1. Clone master from https://github.com/holoviz/panel (currently at 86aa4d0086978880f60b50477adcc8496a279b9f)
  2. cd attractors
  3. anaconda-project prepare (you need anaconda-project installed)
  4. conda activate envs/default
  5. conda install -c pyviz panel=0.8 bokeh=1.4
  6. jupyter notebook and run attractors_panel.ipynb
  7. Grab a handle on the final dashboard layout in the notebook.
  8. Call handle.save('image.png')

Traceback:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
 in 
----> 1 test.save('broken.png')

~/Desktop/development/panel/panel/viewable.py in save(self, filename, title, resources, template, template_variables, embed, max_states, max_opts, embed_json, json_prefix, save_path, load_path)
    476         return save(self, filename, title, resources, template,
    477                     template_variables, embed, max_states, max_opts,
--> 478                     embed_json, json_prefix, save_path, load_path)
    479 
    480     def server_doc(self, doc=None, title=None):

~/Desktop/development/panel/panel/io/save.py in save(panel, filename, title, resources, template, template_variables, embed, max_states, max_opts, embed_json, json_prefix, save_path, load_path)
     94     if isinstance(filename, string_types):
     95         if filename.endswith('png'):
---> 96             save_png(model, filename=filename)
     97             return
     98         if not filename.endswith('.html'):

~/Desktop/development/panel/panel/io/save.py in save_png(model, filename)
     40 
     41     webdriver = state.webdriver
---> 42     export_png(model, filename, webdriver=webdriver)
     43 
     44 #---------------------------------------------------------------------

~/Desktop/development/misc/topics/examples/attractors/envs/default/lib/python3.7/site-packages/bokeh/io/export.py in export_png(obj, filename, height, width, webdriver, timeout)
    101 
    102     if image.width == 0 or image.height == 0:
--> 103         raise ValueError("unable to save an empty image")
    104 
    105     image.save(filename)

ValueError: unable to save an empty image

I ran git bisect to tracks the issue down to this commit:

git bisect good
7d409f53cdbcda9358b5d6eadb05a518c1e7f6f8 is the first bad commit
commit 7d409f53cdbcda9358b5d6eadb05a518c1e7f6f8
Author: Philipp Rudiger <prudiger@anaconda.com>
Date:   Thu Dec 19 05:09:45 2019 +0100
    Use optimized HTML model consistently (#888)
    * Use optimized HTML model consistently
    * Fixed Image panes
    * Updated tests
:040000 040000 97b619fc3c2c5ee4ffb3b180c5d31d6c01517d9a 3ea524f9d4a18b7aa4ba71c52e57a1069e96e1d4 M  panel
philippjfr commented 4 years ago

This is likely not actually a new issue but affects more output now because since that PR more objects are rendered with the HTML pane. Internally the HTML model uses the DOMParser to parse the HTML that is being rendered which is necessary to safely instantiate script tags for instance. The problem with that is that PhantomJS does not support parsing HTML using the DOMParser so you get an error like this:

WARNING:bokeh.io.export:TypeError: null is not an object (evaluating '(new DOMParser).parseFromString(e,"text/html").documentElement')

There's two possible fixes, during static png export we can simply swap out the HTML bokeh model for the Div bokeh model which will render the majority of content. Even if we do nothing though this will just work when bokeh 2.0 is released which uses chromedriver instead of PhantomJS.

jbednar commented 4 years ago

Given that bokeh 2 is python 3 only, I think we should fix this in a bugfix release now, before depending on bokeh 2