conda update spyder
(or pip
, if not using Anaconda)jupyter qtconsole
(if console-related)spyder --reset
The newly add feature: plots has problems with saving the plotted image produced by Plotly.
When using the Save Image As.. button, the saved image will have the default size of 700x450 px. This cannot be changed even if the size is specified otherwise in plotly API.
If the image is saved by Plotly itself, the image will have a correct size (ex. 800x600 px).
The saved image will have a default size (i.e. 700x450) which cannot be changed.
PASTE TRACEBACK HERE
Reproducing the problem:
import plotly.graph_objects as go
import os
script_path = os.path.dirname(os.path.realpath(__file__))
animals=['giraffes', 'orangutans', 'monkeys']
fig = go.Figure([go.Bar(x=animals, y=[20, 14, 23])])
fig.update_layout(height = 600,
width = 800,)
fig.show()
fig.write_image(script_path + '/fig.png')
Please post an example of an image generated by Plotly to take a look at it.
If you could provide also some code that can reproduce the problem, that would be helpful, thanks.
Here is a simple code from Plotly that demonstrates the problem.
The saved fig.png is 800x600, which is the set size. But the figure saved from Spyder plot "Save as ..." button still has the default size of 700x450.
import plotly.graph_objects as go
import os
script_path = os.path.dirname(os.path.realpath(__file__))
animals=['giraffes', 'orangutans', 'monkeys']
fig = go.Figure([go.Bar(x=animals, y=[20, 14, 23])])
fig.update_layout(height = 600,
width = 800,)
fig.show()
fig.write_image(script_path + '/fig.png')
Here is a simple code from Plotly that demonstrates the problem.
The saved fig.png is 800x600, which is the set size. But the figure saved from Spyder plot "Save as ..." button still has the default size of 700x450.
Excellent, thanks. I'll take a look at this and report back.
From the documentation https://plot.ly/python/renderers/, I think you need to pass the width
and height
value to the renderer. One way to do it is to pass the width
and height
as arguments of the show method :
```
fig.show(width=800, height=600)
````
Then your figures are going to be plotted in the IPython console and the Plots plugin with the right size.
@ccordoba12 I don't know much about Plotly
, but I think it may not be a Spyder problem. It seems to be how Plotly
is designed and it is working like that also in Jupyter Notebooks when using either the 'png' or 'svg' renderer, but I might be wrong.
But if we would like to support this in Spyder, I think we would have to write our own renderer.
Can we do this in our side and register it when Plotly is imported? Or how does this work @jnsebgosselin?
Can we do this in our side and register it when Plotly is imported? Or how does this work @jnsebgosselin?
I don't know, I'll take a look and report back.
Ok, so this is pretty simple actually. Basically, when plotly gets imported, if it detects that it is done from Spyder, it will assign the svg
renderer by default.
The svg
renderer, as well as the png
renderer, is defined here:
By design, the svg
and png
renderers do not use the width and height values that were set in the layout of the figure to produce their static image. You need to pass those values again as independent arguments to the renderer directly.
To have a better integration of Plotly inside Spyder, we would simply need to create our own renderer and add it to the list of available renderers when Plotly gets imported.
For testing purpose, I've created this renderer that inherits from the PngRenderer
where I override the to_mimebundle
method to assign the values of the width
and height
of the renderer to the values saved in the layout of the figure, so that the size of the png produced is automatically updated when updating the layout of the figure.
import plotly.graph_objects as go
from plotly.io._base_renderers import PngRenderer
from plotly.io._renderers import renderers
class SpyderRenderer(PngRenderer):
def to_mimebundle(self, fig_dict):
self.width = fig_dict['layout']['width']
self.height = fig_dict['layout']['height']
return super().to_mimebundle(fig_dict)
renderers["spyder"] = SpyderRenderer(height=450, width=700)
renderers.default = "spyder"
# %%
animals = ['giraffes', 'orangutans', 'monkeys']
fig = go.Figure([go.Bar(x=animals, y=[20, 14, 23])])
fig.update_layout(autosize=False, width=800, height=500)
fig.show()
This is pretty nice @jnsebgosselin! I think we should add this to spyder-kernels
, like this:
You need to add some lines similar to these ones:
to register the renderer at startup.
Then you need to create a method in our kernel, similar to this one
with the code you posted above to do the actual job (but inside a try/except to account for the possibility of not having Plotly installed).