1

I'd like to create a barplot in matplotlib:

fig, ax = plt.subplots()
oldbar = ax.bar(x=ind, height=y, width=width)

I'd then like to pickle this barplot to file (either the dictionary or the axes - I'm not sure which is correct):

pickle.dump(oldbar, file('oldbar.pkl', 'w'))  

I'd then like to reload this file, and then plot the old bar onto alongside a new bar plot, so I can compare them on a single axes:

fig, ax = plt.subplots()
newbar = ax.bar(x=ind, height=y, width=width)
oldbar = pickle.load(file('oldbar.pkl'))

# I realise the line below doesn't work
ax.bar(oldbar) 

plt.show()

Ideally, I'd then like to present them as below. Any suggestions of how I might go about this?

enter image description here

2
  • 1
    You don't really need to save the bar graph, only the data that you feed it, the x and y values. If you pickle the two lists into a file and "unpickle" them latter you can redraw them. Commented Nov 26, 2017 at 18:14
  • Correct. It's not at all clear from the question, why you would need to pickle the plot. This doesn't mean that it's not possible, but it may not be the best approach here. Commented Nov 26, 2017 at 21:50

2 Answers 2

2

You would pickle the figure instead the artists in it.

import matplotlib.pyplot as plt
import numpy as np
import pickle

ind = np.linspace(1,5,5)
y   = np.linspace(9,1,5)
width = 0.3


fig, ax = plt.subplots()
ax.bar(x=ind, height=y, width=width)
ax.set_xlabel("x label")

pickle.dump(fig, file('oldbar.pkl', 'w'))  

plt.close("all")

ind2 = np.linspace(1,5,5)
y2   = np.linspace(8,2,5)
width2 = 0.3


fig2 = pickle.load(file('oldbar.pkl'))
ax2 = plt.gca()

ax2.bar(x=ind2+width, height=y2, width=width2, color="C1")

plt.show()

However pickling the data itself may make more sense here.

import matplotlib.pyplot as plt
import numpy as np
import pickle

ind = np.linspace(1,5,5)
y   = np.linspace(9,1,5)
width = 0.3

dic = {"ind":ind, "y":y, "width":width}

pickle.dump(dic, file('olddata.pkl', 'w'))  

### new data
ind2 = np.linspace(1,5,5)
y2   = np.linspace(8,2,5)
width2 = 0.3

olddic = pickle.load(file('olddata.pkl'))

fig, ax = plt.subplots()
ax.bar(x=olddic["ind"], height=olddic["y"], width=olddic["width"])
ax.bar(x=ind2+olddic["width"], height=y2, width=width2)
ax.set_xlabel("x label")
plt.show()
Sign up to request clarification or add additional context in comments.

Comments

1

Maybe this will help:

import pickle as pkl
import matplotlib.pyplot as plt
import numpy as np


class Data_set(object):
    def __init__(self, x=[], y=[], name='data', pklfile=None,
                 figure=None, axes=None):
        """
        """
        if pklfile is None:
            self.x = np.asarray(x)
            self.y = np.asarray(y)
            self.name = str(name)
        else:
            self.unpickle(pklfile)
        self.fig = figure
        self.ax = axes
        self.bar = None

    def plot(self, width=0, offset=0, figure=None, axes=None):

        if self.fig is None:
            if figure is None:
                self.fig = plt.figure()
                self.ax = self.fig.subplots(1, 1)
            else:
                self.fig = figure
                if axes is None:
                    self.ax = self.fig.subplots(1, 1)
                else:
                    self.ax = axes

        # maybe there's no need to keep track of self.fig, .ax and .bar,
        # but just in case...
        if figure is not None:
            fig_to_use = figure
            if axes is not None:
                ax_to_use = axes
            else:
                ax_to_use = fig_to_use.subplots(1, 1)
        else:
            fig_to_use = self.fig
            ax_to_use = self.ax
        if not width:
            width = (self.x[1]-self.x[0]) / 2.
        self.bar = ax_to_use.bar(x=self.x+offset, height=self.y, width=width)
        return fig_to_use, ax_to_use, self.bar

    def pickle(self, filename='', ext='.pkl'):
        if filename == '':
            filename = self.name
        with open(filename+ext, 'w') as output_file:
            pkl.dump((self.name, self.x, self.y), output_file)

    def unpickle(self, filename='', ext='.pkl'):
        if filename == '':
            filename = self.name
        with open(filename + ext, 'r') as input_file:
            # the name should really come from the filename, but then the
            # above would be confusing? 
            self.name, self.x, self.y = pkl.load(input_file)


class Data_set_manager(object):
    def __init__(self, datasets={}):
        self.datasets = datasets

    def add_dataset(self, data_set):
        self.datasets[data_set.name] = data_set

    def add_dataset_from_file(self, filename, ext='.pkl'):
        self.datasets[filename] = Data_set(name=filename)
        self.datasets[filename].unpickle(filename=filename, ext=ext)

    def compare(self, width=0, offset=0, *args):
        self.fig = plt.figure()
        self.ax = self.fig.subplots(1, 1)
        if len(args) == 0:
            args = self.datasets.keys()
            args.sort()
        n = len(args)
        if n == 0:
            return None, None
        if width == 0:
            min_dx = None
            for dataset in self.datasets.values():
                sorted_x = dataset.x.copy()
                sorted_x.sort()
                try:
                    new_min_dx = np.min(dataset.x[1:] - dataset.x[:-1])
                except ValueError:
                    # zero-size array to reduction operation minimum which
                    # has no identity (empty array)
                    new_min_dx = None
                if new_min_dx < min_dx or min_dx is None:
                    min_dx = new_min_dx
            if min_dx is None:
                min_dx = 1.
            width = float(min_dx) / (n + 1)
            offset = float(min_dx) / (n + 1)
        offsets = offset*np.arange(n)
        if n % 2 == 0:
            offsets -= offsets[n/2] - offset/2.
        else:
            offsets -= offsets[n/2]
        i = 0
        for name in args:
            self.datasets.get(name, Data_set()).plot(width=width,
                                                     offset=offsets[i],
                                                     figure=self.fig,
                                                     axes=self.ax)
            i += 1
        self.ax.legend(args)
        return self.fig, self.ax


if __name__ == "__main__":
    # test saving/loading
    name = 'test'
    to_pickle = Data_set(x=np.arange(10),
                         y=np.random.rand(10),
                         name=name)
    to_pickle.pickle()
    unpickled = Data_set(pklfile=name)
    print unpickled.name == to_pickle.name

    # test comparison
    blorg = Data_set_manager({})
    x_step = 1.
    n_bars = 4  # also try an odd number
    for n in range(n_bars):
        blorg.add_dataset(Data_set(x=x_step * np.arange(n_bars),
                                   y=np.random.rand(n_bars),
                                   name='teste' + str(n)))
    fig, ax = blorg.compare()
    fig.show()

It should work with both even and odd number of bars: even number of bars odd number of bars

And as long as you keep a record of the names you've used (tip:look in the folder where you are saving them) you can reload the data and compare it with the new one.

More checks could be made (to make sure the file exists, that the x axis is something that can be subtracted before trying to do so, etc.), and it could also use some documentation and proper testing - but this should do in a hurry.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.