The derivate class dosn't behave like the base when i pass parameter to them

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



The derivate class dosn't behave like the base when i pass parameter to them



I have done a class hierarchy for product several plot stile , in which change almost any parameter, just inherit and define a set of parameter for change the default plot ..



but I have some problem with the derived class , basically from the abstract base class
derive a complete and usable class which is callable ! (in this way i can call directly subplot, or plot referring to the derived class)



The problem is that the usable base class that define the method __call__ works fine and accept and use in the right way the parameter passed by a generic script that instantiate it for create a plot, the derivatives classes don't.


__call__



here I'm report minimal working code



the base abstract class is:


class BasePlot(metaclass=ABCMeta):

def __init__(self, title : str = ' ' , filename : str = ' '):
self.title = title
self.filename = filename

def schemes(self, style:str = 'nb'):
if style == 'nb':
return ['#8DA0CB', '#E58AC3', '#A6D853', '#FFD930', '#B2B2B2', '#5FC3A4', '#FC8D62', '#66C2A5']
elif style == 'vega':
return ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728', '#9467BD', '#8C564B', '#E377C2', '#7F7F7F', '#BCBD22', '#17BECF']



from this base class derive the "Default plot" before called "the usable base class"


class DefaultPlot(BasePlot) :

def __init__(self, figsize,*args,**kwargs):
self.var = [*args]
self.params = kwargs

def cycle(self,n : str):
if n == '0':
return plt.cycler("color", self.schemes(self.parameters['scheme']) ) #colors)
elif n=='1':
return plt.cycler("color", self.schemes(self.parameters['scheme']) ) + plt.cycler("linestyle", self.linestyles(self.parameters['linestyle']))

def setparams(self, kwargs):
self.parameters = kwargs

if 'scheme' not in self.parameters.keys():
self.parameters['scheme'] = self.schemes('nb')


myparams =
'axes.prop_cycle': 0,



plt.rcParams.update(myparams)

def __call__ (self,nrows,ncols,*args,**kwargs):

self.setparams(kwargs)


self.fig, self.axs = plt.subplots(nrows,ncols,figsize=(9.5,4.5))



then the derivate class for which the parameter passed as dictionary dosen't affect
the parameters (as expected ... here is the problem)


#-*- coding : utf-8 -*-


class Standard(DefaultPlot):

def __init__(self , figsize , *args , **kwargs):
self.args = [*args]
self.params = kwargs
super().__init__(figsize,*self.args, **self.params )

def setparams(self, kwargs):

self.parameters = kwargs
if 'scheme' in self.parameters.keys():
self.parameters['scheme'] = 'nb'
if 'cycle' not in self.parameters.keys():
self.parameters['cycle'] = self.cycle('0')

super().setparams(self.parameters)



and finally the script in which the class is called :


import defaultplot
import qualityplot

def main():

x = np.linspace(0,2*np.pi,100)
y1 = np.sin(x)
y2 = np.sin(2*x)
y3 = np.sin(3*x)

fig,axs = qualityplot.Standard(figsize=(9.5,4.5))(1,1,**'scheme':'vega')
#fig,axs = defaultplot.DefaultPlot(figsize=(9.5,4.5))(1,1,**'scheme':'vega')

axs.plot(x,y1,x,y2,x,y3)
plt.show()

if __name__ == '__main__':
main()



In this script above the Standard class is instantiate and a dictionary containing parameters is passed , in particular the parameter for the scheme colors !
even thought the code works the result is not was I expected indeed the scheme 'vega' is not used in the plot ! while if you call in the same way the base class (the commented call) the code use the scheme 'vega' !! whyy ??? what I'm wronging ?



EDIT I'm sorry if you spend time to understand this messy code ! this morning I've look this and I was yelling versus myself ... I fixed this mess and revrite all the things clear !



i think that in order to be correct with who spent time trying to help me I have to apologize ...



the solution is straightforward : think before post !

for who is interested the solution code :


class BasePlot(metaclass=ABCMeta):

def __init__(self,figsize,**kwargs):
self.figsize = figsize
self.params = kwargs

def schemes(self, style:str = 'nb'):
if style == 'nb':
return ['#8DA0CB', '#E58AC3', '#A6D853', '#FFD930', '#B2B2B2', '#5FC3A4', '#FC8D62', '#66C2A5']
elif style == 'nb2':
return ['#82A6C7', '#DAADEB', '#99D366', '#FFD930', '#B2B2B2', '#5FC3A4', '#FC8D62', '#66C2A5']
elif style == 'vega':
return ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728', '#9467BD', '#8C564B', '#E377C2', '#7F7F7F', '#BCBD22', '#17BECF']



