Skip to content

cannot write plotly figure to file with pickle #579

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
latorrefabian opened this issue Oct 14, 2016 · 11 comments
Closed

cannot write plotly figure to file with pickle #579

latorrefabian opened this issue Oct 14, 2016 · 11 comments
Assignees
Milestone

Comments

@latorrefabian
Copy link

import plotly.graph_objs as go
import pickle

file = open('myfile.pkl', 'wb')
a = go.Scatter(x=[1,2,3], y=[4,5,6])
figure = go.Figure(data = [a])
pickle.dump(figure, file)

Traceback (most recent call last):
File "", line 1, in
File "/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1376, in dump
Pickler(file, protocol).dump(obj)
File "/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump
self.save(obj)
File "/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 306, in save
rv = reduce(self.proto)
File "xxx/bin/../lib/python2.7/copy_reg.py", line 84, in _reduce_ex
dict = getstate()
TypeError: 'NoneType' object is not callable

@tejaslodaya
Copy link

Is this issue resolved?

@dmarx
Copy link

dmarx commented Aug 15, 2017

👍

1 similar comment
@maegul
Copy link

maegul commented Aug 15, 2017

👍

@dmarx
Copy link

dmarx commented Aug 15, 2017

I figured out a workaround: instead of pickling the figure, serialize it to JSON.

import numpy as np
import json
from plotly.utils import PlotlyJSONEncoder
from plotly.offline import download_plotlyjs, init_notebook_mode, iplot
import plotly.graph_objs as go
init_notebook_mode()

def plotlyfig2json(fig, fpath=None):
    """
    Serialize a plotly figure object to JSON so it can be persisted to disk.
    Figure's persisted as JSON can be rebuilt using the plotly JSON chart API:

    http://help.plot.ly/json-chart-schema/

    If `fpath` is provided, JSON is written to file.

    Modified from https://github.com/nteract/nteract/issues/1229
    """

    redata = json.loads(json.dumps(fig.data, cls=PlotlyJSONEncoder))
    relayout = json.loads(json.dumps(fig.layout, cls=PlotlyJSONEncoder))

    fig_json=json.dumps({'data': redata,'layout': relayout})

    if fpath:
        with open(fpath, 'wb') as f:
            f.write(fig_json)
    else:
        return fig_json

def plotlyfromjson(fpath):
    """Render a plotly figure from a json file"""
    with open(fpath, 'r') as f:
        v = json.loads(f.read())

    fig = go.Figure(data=v['data'], layout=v['layout'])
    iplot(fig, show_link=False)

###################
## Minimial demo ##
###################

n = 1000
trace = go.Scatter(
    x = np.random.randn(n),
    y = np.random.randn(n),
    mode = 'markers')

fig = go.Figure(data=[trace])

plotlyfig2json(fig, 'myfile.json')
plotlyfromjson('myfile.json')

@cbarquest
Copy link

Not sure if this is correct, but I wanted to share in case it could help someone else since it has worked for us so far. I added the following code to plotly's graph_objs.py PlotlyBase class :

#Pickleablize PlotlyBase
def __reduce__(self):
    return (PlotlyBase, (self.progress_int,))

(file located here: /lib/python2.7/site-packages/plotly/graph_objs/graph_objs.py)
We've had to make plotly figs pickleable for using flask sessions. I originally got this solution from: https://stackoverflow.com/questions/30699391/python-how-can-i-make-this-un-pickleable-object-pickleable

@dmarx
Copy link

dmarx commented Sep 13, 2017

Thanks for bumping @cbarquest, I came up with a different workaround myself. In case people have issues with your solution, here's mine (copied from my post on SO:

Since I wasn't able to get pickle working, The solution I came up with was to serialize the fig object to JSON, and then use plotly's "json chart schema" to build the plot from JSON.

import numpy as np
import json
from plotly.utils import PlotlyJSONEncoder
from plotly.offline import download_plotlyjs, init_notebook_mode, iplot
import plotly.graph_objs as go
init_notebook_mode()

def plotlyfig2json(fig, fpath=None):
    """
    Serialize a plotly figure object to JSON so it can be persisted to disk.
    Figure's persisted as JSON can be rebuilt using the plotly JSON chart API:

    http://help.plot.ly/json-chart-schema/

    If `fpath` is provided, JSON is written to file.

    Modified from https://github.com/nteract/nteract/issues/1229
    """

    redata = json.loads(json.dumps(fig.data, cls=PlotlyJSONEncoder))
    relayout = json.loads(json.dumps(fig.layout, cls=PlotlyJSONEncoder))

    fig_json=json.dumps({'data': redata,'layout': relayout})

    if fpath:
        with open(fpath, 'wb') as f:
            f.write(fig_json)
    else:
        return fig_json

def plotlyfromjson(fpath):
    """Render a plotly figure from a json file"""
    with open(fpath, 'r') as f:
        v = json.loads(f.read())

    fig = go.Figure(data=v['data'], layout=v['layout'])
    iplot(fig, show_link=False)

## Minimial demo ##

n = 1000
trace = go.Scatter(
    x = np.random.randn(n),
    y = np.random.randn(n),
    mode = 'markers')

fig = go.Figure(data=[trace])
#iplot(fig)
plotlyfig2json(fig, 'myfile.json')
plotlyfromjson('myfile.json')

@ColasDroin
Copy link

So, there's still no fix for Pickle serialization?

cbarquest solution didn't work for me

#Pickleablize PlotlyBase
def __reduce__(self):
    return (PlotlyBase, (self.progress_int,))

-> return TypeError: object() takes no parameters when trying to load the figure...

@cbarquest
Copy link

We ran into this problem in the context of writing plotly figures into session data (a pickled file). We've since moved away from this approach, however, I do remember once seeing an error like @ColasDroin's. It went away after removing our code's and plotly's __pycache__ files and deleting old session files.

If this doesn't work for you, potentially you could try @dmarx's approach? We're now going this way as well, in our case passing data and layout separately as dictionaries and then having a javascript function assemble the final plotly figure. Hope this helps!

@ColasDroin
Copy link

Well I wanted to avoid json serialization because I wanted to keep the code as simple as possible, but in the end this is the approach I chose too, and it works. Thanks for the help!

@Teoretic6
Copy link

@dmarx thank you very much for your solution! Saved me a lot of time.

One small note though - writing to a file:

with open(fpath, 'wb') as f:
    f.write(fig_json)

didn't work when I tested it, because here we are writing string data, not binary (failed on Python 3.6,
I believe it fails on other versions as well)

If you change it to simple 'w' mode:

with open(fpath, 'w') as f:
    f.write(fig_json)

everything works as a charm.

Nevertheless thank you once again for your solution!

@jonmmease
Copy link
Contributor

Closed by #1191 with the introduction or proper deepcopy/pickle support for figures and graph_objs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants