def fac(n):
value = 1
for i in range(2,n+1):
value = value * i
return value
def C(n,k):
return fac(n)/(fac(k) * (fac(n-k)))
for k in range(1,100):
for n in [10,20,30]:
F=C(n,k)
plt.plot(k,F)
plt.legend()
plt.show()
I wanna plot the binomial function as a function in k for certain n values say for n = 10, 20, 30, ...
However, I do not know how to plot that.
I suspect, there's a specific reason not to use NumPy, so here's a solution using plain Python.
If you're talking about binomial distribution, then the formula needs to incorporate the probability p. I added that in the code below. (If you actually only want to have the binomical coefficient, delete the two pow terms.)
In general, for plotting, you need to collect your x and y values in some arrays (say X and Y), so that you can use plt.plot(X, Y) to plot the whole function.
In your example, you also need to switch the two loops, because you want to have three functions, each for k = [1 ... 100].
That'd be my solution:
from matplotlib import pyplot as plt
def fac(n):
value = 1
for i in range(2, n+1):
value = value * i
return value
def C(n, k, p):
return fac(n)/(fac(k) * (fac(n-k))) * pow(p, k) * pow(1-p, n-k)
for N in [10, 20, 30]:
X = []
Y = []
for K in range(1, 100):
X.append(K)
Y.append(C(N, K, 0.5))
plt.plot(X, Y)
plt.legend(('N = 10', 'N = 20', 'N = 30'))
plt.show()
The generated output then looks like this:
Hope that helps!
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.8.1
Matplotlib: 3.2.0rc1
----------------------------------------
Good question!
The "typical" way to plot a function is to compute 2 vectors (lists). One of the x values and one of f(x) and then plot them. You can either type in your x values or use one of several convenient functions such as numpy.linspace to make them. You can (and should) also use list comprehension to make the y values. Here is a toy example:
from matplotlib import pyplot as plt
def f(x): # just return x squared
return x**2
x = range(10)
y = [f(t) for t in x]
plt.plot(x,y)
produces:
If you want to make the graph smoother and use a lot of values for x, then use numpy.linspace perhaps like so:
import numpy as np
x = np.linspace(0,20,1000) # low, high, number of pts
y = [np.sin(4*t) for t in x]
plt.plot(x,y)
You should be able to use whatever function you want to compute you y-values and use this structure.
Related
I am trying to implement Complex Exponential Fourier Series for f(x) defined on [-L,L] using these formulas,
I want to be able to implement these without calling the Fourier functions in other libraries since I want to also understand what's going on. Here is my attempt,
import numpy as np
from matplotlib import pyplot as plt
steps = 100
dt = 1/steps
L = np.pi
t = np.linspace(-L, L, steps)
def constant(X, Y, n):
return (1/(2*L))*sum([y*np.exp((1j*n*np.pi*t)/L)*dt for t, y in zip(X, Y)])
def complex_fourier(X, Y, N):
_X, _Y = [], []
for t in X:
f = 0
for n in range(-N//2, N//2 + 1):
c = constant(X, Y, n)
f += c*np.exp((-1j*n*np.pi*t)/L)
_X += [f.real]
_Y += [f.imag]
return _X, _Y
X, Y = complex_fourier(t, np.sin(t), 50)
plt.plot(X, Y, 'k.')
# plt.plot(t, np.sin(t))
plt.show()
The plot seems to be almost random and does not improve with more c terms. Could someone point out exactly what am I doing wrong?
Just to answer the "random plot" part of the question for now - note the Y-scale of your plot!
>>> np.min(Y), np.max(Y)
(-6.1937063114043705e-18, 6.43002899658067e-18)
>>> np.min(X), np.max(X)
(-0.15754356079010426, 0.15754356079010395)
In other words, all of your coefficients are basically real valued. You probably wouldn't be interested in an plot of the imaginary part vs the real part, but rather the sum of squares vs the frequency or mode number.
I am trying to plot 3 different functions on a log-log scale in python for three intervals of the x-range. Attaching the image of the kind of plot that I want to create and which functions, y, for what intervals of x.
My code attempt is as follows. Maybe I am overcomplicating it.
import math as m
import numpy as np
import pylab as pl
import matplotlib.pyplot as plt
x = np.arange(100) # this gives `array([0, 1, 2, ..., 9])`
y = np.arange(100)
for i in range (-50,20):
if x[i] < -43:
y[i] = m.log10((10**x[i])/(10**-43))**(1/2)
if x[i] > -43 and x[i] < -40:
y[i] = m.log10(np.exp((10**36)((10**x[i])-(10**-43))))
if x[i] >-40:
y[i] = m.log10((np.exp((10**36)((10**-40) - (10**-43)))(((10**x[i])/(10**-43))**(1/2)))
#i+=1
pl.plot(x,y)
#pl.xlim([-100.,100.])
#pl.ylim([-100.,100.])
pl.xlabel('log x')
pl.ylabel('log y')
pl.show()
PLEASE NOTE:
updated code with help from #Sembei which works but there's further question on colours below:
import matplotlib.pyplot as plt
x = np.linspace(-50,23,500)
y = []
for xval in x:
if xval < -36:
y.append(m.log10(((10**xval)/(10**-36))**(1/2)))
elif -36 <= xval <= -34:
y.append(m.log10(np.exp((10**36)*((10**xval)-(10**-36)))))
else:
y.append(m.log10((np.exp((10**36)*((10**-34) - (10**-36)))*(((10**xval)/(10**-36))**(1/2)))))
plt.plot(x,y)
pl.xlim([-44.,-30.])
#pl.ylim([-10.,20.])
pl.xlabel('log x')
pl.ylabel('log y')
plt.show()
FURTHER QUESTION:
how to set 3 different colours for the different y functions for the 3 x-intervals?
Any help is appreciated. Thanks!
you can do something like this:
x = range(-50,23)
y = []
for xval in x:
if xval < -43:
y.append(-43) #your function in this interval
elif -43 <= xval <= -40:
y.append(xval) #your function in this interval)
else:
y.append(-40) #your function in this interval)
plt.plot(x,y, '.-')
plt.xlabel('log x')
plt.ylabel('log y')
plt.show()
You just need to fill the #your function in this interval with a correct syntax (note that in your syntax you are missing product operators *)
Here I have used y as a list and I'm appending values. You can also initialize y to all zeros and assign values based on indexes. For that you will need to include an enumerate in the loop that will give you the index of y where you have to put the value.
Note: here, range steps one by one. if you want more resolution you might want to use np.linspace so you can control the resolution of your function.
Edit: I put some toy definitions of the function so you can see how it works. Now just change my function definitions for your own
I have a set of data values, and I want to get the CDF (cumulative distribution function) for that data set.
Since this is a continuous variable, we can't use binning approach as mentioned in (How to get cumulative distribution function correctly for my data in python?). So I came up with following approach.
import scipy.stats as st
def trapezoidal_2(ag, a, b, n):
h = np.float(b - a) / n
s = 0.0
s += ag(a)[0]/2.0
for i in range(1, n):
s += ag(a + i*h)[0]
s += ag(b)[0]/2.0
return s * h
def get_cdf(data):
a = np.array(data)
ag = st.gaussian_kde(a)
cdf = [0]
x = []
k = 0
max_data = max(data)
while (k < max_data):
x.append(k)
k = k + 1
sum_integral = 0
for i in range(1, len(x)):
sum_integral = sum_integral + (trapezoidal_2(ag, x[i - 1], x[i], 2))
cdf.append(sum_integral)
return x, cdf
This is how I use this method.
b = 1
data = st.pareto.rvs(b, size=10000)
data = list(data) x_cdf, y_cdf = get_cdf(data)
Ideally I should get a value close to 1 at the end of y_cdf list. But I get a value close to 0.57.
What is going wrong here? Is my approach correct?
Thanks.
The value of the cdf at x is the integral of the pdf between -inf and x, but you are computing it between 0 and x. Maybe you are assuming that the pdf is 0 for x < 0 but it is not:
rs = np.random.RandomState(seed=52221829)
b = 1
data = st.pareto.rvs(b, size=10000, random_state=rs)
ag = st.gaussian_kde(data)
x = np.linspace(-100, 100)
plt.plot(x, ag.pdf(x))
So this is probably what's going wrong here: you not checking your assumptions.
Your code for computing the integral is painfully slow, there are better ways to do this with scipy but gaussian_kde provides the method integrate_box_1d to integrate the pdf. If you take the integral from -inf everything looks right.
cdf = np.vectorize(lambda x: ag.integrate_box_1d(-np.inf, x))
plt.plot(x, cdf(x))
Integrating between 0 and x you get the same you are seeing now (to the right of 0), but that's not a cdf at all:
wrong_cdf = np.vectorize(lambda x: ag.integrate_box_1d(0, x))
plt.plot(x, wrong_cdf(x))
Not sure about why your function is not working exactly but one way of calculating CDF is as follows:
def get_cdf_1(data):
# start with sorted list of data
x = [i for i in sorted(data)]
cdf = []
for xs in x:
# get the sum of the values less than each data point and store that value
# this is normalised by the sum of all values
cum_val = sum([i for i in data if i <= xs])/sum(data)
cdf.append(cum_val)
return x, cdf
There is no doubt a faster way of computing this using numpy arrays rather than appending values to a list, but this returns values in the same format as your original example.
I think it's just:
def get_cdf(data):
return sorted(data), np.linspace(0, 1, len(data))
but I might be misinterpreting the question!
when I compare this to the analytic result I get the same:
x_cdf, y_cdf = get_cdf(st.pareto.rvs(1, size=10000))
import matplotlib.pyplot as plt
plt.semilogx(x_cdf, y_cdf)
plt.semilogx(x_cdf, st.pareto.cdf(x_cdf, 1))
I would like to plot implicit equations (of the form f(x, y)=g(x, y) eg. X^y=y^x) in Matplotlib. Is this possible?
Since you've tagged this question with sympy, I will give such an example.
From the documentation: http://docs.sympy.org/latest/modules/plotting.html.
from sympy import var, plot_implicit
var('x y')
plot_implicit(x*y**3 - y*x**3)
I don't believe there's very good support for this, but you could try something like
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
delta = 0.025
xrange = arange(-5.0, 20.0, delta)
yrange = arange(-5.0, 20.0, delta)
X, Y = meshgrid(xrange,yrange)
# F is one side of the equation, G is the other
F = Y**X
G = X**Y
matplotlib.pyplot.contour(X, Y, (F - G), [0])
matplotlib.pyplot.show()
See the API docs for contour: if the fourth argument is a sequence then it specifies which contour lines to plot. But the plot will only be as good as the resolution of your ranges, and there are certain features it may never get right, often at self-intersection points.
matplotlib does not plot equations; it plots serieses of points. You can use a tool like scipy.optimize to numerically calculate y points from x values (or vice versa) of implicit equations numerically or any number of other tools as appropriate.
For example, here is an example where I plot the implicit equation x ** 2 + x * y + y ** 2 = 10 in a certain region.
from functools import partial
import numpy
import scipy.optimize
import matplotlib.pyplot as pp
def z(x, y):
return x ** 2 + x * y + y ** 2 - 10
x_window = 0, 5
y_window = 0, 5
xs = []
ys = []
for x in numpy.linspace(*x_window, num=200):
try:
# A more efficient technique would use the last-found-y-value as a
# starting point
y = scipy.optimize.brentq(partial(z, x), *y_window)
except ValueError:
# Should we not be able to find a solution in this window.
pass
else:
xs.append(x)
ys.append(y)
pp.plot(xs, ys)
pp.xlim(*x_window)
pp.ylim(*y_window)
pp.show()
There is an implicit equation (and inequality) plotter in sympy. It is created as a part of GSoC and it produces the plots as matplotlib figure instances.
Docs at http://docs.sympy.org/latest/modules/plotting.html#sympy.plotting.plot_implicit.plot_implicit
Since sympy version 0.7.2 it is available as:
>>> from sympy.plotting import plot_implicit
>>> p = plot_implicit(x < sin(x)) # also creates a window with the plot
>>> the_matplotlib_axes_instance = p._backend._ax
Edit: If you plot a hyperbola using plt.plot() then you will get the undesired branching effect. plt.scatter() in its place should still work. Then there is no need to reverse the order of negative or positive values, but if you wanted to use this code for some reason (instead of using contour plot from scipy) it will work anyways with plt.scatter()
An implicit function in two dimensions in general can be written as:
f(x,y)=0
Since we cannot write this as f(x) = y, then we cannot compute y from an easily programmable set of discrete x. It is possible, however, to see how close a point generated from a grid is from the true function.
So make a grid of x and y to a custom point density and see how close each point is to satisfying the equation.
In other words, if we can't get f(x,y) =0, perhaps we can get close to 0. Instead of looking for f(x,y) =0 look for f(x,y) > -\epsilon and f(x,y) < \epsilon.
\epsilon is your tolerance and if this condition fits within your tolerance of 0 and tuning the grid appropriately you can get your function plotted.
The code below does just that for a circle of radius 1 (f(x,y)= x^2 + y^2 -1 = 0). I used the symbol dr for \epsilon.
Also, to make sure the plt.plot function connects the lines in the correct order, I use a reversed version of the x values for the negative y values. That way, the evaluation of f(x,y) is done in a clockwise loop so that the nearest values are one after another. Without this, lines from opposite sides of the function would connect and it would appear slightly filled in.
import numpy as np
import matplotlib.pyplot as plt
r = 1 #arbitrary radius to set up the span of points
points = 250
dr = r/points #epsilon window
x=list(np.linspace(-5*r,5*r,5*points+1)) #setting up the x,y grid
y=x
xreversed = reversed(x) #reversing the array
x_0=[] #placeholder arrays
y_0=[]
for i in x:
for j in y:
if i**2 + j**2 -1 < dr and i**2+j**2 -1 > -dr and j >= 0: #positive values of y
x_0.append(i)
y_0.append(j)
for i in xreversed:
for j in y:
if i**2+j**2 -1 < dr and i**2+j**2 -1 > -dr and j < 0: #negative values of y, using x reversed
x_0.append(i)
y_0.append(j)
plt.plot(x_0,y_0)
plt.show()
Many thanks Steve, Mike, Alex. I have gone along with Steve's solution (please see code below). My only remaining issue is that the contour plot appears behind my gridlines, as opposed to a regular plot, which I can force to the front with zorder. Any more halp greatly appreciated.
Cheers,
Geddes
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
import numpy as np
fig = plt.figure(1)
ax = fig.add_subplot(111)
# set up axis
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# setup x and y ranges and precision
x = np.arange(-0.5,5.5,0.01)
y = np.arange(-0.5,5.5,0.01)
# draw a curve
line, = ax.plot(x, x**2,zorder=100)
# draw a contour
X,Y=np.meshgrid(x,y)
F=X**Y
G=Y**X
ax.contour(X,Y,(F-G),[0],zorder=100)
#set bounds
ax.set_xbound(-1,7)
ax.set_ybound(-1,7)
#produce gridlines of different colors/widths
ax.xaxis.set_minor_locator(MultipleLocator(0.2))
ax.yaxis.set_minor_locator(MultipleLocator(0.2))
ax.xaxis.grid(True,'minor',linestyle='-')
ax.yaxis.grid(True,'minor',linestyle='-')
minor_grid_lines = [tick.gridline for tick in ax.xaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.xaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
minor_grid_lines = [tick.gridline for tick in ax.yaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.yaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
plt.show()
I would like to plot implicit equations (of the form f(x, y)=g(x, y) eg. X^y=y^x) in Matplotlib. Is this possible?
Since you've tagged this question with sympy, I will give such an example.
From the documentation: http://docs.sympy.org/latest/modules/plotting.html.
from sympy import var, plot_implicit
var('x y')
plot_implicit(x*y**3 - y*x**3)
I don't believe there's very good support for this, but you could try something like
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
delta = 0.025
xrange = arange(-5.0, 20.0, delta)
yrange = arange(-5.0, 20.0, delta)
X, Y = meshgrid(xrange,yrange)
# F is one side of the equation, G is the other
F = Y**X
G = X**Y
matplotlib.pyplot.contour(X, Y, (F - G), [0])
matplotlib.pyplot.show()
See the API docs for contour: if the fourth argument is a sequence then it specifies which contour lines to plot. But the plot will only be as good as the resolution of your ranges, and there are certain features it may never get right, often at self-intersection points.
matplotlib does not plot equations; it plots serieses of points. You can use a tool like scipy.optimize to numerically calculate y points from x values (or vice versa) of implicit equations numerically or any number of other tools as appropriate.
For example, here is an example where I plot the implicit equation x ** 2 + x * y + y ** 2 = 10 in a certain region.
from functools import partial
import numpy
import scipy.optimize
import matplotlib.pyplot as pp
def z(x, y):
return x ** 2 + x * y + y ** 2 - 10
x_window = 0, 5
y_window = 0, 5
xs = []
ys = []
for x in numpy.linspace(*x_window, num=200):
try:
# A more efficient technique would use the last-found-y-value as a
# starting point
y = scipy.optimize.brentq(partial(z, x), *y_window)
except ValueError:
# Should we not be able to find a solution in this window.
pass
else:
xs.append(x)
ys.append(y)
pp.plot(xs, ys)
pp.xlim(*x_window)
pp.ylim(*y_window)
pp.show()
There is an implicit equation (and inequality) plotter in sympy. It is created as a part of GSoC and it produces the plots as matplotlib figure instances.
Docs at http://docs.sympy.org/latest/modules/plotting.html#sympy.plotting.plot_implicit.plot_implicit
Since sympy version 0.7.2 it is available as:
>>> from sympy.plotting import plot_implicit
>>> p = plot_implicit(x < sin(x)) # also creates a window with the plot
>>> the_matplotlib_axes_instance = p._backend._ax
Edit: If you plot a hyperbola using plt.plot() then you will get the undesired branching effect. plt.scatter() in its place should still work. Then there is no need to reverse the order of negative or positive values, but if you wanted to use this code for some reason (instead of using contour plot from scipy) it will work anyways with plt.scatter()
An implicit function in two dimensions in general can be written as:
f(x,y)=0
Since we cannot write this as f(x) = y, then we cannot compute y from an easily programmable set of discrete x. It is possible, however, to see how close a point generated from a grid is from the true function.
So make a grid of x and y to a custom point density and see how close each point is to satisfying the equation.
In other words, if we can't get f(x,y) =0, perhaps we can get close to 0. Instead of looking for f(x,y) =0 look for f(x,y) > -\epsilon and f(x,y) < \epsilon.
\epsilon is your tolerance and if this condition fits within your tolerance of 0 and tuning the grid appropriately you can get your function plotted.
The code below does just that for a circle of radius 1 (f(x,y)= x^2 + y^2 -1 = 0). I used the symbol dr for \epsilon.
Also, to make sure the plt.plot function connects the lines in the correct order, I use a reversed version of the x values for the negative y values. That way, the evaluation of f(x,y) is done in a clockwise loop so that the nearest values are one after another. Without this, lines from opposite sides of the function would connect and it would appear slightly filled in.
import numpy as np
import matplotlib.pyplot as plt
r = 1 #arbitrary radius to set up the span of points
points = 250
dr = r/points #epsilon window
x=list(np.linspace(-5*r,5*r,5*points+1)) #setting up the x,y grid
y=x
xreversed = reversed(x) #reversing the array
x_0=[] #placeholder arrays
y_0=[]
for i in x:
for j in y:
if i**2 + j**2 -1 < dr and i**2+j**2 -1 > -dr and j >= 0: #positive values of y
x_0.append(i)
y_0.append(j)
for i in xreversed:
for j in y:
if i**2+j**2 -1 < dr and i**2+j**2 -1 > -dr and j < 0: #negative values of y, using x reversed
x_0.append(i)
y_0.append(j)
plt.plot(x_0,y_0)
plt.show()
Many thanks Steve, Mike, Alex. I have gone along with Steve's solution (please see code below). My only remaining issue is that the contour plot appears behind my gridlines, as opposed to a regular plot, which I can force to the front with zorder. Any more halp greatly appreciated.
Cheers,
Geddes
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
import numpy as np
fig = plt.figure(1)
ax = fig.add_subplot(111)
# set up axis
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# setup x and y ranges and precision
x = np.arange(-0.5,5.5,0.01)
y = np.arange(-0.5,5.5,0.01)
# draw a curve
line, = ax.plot(x, x**2,zorder=100)
# draw a contour
X,Y=np.meshgrid(x,y)
F=X**Y
G=Y**X
ax.contour(X,Y,(F-G),[0],zorder=100)
#set bounds
ax.set_xbound(-1,7)
ax.set_ybound(-1,7)
#produce gridlines of different colors/widths
ax.xaxis.set_minor_locator(MultipleLocator(0.2))
ax.yaxis.set_minor_locator(MultipleLocator(0.2))
ax.xaxis.grid(True,'minor',linestyle='-')
ax.yaxis.grid(True,'minor',linestyle='-')
minor_grid_lines = [tick.gridline for tick in ax.xaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.xaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
minor_grid_lines = [tick.gridline for tick in ax.yaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.yaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
plt.show()