has2k1 / plotnine

A Grammar of Graphics for Python
https://plotnine.org
MIT License
4k stars 213 forks source link

Error when pickling an object obtained by draw() #729

Closed lucazav closed 9 months ago

lucazav commented 10 months ago

I created a plot in the following way:

import os
import pickle
import pandas as pd
from plotnine import (
    options, theme_tufte, ggplot, aes, geom_bar,
    geom_text, after_stat, labs
)

dataset_url = 'http://bit.ly/titanic-dataset-csv'
df = pd.read_csv(dataset_url)

options.dpi = 300

p = (
        ggplot(df) 
        + aes(x='Pclass', fill="factor(Pclass)") 
        + geom_bar()
        + geom_text(
            aes(label = after_stat('count')),
            stat = 'count',
            nudge_x = -0.14,
            nudge_y = 0.125,
            va = 'bottom',
            size = 8
        )
        + geom_text(
            aes(label = after_stat('prop*100'), group=1),
            stat = 'count',
            nudge_x = 0.14,
            nudge_y = 0.125,
            va = 'bottom',
            format_string = '({:.1f}%)',
            size = 8
        )
        + labs(title='Passenger Count by Class',
               x='Class', y='Count', fill='Class')
        + theme_tufte()
)

Now I'm trying to pickle the related Matplotlib figure as follows:

mplt = p.draw()

project_folder = r'<my-folder>'

pickle.dump( mplt, open(os.path.join(project_folder, "mplt.pkl"), "wb") )

But I'm getting the following error:

NotImplementedError: Sorry, pickling not yet supported. See https://github.com/pydata/patsy/issues/26 if you want to help.

I tried to pickle a plot generated directly with Matplotlib and everything works fine.

What's wrong with the Matplotlib figure given by the ggplot draw() method?

lucazav commented 8 months ago

@has2k1 I installed the developer version of plotnine in my conda environment on Windows using:

pip install "plotnine @ https://github.com/has2k1/plotnine/archive/master.zip"

Then I tried the upon code and I'm getting the following error:

cannot pickle 'KeyedRef' object

Is there anything wrong in my installation?

has2k1 commented 8 months ago

This works for me.

from plotnine import *
from plotnine.data import mtcars

def test_pickle(obj):
    import io
    import pickle

    with io.BytesIO() as f:
        pickle.dump(obj, f)
        f.seek(0)
        unpickled_obj = pickle.load(f)

    return unpickled_obj

p  = (
 ggplot(mtcars, aes("wt", "mpg"))
 + geom_point()
)

fig = p.draw()

test_pickle(fig)
test_pickle(p)
lucazav commented 8 months ago

My fault, I was using dill instead of pickle. Now it's working like a charm with pickle.