Search code examples
arraysnumpymatplotlibtypeerrormpmath

How to manage "TypeError" message when plotting functions defined in mpmath module instead of scipy?


For the purpose of my problem, I have to use gamma functions from mpmath module rather than scipy. However, I am using matplotlib.pyplot to plot my functions when the variable is taken from a numpy array and the y-values are supposed to be produced in the same format. But in doing so, I am receiving an error message of TypeError complaining of the conversion from array to mpf.

import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import quad, dblquad
import mpmath as mp


low, up  = 5.630e5, 1.167e12
alpha, threshold = 1.05   , 2.15e10     
beta = 274

def g(x, low, up, beta):
    return mp.gamma(-2/3) * (mp.gammainc(-2/3, beta*(x/low)**3) - mp.gammainc(-2/3, beta*(x/up)**3))

def Integrand1(x, low, up, threshold, alpha, beta):
    return pow(x/threshold, alpha) * g(x, low, up, beta)

def Integrand2(x, low, up, threshold, alpha, beta):
    return g(x, low, up, beta)


def PDF(x, low, up, threshold, alpha, beta):
    A = quad(Integrand1, low, threshold, args=(low, up, threshold, alpha, beta))
    B = quad(Integrand2, threshold, up, args=(low, up, threshold, alpha, beta))
    C=(A[0]+B[0])**(-1)
    y = np.piecewise(x, 
                    [x < threshold], [lambda x: C * pow(x/threshold, alpha) * g(x, low, up, beta), 
                                   lambda x: C *                           g(x, low, up, beta)
                                  ]
                    )
    return y


x_array = np.array(np.logspace(8.2, 11.8, 10))
y_array = PDF(x_array, low, up, threshold, alpha, beta)
plt.plot(x_array, y_array, color='green', linestyle='-')
plt.gca().autoscale(False)
plt.vlines([threshold], 
        plt.gca().get_ylim()[0], plt.gca().get_ylim()[1], 
        linestyles='dashed', color='k', label='')

plt.xscale("log", nonposx='clip')
plt.yscale("log", nonposy='clip')
plt.show()

Traceback (most recent call last): File "test.py", line 35, in y_array = PDF(x_array, low, up, threshold, alpha, beta) File "test.py", line 28, in PDF lambda x: C * g(x, low, up, beta) File "/home/username/anaconda3/lib/python3.6/site-packages/numpy/lib/function_base.py", line 1344, in piecewise y[condlist[k]] = item(vals, *args, **kw) File "test.py", line 27, in [x < threshold], [lambda x: C * pow(x/threshold, alpha) * g(x, low, up, beta), File "test.py", line 13, in g return mp.gamma(-2/3) * (mp.gammainc(-2/3, beta*(x/low)**3) - mp.gammainc(-2/3, beta*(x/up)**3)) File "/home/username/anaconda3/lib/python3.6/site-packages/mpmath/functions/expintegrals.py", line 141, in gammainc a = ctx.convert(a) File "/home/username/anaconda3/lib/python3.6/site-packages/mpmath/ctx_mp_python.py", line 662, in convert return ctx._convert_fallback(x, strings) File "/home/username/anaconda3/lib/python3.6/site-packages/mpmath/ctx_mp.py", line 614, in _convert_fallback raise TypeError("cannot create mpf from " + repr(x)) TypeError: cannot create mpf from array([ 6.11259157e+09, 9.68780477e+10,
1.53541358e+12, 2.43346654e+13, 3.85678455e+14, 6.11259157e+15])

I need to know how to mpf an array and I found thes pages (How to mpf an array) and (create an mpf) but I don't know how to apply them to my plotting routine.


Solution

  • This isn't about plotting. The error occurs within the function PDF, specifically within np.piecewise. As the documentation says, the lambdas you pass to piecewise must be able to take an array, because this is what piecewise will pass to them.

    And your function g isn't able to take an array, because the mpmath functions it uses are meant for a single float. Solution: np.vectorize wrapper:

    gv = np.vectorize(g)
    

    and then use gv instead of g in piecewise.

    Then np.piecewise will work, and you'll be able to proceed to other errors, like mismatched names PDF_values and y_array.