3
votes

I want to create a separate class in Python (v2.7.12) that will be saving plots to files (here 'test.eps') and use some labels, titles etc. given by the user as arguments (*args and **kwargs).

The background story is that I have to create plots for scientific data an I want Python class to be simple and fit to my case.

import matplotlib.pyplot as plt 

# class of figures for channel flow
# with one subfigure
class Homfig(plt.Figure):

    # *args: list of plot features for ax1.plot
    #     (xdata,ydata,str linetype,str label)
    # **kwargs: list of axes features for ax1.set_$(STH)
    #     possible keys:
    #     title,xlabel,ylabel,xlim,ylim,xscale,yscale

    def __init__(self,*args,**kwargs):

        self.arg_lst = []
        for key,value in kwargs.iteritems():
            setattr(self,key,value)
            self.arg_lst.append(key)
        i=0
        for value in args:
            setattr(self,'plot'+str(i),value)
            i=i+1
        print 'list of attributes set: ', self.__dict__.keys()


    def hdraw(self):
        fig2=plt.figure()
        ax1 = fig2.add_subplot(111)
        for key in self.arg_lst:
            setattr(ax1,'set_'+key,getattr(self,key))
            print getattr(ax1,'set_'+key)


        ax1.plot([0, 1, 2, 3, 4], [0, 1, 2, 3, 4], label="Test", color='g')
        leg = ax1.legend(loc=4)
        plt.savefig('test.eps')
        plt.clf()

ff = Homfig(title='very important title',xlabel="xxx",ylabel="yyy")
ff.hdraw()

Method "hdraw" should be plotting my data and saving it to a file. The code does not give error message, but no change in plot title or axes labels is seen. Attributes are given to ax1 and the plot is drawn.

Can you help me understand this issue and find a solution?

I run the script in console: python homfigs.py

and the output is: list of attributes set: ['title', 'ylabel', 'xlabel', 'arg_lst'] yyy xxx very important title

1

1 Answers

3
votes

Problem:

Note the difference between

ax.set_title = "some title"

and

ax.set_title("some title")

The first changes the class attribute set_title from a method to a string. The second uses the class method set_title, which sets the title of the axes.

Using setattr is equivalent to the first case. So you're destroying the useful classmethod by overwriting it with a string. After that you (a) cannot use the method anymore (b) still haven't set the title yet (and cannot even do so anymore, because of (a)).

Solution:

While I'm not convinced by the structure of the class you're using, a way to go can be to acutally call the respective methods

for key in self.arg_lst:
    getattr(ax1,'set_'+key)(getattr(self,key))

Recommendation:

If I may I would recommend not to store the properties in an attribute of the Figure class. There seems no need to subclass Figure anyways. Instead you can just store the args and kwargs in a class variable; e.g. kwargs is already the dictionary with the values to use as properties for the plot, such that there is no need for self.arg_lst to even exist.

import matplotlib.pyplot as plt 

# class of figures for channel flow
# with one subfigure
class Homfig():

    # *args: list of plot features for ax1.plot
    #     (xdata,ydata,str linetype,str label)
    # **kwargs: list of axes features for ax1.set_$(STH)
    #     possible keys:
    #     title,xlabel,ylabel,xlim,ylim,xscale,yscale

    def __init__(self,*args,**kwargs):
        self.args = args
        self.kwargs = kwargs
        self.fig = plt.figure()
        self.ax = self.fig.add_subplot(111)

        for key, val in self.kwargs.iteritems():
            getattr(self.ax,'set_'+key)(val)

    def hdraw(self):
        self.ax.plot([0, 1, 2, 3, 4], [0, 1, 2, 3, 4], label="Test", color='g')
        leg = self.ax.legend(loc=4)

    def save(self, name="text"):
        self.fig.savefig(name+'.eps')


ff = Homfig(title='very important title',xlabel="xxx",ylabel="yyy")
ff.hdraw()
ff.save()
plt.show()