The derivate class dosn't behave like the base when i pass parameter to them
Clash 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
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.
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