Given a function g(x), I want to find a fixed point to this function using
fixed point iteration. Except for finding the point itself, I want to plot the graph to the function using matplotlib.pyplot, and include the vertical and horizontal bars that show how the iteration closes in on the fixed point (if one exists). Example picture
All help appreciated!
/programming newbie
EDIT: Since I'm no too comfortable with generator objects yet, I've written the following code. It doesn't quite work though: what's wrong with it?
from matlibplot.axes import vlines, hlines
def fixpt(f, x, epsilon=1.0E-4, N=500, store=False):
y = f(x)
n = 0
if store: Values = [(x, y)]
while abs(y-x) >= epsilon and n < N:
x = f(x)
n += 1
y = f(x)
if store: Values.append((x, y))
vlines(x, min(x, y), max(x, y), color='b')
hlines(y, min(y, x), max(y, x), color='b')
if store:
return y, Values
else:
if n >= N:
return "No fixed point for given start value"
else:
return x, n, y
def fixedpoint(f,x):
while x != f(x):
yield x
x = f(x)
yield x
Usage: fixedpoint(g,some_starting_value).
Vertical and horizontal bars depend on plotting library. Specify which one you use.
Your function looks fine. I am not familiar with vlines and hlines. I used your store arg to get the points, and plot them outside the function (it is generally better to separate problems like this).
I used only the plot function from matplotlib.pyplot, and the show function to display the graph.
from matplotlib import pyplot as plt
import numpy as np
def fixpt(f, x, epsilon=1.0E-4, N=500, store=False):
y = f(x)
n = 0
if store: Values = [(x, y)]
while abs(y-x) >= epsilon and n < N:
x = f(x)
n += 1
y = f(x)
if store: Values.append((x, y))
if store:
return y, Values
else:
if n >= N:
return "No fixed point for given start value"
else:
return x, n, y
# define f
def f(x):
return 0.2*x*x
# find fixed point
res, points = fixpt(f, 3, store = True)
# create mesh for plots
xx = np.arange(0, 6, 0.1)
#plot function and identity
plt.plot(xx, f(xx), 'b')
plt.plot(xx, xx, 'r')
# plot lines
for x, y in points:
plt.plot([x, x], [x, y], 'g')
plt.plot([x, y], [y, y], 'g')
# show result
plt.show()
Here is how I thought it through :
from pylab import *
def f(x):
return 8*x/(1 + 2*x)
def cobweb(x0, n, ax):
xs = [x0]
ys = [0]
for i in range(1,n):
if i % 2 == 0:
xs.append(ys[-1])
ys.append(ys[-1])
else:
xs.append(xs[-1])
ys.append(f(xs[-1]))
ax.plot(xs, ys, 'k--', lw=2.0)
x = linspace(0, 4, 100)
fig = figure()
ax = fig.add_subplot(111)
ax.plot(x, x, 'k', lw=2.0)
ax.plot(x, f(x), 'r', lw=2.0)
cobweb(0.5, 50, ax)
ax.set_xlabel(r'$x$')
ax.set_ylabel(r'$f(x)$')
grid()
show()
Related
I have a function g(psi, k) where psi is a two components array and k is a real parameter. I would like to display the g function in a 3D contour plot with respect to the coordinates psi given a selected parameter k. How can I do that in Python?
I tried using the function contour3D with a wrapper function in the following way:
import numpy as np
import matplotlib.pyplot as plt
k = 32 # Change this value to display different plots
# Wrapper of the g function
def f(x, y):
psi = np.array([x, y])
return g(psi, k)
x = np.linspace(-6, 6, 30)
y = np.linspace(-6, 6, 30)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.contour3D(X, Y, Z, 50, cmap='binary')
plt.show()
But I get the following error relative to the line Z = f(X, Y):
ValueError: setting an array element with a sequence.
Running simply:
print(f(-0.33, -0.5))
I obtain a real value as expected:
28.08105396614395
How can I fix it? Is there any other way more straightforward to display the plot of g(psi, 32)?
Your function g(psi, k) is probably only working with psi being a 1D array, meaning only accepting x and y being scalars. Either call f in a loop, or vectorize the g function. Here is how to call the function f in a loop:
Z = np.empty(shape=(X.shape))
for row, (xx, yy) in enumerate(zip(X,Y)): # into rows
for col, (xxx, yyy) in enumerate(zip(xx,yy)): # rows to single values
Z[row, col] = f(xxx, yyy)
I'm trying to demonstrate a cost function right now and wondering if there's a way to traverse the parabola by adding plot in the same subplot and figure.
def costfuntion(b, a):
# b Value
x = np.linspace(b*(-b), b*(b), 100)
y = (x - a)**2
return y
My Plot Attempt:
plt.plot(costfuntion(20,5))
plt.ylabel("Cost Value");
#b = 'some b value'
plt.plot(b, marker='o', color='b')
What I'm trying to mimic
(Around: 1:13)
Since the y values depend on the a values you need to specify an a for the y lookup. Consider the following:
def costfunction(b, a):
# b Value
x = np.linspace(b*(-b), b*(b), 100)
y = (x - a)**2
return x, y
a = 5
c = costfunction(20, a)
plt.plot(c[0], c[1], linestyle='-', linewidth=1)
plt.ylabel("Cost Value");
b = 100
yb = (b - a)**2 # Find the corresponding y-value
plt.plot(b, yb, marker='o', color='b')
plt.show()
This will give you
You might also note that I modified the costfunction definition to return the x values, otherwise matplotlib will just use whatever values it pleases.
def costfuntion(b, a):
# b Value
x = np.linspace(b*(-b), b*(b), 100)
y = (x - a)**2
return x, y
x, y = costfuntion(20,5)
plt.plot(x, y)
for i in range(0, len(x), 2):
plt.plot(x[i], y[i], marker='o', color='b')
Change the cost function to return both x and y of the function you are plotting and use this information to plot points on the function.
I'm trying to plot a cdf with matplotlib. However, cdfs begin in the origin, thus I prepended zeros to the x and y arrays. The problem is now that the origin now is marked as a data point. I'd like to remove that single marker in the point (0,0).
Code and picture below.
#Part of the myplot (my own) class
def cdf(self):
markers = ["x","v","o","^","8","s","p","+","D","*"]
for index,item in enumerate(np.asarray(self.data).transpose()):
x = np.sort(item)
y = np.arange(1,len(x)+1) / len(x)
x = np.insert(x,0,0)
y = np.insert(y,0,0)
self.plot = plt.plot(x,
y,
marker=markers[index],
label=self.legend[index])
self.setLabels( xlabel=self.xlabel,
ylabel="cumulative density",
title=self.title)
self.ax.set_ylim(ymax=1)
You cannot remove a marker. What you may do is to plot all the markers first, then append the origin and then plot a line.
x = np.sort(item)
y = np.arange(1,len(x)+1) / len(x)
self.plot, = plt.plot(x, y, marker=markers[index], ls="", label=self.legend[index])
x = np.insert(x,0,0)
y = np.insert(y,0,0)
self.plot2, = plt.plot(x, y, marker="", color=self.plot.get_color())
Alternative: Use the markevery argument.
x = np.sort(item)
y = np.arange(1,len(x)+1) / len(x)
x = np.insert(x,0,0)
y = np.insert(y,0,0)
markevery = range(1, len(x))
self.plot, = plt.plot(x, y, marker=markers[index], markevery=markevery,
ls="", label=self.legend[index])
I am getting a horrible fit when I am trying to fit a parabola to this data.
I am initially making a histogram of the data which is the position of an object and then plotting the negative log values of the histogram bin counts to the position using a parabola fit.
the code I am using is this:
time,pos=postime()
plt.plot(time, pos)
poslen=len(pos)
plt.xlabel('Time')
plt.ylabel('Positions')
plt.show()
n,bins,patches = plt.hist(pos,bins=100)
n=n.tolist()
plt.show()
l=len(bins)
s=len(n)
posx=[]
i=0
j=0
pbin=[]
sig=[]
while j < (l-1):
pbin.append((bins[j]+bins[j+1])/2)
j=j+1
while i < s:
if n[i]==0:
pbin[i]=0
else:
sig.append(np.power(1/n[i],2))
n[i]=n[i]/poslen
n[i]=np.log(n[i])
n[i]=n[i]*(-1)
i=i+1
n[:]=[y for y in n if y != 0]
pbin[:]=[y for y in pbin if y != 0]
from scipy.optimize import curve_fit
def parabola(x, a , b):
return a * (np.power(x,2)) + b
popt, pcov = curve_fit(parabola, pbin, n)
print popt
plt.plot(pbin,n)
plt.plot(pbin, parabola(pbin, *popt), 'r-')
I am not sure why you are computing the histogram... But here is a working example which does not require histogram computation.
import numpy as np
from scipy.optimize import curve_fit
from matplotlib import pyplot
time_ = np.arange(-5, 5, 0.1)
pos = time_**2 + np.random.rand(len(time_))*5
def parabola(x, a, b):
return a * (np.power(x, 2)) + b
popt, pcov = curve_fit(parabola, time_, pos)
yfit = parabola(time_, *popt)
pyplot.plot(time_, pos, 'o')
pyplot.plot(time_, yfit)
Also, if your time_ vector is not uniformly sampled, and you want it to be uniformly sampled for the fit, you can do: fittime_ = np.linsapce(np.min(time_), np.max(time_)) and then yfit = parabola(fittime_, *popt).
You can also use matrix inversion.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-5,5,100)
Y = (np.power(x,2) + np.random.normal(0,1,x.shape)).reshape(-1,1)
X = np.c_[np.ones(x.shape), x, np.power(x,2)]
A = np.linalg.inv(X.transpose().dot(X)).dot(X.transpose().dot(Y))
Yp = X.dot(A)
fig = plt.figure()
ax = fig.add_subplot()
plt.plot(x,Y,'o',alpha=0.5)
plt.plot(x,Yp)
plt.show()
The matrix form is
X*A=Y
A=(Xt*X)-1*Xt*Y
You can have a better idea here if needed. It does not always work out and you may want to apply some form of regularization.
I want to render a 6th degree function with matplotlib, it works with this code i found, but not with python3.
import numpy as np
from matplotlib import pyplot as plt
def langrange_polynomial(X, Y):
def L(i):
return lambda x: np.prod([(x-X[j])/(X[i]-X[j]) for j in range(len(X)) if i != j]) * Y[i]
Sx = [L(i) for i in range(len(X))] # summands
return lambda x: np.sum([s(x) for s in Sx])
# cut something
# Here i get the points with a function
(X, Y) = [1,2,3,4,5,6,7],[0,20,10,4,3,40,4]
F = langrange_polynomial(X, Y)
x_range = np.linspace(X[0], X[-1], 100)
plt.plot(X, Y, 'ro')
plt.plot(x_range, map(F, x_range))
plt.xlabel(r'$x$')
plt.ylabel(r'$F(x)$')
plt.title('Lagrange polynomial interpolation')
plt.grid(True)
plt.show()
Get this Error:
raise ValueError("x and y must have same first dimension")
ValueError: x and y must have same first dimension
in that Line:
plt.plot(x_range, map(F, x_range))
I read about something about declare the X,Y Coordinates to an np.array, but that did not worked anyway. What do I have to do in Python3.5?
In python 3, map(function, iterable) returns an iterator instead of a list.
You would need to get a list via
list(map(function, iterable))
or, more specifically in this case
plt.plot(x_range, list(map(F, x_range)))