the default class


class DefaultPlot(BasePlot) :

def __init__(self, figsize, **kwargs):
self.figsize = figsize
self.parameters = kwargs
#print(self.parameters)
self.setparams(self.parameters)
def cycle(self,n : str):
if n == '0':
return plt.cycler("color", self.schemes(self.parameters['scheme']) ) #colors)
elif n=='1':
return plt.cycler("color", self.schemes(self.parameters['scheme']) ) + plt.cycler("linestyle", self.linestyles(self.parameters['linestyle']))

def setparams(self, kwargs):
print(self.parameters)
self.parameters.update(kwargs)

if 'font' not in self.parameters.keys():
self.parameters['font'] = 'serif'
if 'cycle' not in self.parameters.keys():
self.parameters['cycle'] = self.cycle('0')
if 'linestyles' not in self.parameters.keys():
self.parameters['linestyles'] = self.linestyles('paper')
if 'scheme' not in self.parameters.keys():
self.parameters['scheme'] = 'nb'
if 'linestyle' not in self.parameters.keys():
self.parameters['linestyle'] = self.linestyles('ls2')

print('*' ,self.parameters['scheme'])

myparams =
'axes.prop_cycle': self.parameters['cycle'],
'grid.color' : 'gray',
'font.family': self.parameters['font'] ,
'font.style' : 'italic'



plt.rcParams.update(myparams)


def __call__ (self,nrows,ncols,figsize=(9,6)):
self.nrows = nrows
self.ncols = ncols
self.figsize = figsize
if self.nrows == self.ncols ==1:
self.fig, self.axs = plt.subplots(self.nrows,self.ncols,figsize=self.figsize)
else:
self.fig, self.axs = plt.subplots(self.nrows,self.ncols,figsize=self.figsize)



the quality (final derived)


from defaultplot import DefaultPlot

class Standard(DefaultPlot):

def __init__(self , figsize , **kwargs):
self.figsize = figsize
self.parameters = kwargs


print(self.parameters)
self.setparams(self.parameters)
print(self.parameters)
super().__init__(figsize,**self.parameters )

def setparams(self, kwargs):
print(kwargs, '#')
self.parameters.update(kwargs)

if 'scheme' not in self.parameters.keys():
self.parameters['scheme'] = 'nb'
if 'linestyles' not in self.parameters.keys():
self.parameters['linestyles'] = self.linestyles('paper')
if 'cycle' not in self.parameters.keys():
self.parameters['cycle'] = self.cycle('0')

super().setparams(self.parameters)



and the script that call :


import numpy as np
import matplotlib.pyplot as plt
import defaultplot
import qualityplot

def main():

x = np.linspace(0,2*np.pi,100)
y1 = np.sin(x)
y2 = np.sin(2*x)
y3 = np.sin(3*x)

fig,axs = qualityplot.Standard(figsize=(9.5,4.5) , **'scheme':'vega')(1,1)
#fig,axs = defaultplot.DefaultPlot(figsize=(9.5,4.5), **'scheme':'vega')(1,1, figsize=(9.5,4.5))

axs.plot(x,y1,x,y2,x,y3)
plt.show()

if __name__ == '__main__':
main()



EDIT
my complete call is


def __call__ (self,nrows,ncols,figsize=(9.5,4.5)):

self.nrows = nrows
self.ncols = ncols
self.figsize = figsize
#self.figsize = self.parameters['figure.figsize']

if self.nrows == self.ncols ==1:
self.fig, self.axs = plt.subplots( self.nrows, self.ncols,figsize=self.figsize)
else:
self.fig, self.axs = plt.subplots( self.nrows, self.ncols,figsize=self.figsize)

self.fig,self.axs = self.set( self.nrows, self.ncols,self.fig,self.axs, self.parameters )
return self.fig,self.axs





If all you want to do is change plotting styles, why not simply create a matplotlib style for each?
– Dux
Aug 5 at 17:52


matplotlib





because there is some parameters that is not possible to define in rcparams .. like the grid( dashes=(5,9)) and I prefer have a hierarchy ... for me it is more powerful ... could you help me about my problem ?
– Drudox lebowsky
Aug 5 at 17:56





Can you please post an MCVE that illustrates your issue? The code you posted above is neither minimal nor verifiable. It contains unused code and does not run the way you posted it.
– shmee
Aug 6 at 10:27




1 Answer
1



