0

I am trying to write a simple Python matplotlib plotting Class that will set up formatting of the plot as I would like. To do this, I am using a class and a subclass. The parent generates an axis and figure, then sets all axis properties that I would like. Then the child generates the plot itself - scatter plot, line, etc. - and saves the plot to an output file.

Here is what I have come up with for the purposes of this question (the plot itself is based on this code):

import matplotlib.pyplot as plt
import numpy as np

class myplot():

    def __init__(self,dims,padd):
        self.fig = plt.figure(figsize=(8.5, 11))
        self.ax = self.fig.add_axes(dims)
        self.pad = padd

    def ax_prop(self):
        self.ax.set_axisbelow(True)
        self.ax.tick_params(axis='x', pad=self.pad, which='both')

class plotter(myplot):
    def __init__(self,dims,padd,x,y):
        myplot.__init__(self,dims,padd)
        self.x = x
        self.y = y

    def mk_p(self):
        self.ax.plot(self.x, self.y, linestyle = '-')
        plt.savefig('Outfile.png', facecolor=self.fig.get_facecolor(), dpi = 300)
        plt.show()

if __name__ == "__main__":
    x = np.arange(0.0, 2.0, 0.01)
    y = np.sin(2*np.pi*x)
    propr = [0.60, 0.2, 0.2, 0.25]; padding =5 
    plt_instance = myplot(propr,padding)
    plt_instance.ax_prop()
    pl_d = plotter(propr,padding,x,y)
    pl_d.mk_p()

I'm tying to base this on the following:

The child must have all the properties of the parent.

Therefore, the child class plotter() must inherit the:

ax, and all its customized properties
fig

from the parent (myplot()) class. The following may change in the Child class:

  1. type of plot - scatter, line, etc.
  2. any properties of the type of plot - markersize, linestyle, etc.

but the matplotlib figure and axis objects (fig,ax) will always be required before plotting an input set of numbers.

Question:

Is this a correct usage of Python inheritance or is the child class superfluous in this case? If so, was there a place where the reasoning for a subclass was not consistent with object oriented programming (I'm having difficulty convincing myself of this)?

8
  • 1
    Why not just create a function that creates the figure and a second function which draws on it? In general you should prefer composition to inheritance. Inheritance should imply an "is a" relationship. Is "plotter" a "myplot"? Commented Jul 22, 2016 at 20:17
  • No. it is not. Yeah, that pretty much answers my question. Commented Jul 22, 2016 at 23:07
  • Thanks for the reply. You basically just explained right here. I didn't understand this concept. Commented Jul 22, 2016 at 23:08
  • Also you should be inheriting your classes from object if they don't have a specific base type. In Python 3 you can omit the parentheses after the name of the class entirely if you like. Commented Jul 25, 2016 at 15:21
  • 1
    You should use class myplot(object). Not subclassing from object will declare an old-style class, which is something you do not want. Old-style classes were removed in Python 3, but some people still inherit from object, so it is optional. Commented Jul 25, 2016 at 16:05

2 Answers 2

1

I think the main issue is that your subclass violates the Liskov Substitution Principle. Also see here for nice pictures of SOLID principles. You can't substitute an instance of myplot for plotter, since plotter's method signature is different. You should be able to substitute in a subclass instead of the base class. Because the signature is different, you cannot.

Sign up to request clarification or add additional context in comments.

8 Comments

Yes, I get it now. I just missed it totally before. Thanks.
Child classes extending the functionality of a base class isn't a violation of LSP.
@ZacCrites: You are correct. I have fixed the reasoning (His subclass still violates the LSP principle, but not for the reason I originally gave).
@Gerrat Is it? The constructors have different signatures, but there's nothing wrong with that. Do you mean that he's calling mk_p on an instance of plotter when he should really only be calling methods defined on the base class interface?
@ZacCrites: The constructors do have different signatures, and there is something wrong with that. Because of that fact, you cannot use a plotter in place of a myplot (which is what LSP demands - see either article I linked, or any other resource). The extra mk_p method is ok - it wouldn't affect the substitution.
|
1

You should prefer composition to inheritance wherever possible. I would make a function that creates the plot and another that draws on it.

def create_plot(dims, pad):
    fig = plt.figure(figsize=(8.5, 11))
    ax = fig.add_axes(dims)
    ax.set_axisbelow(True)
    ax.tick_params(axis='x', pad=pad, which='both')
    return fig

def draw_plot(fig, x, y, outfile):
    fig.axes[0].plot(x, y, linestyle='-')
    plt.savefig(outfile, facecolor=fig.get_facecolor(), dpi=300)
    plt.show()

if __name__ == '__main__':
    x = np.arange(0.0, 2.0, 0.01)
    y = np.sin(2 * np.pi * x)
    dims = [0.60, 0.2, 0.2, 0.25]
    padding = 5

    outfile = 'Outfile.png'
    fig = create_plot(dims, padding)
    draw_plot(fig, x, y, outfile)

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.