Open jsignell opened 5 years ago
Thanks @jsignell, here are some API entry points in plotly.py (as of version 4, which is in release candidate stage at the moment) that might be candidates for inclusion in a spec (and definitely open to renaming if the concepts make sense but other names are preferred). I've numbered the ideas to aid discussion.
1) The top-level figure class has a .show()
method that can be called without arguments to display the figure as a side-effect.
2) The optional renderer
kwarg can be used to override the current default renderer. e.g.:
fig.show(renderer='png')
to display the figure as a static png image/fig.show(renderer='browser')
to display the figure in a browser tab. This works in non-jupyter/IPython contexts.3) When figures are displayed in an ipython context, we use the _ipython_display_
protocol to call fig.show()
.
Figures have write_*
and to_*
methods for exporting/converting figures. We don't currently have a .save
method because it would be a bit ambiguous in our case.
4) The write_*
methods write the figure to a file (or writable object) and return None
. If the first argument to a write_*
method is a string, then it is treated as a local file path that can be opened with the standard Python open
function. Otherwise, the object passed as the first argument is assumed to be writable (i.e. to have a .write
method). Beyond the first required argument, each export approach can have its own optional configuration kwargs
. For example
.write_image('/path/to/output.png')
.write_image('/path/to/output.png', width=800, height=600)
.write_json('/path/to/output.json')
.write_html('/path/to/output.html')
.write_html('/path/to/output.html', include_plotlyjs='cdn')
Or with a writable object
with open('/path/to/output.html', 'w') as f:
fig.write_html(f, include_plotlyjs='cdn')
5) The to_*
methods return an in-memory representation of the exported figure and don't write any files. They should have the same signature as the corresponding .write
method without the first file argument. Ideally, these methods can be called with no arguments and reasonable defaults are chosen. For example:
.to_image
returns the static image bytes
object..to_html
returns a string containing the HTML representation of the figure..to_json
returns a string containing the JSON representation of the figure.6) Every object in the figure hierarchy (plotly.py calls these "graph objects") has a .figure
property that returns the parent figure, if any, or None
if the graph object does not belong to a figure.
That sounds really cool! I'd go further and say that such a spec should get a name and revision and have an associated repo in the pyviz organization, with automated tests that define whether each library meets the spec up to revision X (which can be shown in a status page like pyviz.org/tools.html). Seems like a great way to use the pyviz organization!
I'd also propose that the spec include support for the various IPython rich display methods, i.e. repr_html, repr_png, etc. so that each library could be treated the same in how things are displayed inline.
Very interesting idea. Always a big fan of consistency. I have some questions though: Would this spec only apply to plotting interfaces of a library that provide a specific "figure" object? Do most plotting or visualization libraries provide that? What about generic visualizations or animation that may or may not be a "plot" (axes, ticks, etc)?
If a library has every method, but doesn't have a JSON representation for its figures (so no to_json
) does it now look "less complete" on the PyViz site because it can't implement every piece of the spec?
I would say that if a given operation doesn't make sense for that library, then it could satisfy the spec by simply having that method return a message to that effect ("JSON support not available in x-viz").
I don't think any of the operations involved here would require axes, ticks, etc., just a viewable representation.
I'm not sure about the semantics required of "figure"; to me that would just be "some object that has a visible representation but which can also be saved, exported, etc.".
This is a great idea. I'm happy to implement in Altair as soon as there's consensus on the spec.
Another thing that might be useful: a uniform way to enable various libraries in jupyter notebook & jupyterlab. For example, matplotlib has %matplotlib inline
, bokeh has bokeh.output_notebook()
, altair has alt.renderers.enable('notebook')
, etc. If every library agreed to define something like %enable_{LIBNAME}
, things would be much more predictable for the user.
A uniform way to enable various libraries in jupyter is a great idea, but I would argue that such a specification should not rely on magics. We routinely use Jupyter notebooks as literate programming environments for developing and sharing code that we need to be usable both within and outside of jupyter; e.g. with many of our notebooks we can do panel serve nb.ipynb
to launch them as standalone dashboards without Jupyter involved at all. We can always add special cases to deal with magics, but I don't think that's a good idea; I greatly prefer just to have a normal Python call that can register things with Jupyter if it's available but doesn't otherwise cause syntax errors (if not skipped) or missing functionality (if skipped) outside of Jupyter/IPython.
Sure, makes sense.
I wrote up these initial ideas at https://github.com/pyviz/spec/tree/01_02_03 and made you all admin of that repo. Please comment over there. Ping me if you want to be part of that discussion and haven't been added.
There was discussion at SciPy sprints about having a shared API for accessing objects from various plotting libraries. We think there could be a spec for common actions such as
save
,show
,html_repr
. This issue is to start that discussion. @munkm @tacaswell @jonmmease