I am trying to use a custom scale in matplotlib. The particular scale function is for a gamma distribution which requires the shape parameter to determine the scale transform. To get this scale parameter to the scale transform functions I have found it necessary to use a global variable as the functions cannot be called or it messes with matplotlib's use of them. The issue is when I am doing subplots I find that the custom scale uses only the last value of the global variable rather than the value of the variable when each subplot is being generated. To reproduce the problem, run the code provided and note that the first plot is not a straight line, then comment out subplot(122) and run it again, then comment out subplot(121) and run it again. You will see that when run separately the lines look straight (as they should) but when run together we see the last value of the global variable (gamma_beta) is the one that is applied to both subplot y-scales. How can I get the correct value of gamma_beta to the scale transform functions when plotting multiple subplots in the same figure?
I have tried creating other global arrays as lookups but I find that the forward and inverse functions are called hundreds of times during matplotlib's plotting process and it is difficult to know how many times they will be called as it depends on the plot's features.
import matplotlib.pyplot as plt
import scipy.stats as ss
import numpy as np
np.random.seed(42)
#generate some data from a beta distribution
data = ss.beta.rvs(a=5,b=2,size=100)
#these are the scale transform functions
def forward(F):
return ss.gamma.ppf(F, a=gamma_beta) #we need to pass gamma_beta to this function as the axes scaling depends on it
def inverse(R):
return ss.gamma.cdf(R, a=gamma_beta)
def Gamma_CDF(data,fit_gamma):
global gamma_beta #due to the functions "forward" and "inverse" not being called using set_yscale we must get the shape parameter to these functions using a global variable
xvals = np.linspace(0.001,1,1000)
if fit_gamma==True: #fit the location parameter of the gamma distribution
gamma_3_param = ss.gamma.fit(data)
yvals = ss.gamma.cdf(xvals,*gamma_3_param)
gamma_beta = gamma_3_param[0] #extract the shape parameter
else: #do not fit the location parameter
gamma_2_param = ss.gamma.fit(data,floc=0)
yvals = ss.gamma.cdf(xvals,*gamma_2_param)
gamma_beta = gamma_2_param[0] #extract the shape parameter
plt.plot(xvals,yvals)
plt.gca().set_yscale('function',functions=(forward, inverse))
plt.gca().grid(True)
# If we comment out each subplot seperately then the plot is a straight line (as it should be).
# but plotting them together causes the global variable (gamma_beta) to be only used when plt.show()
# is called so we get the last value of gamma_beta applied to all instances and only the last plot is scaled correctly.
# This is bad because the scale needs to use the correct gamma_beta for the line to appear straight.
plt.subplot(121)
Gamma_CDF(data,False)
plt.subplot(122)
Gamma_CDF(data,True)
plt.show()
Expected results are two subplots in the same figure that both appear as straight lines due to the correct custom scale transform being applied. Currently this only works when done as separate figures.