Search code examples
pythonplotprobabilityexponential

How to create Exponential Probability Paper in Python


I am trying right now to recreate this graph of the exponential probability paper in python.

In order to do it, I have to linearize the CDF function as:

x = a*g(Fx(x)) + b

and then plot x vs g(Fx(x)).

This image shows the parameters for different distributions

However I am clueless about how to proceed. Apperently the scale of the x axis has to be changed. I already tried using probplot, but the result was quite the same.

Any ideas?

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import expon
from scipy.stats import probplot

# Creating plot

fig,ax =plt.subplots()
newax=ax.twiny()
ax.grid()

# Lognormal

lambda_expon=0.04
i=1/lambda_expon

probs=np.arange(0.01,0.99,0.01) # array with probabilities

ppf =expon.ppf(probs,i) 
cdf=expon.cdf(ppf,i) 
x=-np.log(1-cdf) # variable
y=-np.log(1-cdf)*i # linearized form CDF

ax.plot(x,y)
newax.set_xticks([0.01,0.5,0.8,0.9,0.96,0.99])
newax.set_xticks([0.01,0.5,0.90,0.99])

ax.plot()

Solution

  • Not sure, why do you think this is CDF plot. If on X axis you put probabilities, and on Y axis you plot x, it looks like quantiles plot.

    I don't see in Python/Matplotlib built-in for such scales, logit looks like best approximation.

    Or did I misunderstood your question?

    Code, Python 3.8 x64 Win10

    import numpy as np
    import matplotlib.pyplot as plt
    
    # exponential distribution
    def PDF(x, λ):
        return λ*np.exp(-λ*x)
    
    def CDF(x, λ):
        return 1.0 - np.exp(-λ*x)
    
    def Q(p, λ): # quantile
        x = -np.log(1.0 - p)/λ
        return x
    
    # plots
    λ = 0.04
    
    p = np.linspace(0.01, 0.99, 101)
    x = Q(p, λ)
    
    fig = plt.figure()
    ax  = fig.add_subplot(2, 1, 1)
    
    ax.set_xscale('logit')
    ax.plot(p, x, 'r-')
    
    plt.show()
    

    and you will get something like

    enter image description here

    UPDATE

    If you need probability plot, here it is

    Code

    from scipy.stats import expon
    
    rve = expon(loc=0.0, scale=1.0/λ)
    
    p = np.linspace(0.01, 0.99, 101)
    x = rve.ppf(p) #  Q(p, λ)
    
    q = rve.rvs(size = 10000)
    
    fig = plt.figure()
    ax  = fig.add_subplot(2, 1, 1)
       
    res = stats.probplot(q, dist=rve, plot=ax)
    
    plt.show()
    

    and graph

    enter image description here

    Well, I already writing the code when you send a message. Placing it here anyway, it looks precisely like graph you asked about - linear with custom labels.

    import matplotlib.ticker as ticker
    
    def linear(x0, xn, y0, yn, x):
        q = (x-x0)/(xn-x0)
        return q * yn + (1.0 - q) * y0
    
    pmin = 0.009
    pmax = 0.991
    
    xmin = Q(pmin, λ)
    xmax = Q(pmax, λ)
    
    x = np.linspace(xmin, xmax, 2)
    p = np.linspace(pmin, pmax, 2)
    
    tick_values = [0.01, 0.50, 0.80, 0.90, 0.96, 0.99] # probabilies
    tick_names  = [str(v) for v in tick_values] # ticks to place on graph
    
    tick_xvals  = [Q(p, λ) for p in tick_values] # x values for each p
    tick_places = [linear(xmin, xmax, pmin, pmax, x) for x in tick_xvals] # x from linear function
    
    fig = plt.figure()
    ax  = fig.add_subplot(2, 1, 1)
    
    ax.axes.xaxis.set_major_locator(ticker.FixedLocator((tick_places)))
    ax.xaxis.set_major_formatter(ticker.FixedFormatter((tick_names)))
    
    ax.plot(p, x, 'r-')
    
    plt.show()
    

    and graph itself

    enter image description here