Ok, I'm doing this in an answer because I cannot possibly handle all this in the comments.



Mate, I hate to break it to you but:


Standard


DefaultPlot



Let me break that down for you.
Your main issue is that you (now) call setparams three times when instantiating Standard.


setparams


Standard


Standard


scheme


cycle


linestyles


Standard


Standard.setparams


scheme


cycle


linestyles


linestyle


font


super().__init__(...)


Standard



Also, doing self.parameters.update(kwargs) at the beginning of setparams achieves absolutely nothing, you update self.params to exactly what it already is a this point.


self.parameters.update(kwargs)


setparams


self.params



The following example does exactly the same as your second example, after stripping away all the calls to pyplot (that are not relevant for this example context here) and all the code that is not used in what you posted.



Maybe you can try to explain your goal using the below. Or you might even be able to go from here and figure out what you need to do to get what you are looking for.


import abc


class BasePlot(metaclass=abc.ABCMeta):

@abc.abstractmethod # this ensures that BasePlot cannot be instantiated
def __init__(self, **kwargs):
self.parameters = kwargs
self.figsize = None # in your example, you use figsize only in __call__
self.nrows = None # declare your instance attributes in the cunstructor
self.ncols = None # declare your instance attributes in the cunstructor
self.setparams() # I would probably add this to __call__ instead of having it here


def setparams(self):
if 'font' not in self.parameters.keys():
self.parameters['font'] = 'serif'
if 'cycle' not in self.parameters.keys():
self.parameters['cycle'] = self.cycle('0')
if 'linestyles' not in self.parameters.keys():
self.parameters['linestyles'] = "paper"
if 'scheme' not in self.parameters.keys():
self.parameters['scheme'] = 'nb'
if 'linestyle' not in self.parameters.keys():
self.parameters['linestyle'] = "ls2"


def cycle(self, n: str):
# this is just a stub method, let it do whatever you need it to do
if n == '0':
return "cycle is 1"
elif n == '1':
return "cycle is 2"


def __call__(self, nrows, ncols, figsize=(9, 6)):
self.nrows = nrows
self.ncols = ncols
self.figsize = figsize
# this is just a stub method, let it do whatever you need it to do
print(self.parameters)
return self.nrows, self.ncols, self.figsize


class DefaultPlot(BasePlot):

def __init__(self, **kwargs): # needed here because the contract requires __init__ to be implemented
super().__init__(**kwargs)


class Standard(DefaultPlot):
pass


def main():

print(Standard(**'scheme': 'vega')(1, 1))
print("="*20)
print(DefaultPlot(**'scheme': 'vega')(1, 1, figsize=(9.5, 4.5)))


if __name__ == '__main__':
main()

# Output:
# 'scheme': 'vega', 'font': 'serif', 'cycle': 'cycle is 1', 'linestyles': 'paper', 'linestyle': 'ls2'
# (1, 1, (9, 6))
# ====================
# 'scheme': 'vega', 'font': 'serif', 'cycle': 'cycle is 1', 'linestyles': 'paper', 'linestyle': 'ls2'
# (1, 1, (9.5, 4.5))



Let me know when you figured out what you need, so that I can delete this answer; or edit it if there's still questions left.





thanks a lot !! I know that my code it's a messy code !! in particular is crap from the software design point of view ... Any advice here is welcome !!! :)
– Drudox lebowsky
Aug 6 at 18:29






but call should return self.fig and self.axs
– Drudox lebowsky
Aug 6 at 18:50


self.fig


self.axs





As I said, I simplified it, to have something that I can run since your code was neither minimal, nor verifiable or complete. If you need __call__ to do something else, then add your code in (although I don't see the point of your if-else condition; both logical paths behave the same). Also, you can put back your code in cycle which I stripped down as well. My main question is: what do you want to achieve? With the above structure (that behaves just as your latest code), there is no point in having inheritance. Standard and DefaultPlot have no functional difference.
– shmee
Aug 7 at 5:32


__call__


if


else


cycle


Standard


DefaultPlot





Thank you very much !! thanks to your advice I rewrote the baseclass , delete the default one (doesn't need ) and create a better project of hierarchy for producing "quality" (from my point of view me) plot !!
– Drudox lebowsky
Aug 7 at 11:41





@Drudoxlebowsky good that you took something away from this. However, please consider deleting this question. As it stands it is too specific to be of help for anyone else and the problem description does not match your desired solution anymore.
– shmee
Aug 8 at 6:10






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

Creating a leaderboard in HTML/JS