Having problems plotting a partly undefined function - python

I have an assignment for my Applied Computer Science class in which we are to test the strength and qualities of an algorithm that tries to find the k:th highest value in a list. This is to be tested both for varying k:s (0, 1, 2, ..., k=N), and varying N:s where I have chosen k=0 and N (1, 2, ..., N). We're supposed to determine whether the algorithm ever makes more than pi*N comparisons as well as log2(N/2 - k)*N comparisons.
To find some clarity in this I made two plots, both having number of comparisons as the y-axis, and k and N respectively for the x-axis. Alongside the plots I want the functions y = pi*N and y = log2(N/2 - k)*N. The problem is I get a ValueError for the second function, most definitely when N/2 = k. I would still like to plot it in python and my question is how to get around this.
The rest of the code isn't really relevant.
My question is: how can I plot this function while circumventing it's undefined parts? I still want to illustrate the undefined part so I don't want to make exceptions in which a simplification is made.
def plotHelper(x, yA, yS, title, trials):
yPi = list()
yLogN = list()
for point in x:
yPi.append(point*math.pi)
yLogN.append((trials*math.log(trials/2 - point, 2)
plt.figure()
plt.title(title)
plt.plot(x, yA)
plt.plot(x, yS)
plt.plot(x, yPi)
plt.plot(x, yLogN)
plt.grid(True)
plt.legend(["Mean", "Standard Deviation", "y = pi * N"])
plt.ylabel("Comparisons")
plt.xlabel("k")
plt.show()
def plot():
choice = initiate()
yA, yS, trials = trialFunc(choice)
x = range(0, trials)
f_of_k = "Comparisons as a function of desired k (N elements)"
f_of_n = "Comparisons as a function of elements (k = 0)"
if choice:
title = f_of_k
else:
title = f_of_n
plotHelper(x, yA, yS, title, trials)

If you cannot represent a value of a function as a number, you can represent it as a Not-a-Number aka NaN. There's no ready-made constant for it, but you can easily produce that value:
NaN = float('NaN')
Now your function can go like this:
def function_to_plot(n): # A contrived example.
if abs(n) <= 1:
return NaN
return sqrt(n * n - sin(n) ** 2)
After that, matplotlib just works, it knows how to skip points that are NaNs.
If you just want to tabulate your function by hand, you can safely print NaNs using format for floats.
For a bit more detail, you can use float('+inf') and float('-inf') to represent infinities.
Also, just in case, Python works fine with complex numbers; import cmath and do things like assert cmath.sqrt(-2j) == (1-1j).

Related

modeling 5 ordinary differential equations and plotting the model to show the 5 equations

hello I am newbie at python and coding for the most part and I have 5 ordinary differential equations.(non-linear) that I want to model and have them plot. I have the parameters that are given, my main issue has been setting the independent variables to be a function of z. As well as setting the 'S' parameters to be a function of time since they vary depending on the time of year.
edited CODE
I've been able to have the code run with set parameters. I now wonder how I could take these parameters and make them behave at different times. The parameters that are set on this code are for a specific amount of "days" during the year. They are not meant to be consistent throughout. How could I implement time to have them be dependent on it?
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import math
from math import e
def func(z,t):
xh, xf, y, m, n = z
v1,v2,v3 = 0.05,0.06,0.07
B1,B2,B3 = 0.1984,0.1593,0.04959
d1,d2,d3 = 0.02272,0.02272,0.2
o1,o2 = 0.25,0.75
S1=S2=S3=0.005
S4=S5=0.3
p = 0
u = 500
k = 0.000075
a = 0.4784
r = 0.0165
K = 8000
i = 2
H = e**(-m*k)
g = ((xh+xf)**i)/((K**i)+((xh+xf)**i))
R = o1-(o2*(xf/(xh+xf+.002)))
P1 =(xh+xf)/(xh+y+xf+.002)
P2 = 1-((m+n)/(a*(xh+y+xf+.002)))
P3 = y/(xh+y+xf+.002)
dxhdt = (u*g*H)-(B1*(m*(xh/(xh+y+xf+.002))))-((d1+S1)*xh)-((v1*(m+n))*xh)-(xh*R)
dxfdt = (xh*R)-(B1*(m*(xf/(xh+y+xf+.002))))-((p+d2+S2)*xf)-(v2*(m+n)*xf)
dydt = (B1*(m*P1))-((d3+S3)*y)-((v3*(m+n))*y)
dmdt =(r*(m*P2))+(B2*(n*P3))-(B3*(m*P1))-(S4*m)
dndt = (r*(n*P2))-(B2*(n*P3))+(B3*(m*P1))-(S5*n)
return [dxhdt,dxfdt,dydt,dmdt,dndt]
z0=[13000,11000,0,0,0]
t = np.linspace(0,100,1000)
xx=odeint(func,z0,t)
plt.figure(1)
plt.plot(t,xx[:,0],'b-',label = 'xh')
plt.plot(t,xx[:,1],'y-',label = 'xf')
plt.plot(t,xx[:,2],'g-',label = 'y')
plt.plot(t,xx[:,3],'r-',label = 'm')
plt.plot(t,xx[:,4],'m-',label = 'n')
plt.legend()
plt.ylabel('POPULATION')
plt.xlabel('TIME')
plt.show()
I though about creating two different functions and looping the plot. How do you makes "days" of function of t? just declaring it is? I get error code "TypeError: 'float' object cannot be interpreted as an integer"
z0=[13000,11000,0,0,0]
t = np.linspace(0,91.25,1000)
xx=odeint(func,z0,t)
xy=odeint(func2,z0,t)
plt.figure(1)
for t in range(1,91.25):
plt.plot(t,xx[:,0],'b-',label = '$x_h$')
plt.plot(t,xx[:,1],'y-',label = '$x_f$')
plt.plot(t,xx[:,2],'g-',label = 'y')
plt.plot(t,xx[:,3],'r-',label = 'm')
plt.plot(t,xx[:,4],'m-',label = 'n')
for t in range(91.25,182.50):
plt.plot(t,xy[:,0],'b-',label = '$x_h$')
plt.plot(t,xy[:,1],'y-',label = '$x_f$')
plt.plot(t,xy[:,2],'g-',label = 'y')
plt.plot(t,xy[:,3],'r-',label = 'm')
plt.plot(t,xy[:,4],'m-',label = 'n')
plt.legend()
plt.ylabel('POPULATION')
plt.xlabel('TIME')
plt.show()
I get what you mean by an ODE, but please expand it so others that are not cognizant of mathematics can understand.
If you want these to be a function of z, then you must declare a function something() and assign the variables this function. This way, your values will change with respect to changes in z.
Also by convention, I don't recommend using this much of variable declarations. Abstract these as much as possible. As an alternative, you can declare similar variables in the same line, like
v1, v2, v3 = 0.5, 0.6, 0.7
etc. This will make it much more readable.
If you don't have any syntax error due to multiple assignments in the first line, I recommend change each of this to be a function of z. Divide your bigger function to smaller chunks, make each of this a different function. This way you can manipulate results directly and code will be much more readable.
You prefer the state vector to be composed as
xh, xf, y, m, n
This interpretation of the state vector then needs to be applied everywhere, which means that you have to change the first line of the ODE function to
xh, xf, y, m, n = z
Also check that your fractions are implemented as they were in paper, esp. P1 appears suspicious. But without the genesis of the equation I can not say that it is wrong as it is.

Python: bisection method

I am trying to write a program to determine the zeros of the given function (f(x) := ln((sin(x**(1/2))**3) + 2) - 1, using the bisection method. The values a and b, which are the initial values used in the bisection method, are inserted on the program already. All it neeeds to do is show the plot and determine the zeros, but I can't get it to run (it stops on line 22). Can anyone spot the error?
import matplotlib.pyplot as plt
import numpy as np
import math
t = np.arange(0.5, 6.0, 0.01)
s = np.log((np.sin(np.sqrt(t)))**3+2)-1
z = len(t)*(0.0,)
plt.plot(t, s, t, z)
plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('A procura do zero')
plt.grid(True)
plt.savefig("test.pdf")
plt.show()
def bisseçao(a,b):
z=(a+b)/2
while b-a>10**(-5):
if (math.log((math.sin(math.sqrt(a)))**3+2)-1)*(math.log((math.sin(math.sqrt(z)))**3+2)-1)<0:
b=(a+z)/2
if (math.log((math.sin(math.sqrt(b)))**3+2)-1)*(math.log((math.sin(math.sqrt(z)))**3+2)-1)<0:
a=(z+b)/2
return a
a1=1
b1=2
a2=4
b2=5
print("Os zeros são:",bisseçao(a1,b1),bisseçao(a2,b2))
Here is the first problem:
z=(a+b)/2
while b-a>10**(-5):
You need to cumpute a new z in every iteration not only at the beginning of the function.
Second problem part 1:
b=(a+z)/2
Second problem part 2:
a=(z+b)/2
Setting the upper/lower bound between lower/upper bound and center point is not correct. They should be set exactly at the center point.
Correct implementation (with a small simplification for clarity - no need to type the whole function five times over):
func = lambda x: np.log((np.sin(np.sqrt(x)))**3+2)-1
def bisseçao(a, b):
while b-a>10**(-5):
z = (a + b)/2
if func(a)*func(z)<0:
b = z
if func(b)*func(z)<0:
a = z
return a
P.S. The code will run into a problem if z happens to fall exactly at the root. You may want to check for this condition explicitly.
P.P.S. The code will also fail if the starting interval does not contain a root. You may want to check for this condition too.

python (sympy) implicit function: get values instead of plot?

I am new to sympy but I already get a nice output when I plot the implicit function (actually the formula for Cassini's ovals) using sympy:
from sympy import plot_implicit, symbols, Eq, solve
x, y = symbols('x y')
k=2.7
a=3
eq = Eq((x**2 + y**2)**2-2*a**2*(x**2-y**2), k**4-a**4)
plot_implicit(eq)
Now is it actually possible to somehow get the x and y values corresponding to the plot? or alternatively solve the implicit equation without plotting at all?
thanks! :-)
This is an answer addressing your
is it actually possible to somehow get the x and y values corresponding to the plot?
and I say "addressing" because it's not possible to get the x and y values used to draw the curves — because the curves are not drawn using a sequenc of 2D points… more on this later,
TL;DR
pli = plot_implicit(...)
series = pli[0]
data, action = series.get_points()
data = np.array([(x_int.mid, y_int.mid) for x_int, y_int in data])
Let's start with your code
from sympy import plot_implicit, symbols, Eq, solve
x, y = symbols('x y')
k=2.7
a=3
eq = Eq((x**2 + y**2)**2-2*a**2*(x**2-y**2), k**4-a**4)
and plot it, with a twist: we save the Plot object and print it
pli = plot_implicit(eq)
print(pli)
to get
Plot object containing:
[0]: Implicit equation: Eq(-18*x**2 + 18*y**2 + (x**2 + y**2)**2, -27.8559000000000) for x over (-5.0, 5.0) and y over (-5.0, 5.0)
We are interested in this object indexed by 0,
ob = pli[0]
print(dir(ob))
that gives (ellipsis are mine)
['__class__', …, get_points, …, 'var_y']
The name get_points sounds full of promise, doesn't it?
print(ob.get_points())
that gives (edited for clarity and with a big cut)
([
[interval(-3.759774, -3.750008), interval(-0.791016, -0.781250)],
[interval(-3.876961, -3.867195), interval(-0.634768, -0.625003)],
[interval(-3.837898, -3.828133), interval(-0.693361, -0.683596)],
[interval(-3.847664, -3.837898), interval(-0.673830, -0.664065)],
...
[interval(3.837895, 3.847661), interval(0.664064, 0.673830)],
[interval(3.828130, 3.837895), interval(0.683596, 0.693362)],
[interval(3.867192, 3.876958), interval(0.625001, 0.634766)],
[interval(3.750005, 3.759770), interval(0.781255, 0.791021)]
], 'fill')
What is this? the documentation of plot_implicit has
plot_implicit, by default, uses interval arithmetic to plot functions.
Following the source code of plot_implicit.py and plot,py one realizes that, in this case, the actual plotting (speaking of the matpolotlib backend) is just a line of code
self.ax.fill(x, y, facecolor=s.line_color, edgecolor='None')
where x and y are constructed from the list of intervals, as returned from .get_points(), as follows
x, y = [], []
for intervals in interval_list:
intervalx = intervals[0]
intervaly = intervals[1]
x.extend([intervalx.start, intervalx.start,
intervalx.end, intervalx.end, None])
y.extend([intervaly.start, intervaly.end,
intervaly.end, intervaly.start, None])
so that for each couple of intervals matplotlib is directed to draw a filled rectangle, small enough that the eye sees a continuous line (note the use of None to have disjoint rectangles).
We can conclude that the list of couples of intervals
l_xy_intervals = ((pli[0]).get_points())[0]
represents rectangular areas where the implicit expression you are plotting is
"true enough"
You can do this, even with interval math, if you try getting the mid point of each interval. Starting from your code, and slightly change it, by saving the plot_implicit object in a variable called g we have:
from sympy import plot_implicit, symbols, Eq, solve
x, y = symbols('x y')
k=2.7
a=3
eq = Eq((x**2 + y**2)**2-2*a**2*(x**2-y**2), k**4-a**4)
g = plot_implicit(eq)
Now let's save in a variable named ptos the intervals that were used to draw the plot.
ptos = g[0].get_points()[0]
This way ptos[0][0] will be the first interval in the x axis and ptos[0][1] will be its pair in the y axis. The intervals have a property called mid which gives the middle point of the interval. So you can suppose that ptos[0][0].mid, ptos[0][1].mid will be a pair x,y "true enough" to be one of our numerical solutions.
This way, a data frame composed of this middle point pairs can be generated with:
intervs = np.array(dtype='object')
meio = lambda x0:x0.mid
px = list(map(meio, intervs[:,0]))
py = list(map(meio, intervs[:,1]))
import pandas as pd
dados = pd.DataFrame({'x':px, 'y':px})
dados.head()
Which in this example would give us:
x y
0 -1.177733 0.598826
1 -1.175389 0.596483
2 -1.175389 0.598826
3 -1.173045 0.596483
4 -1.173045 0.598826
This idea of getting the intervals middle points can be used whenever one needs to move from "interval math" to "standard" point level math. Hope this helps. Regards.

Graphing n iterations of a function- Python

I'm studying dynamical systems, particularly the logistic family g(x) = cx(1-x), and I need to iterate this function an arbitrary amount of times to understand its behavior. I have no problem iterating the function given a specific point x_0, but again, I'd like to graph the entire function and its iterations, not just a single point. For plotting a single function, I have this code:
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
def logplot(c, n = 10):
dt = .001
x = np.arange(0,1.001,dt)
y = c*x*(1-x)
plt.plot(x,y)
plt.axis([0, 1, 0, c*.25 + (1/10)*c*.25])
plt.show()
I suppose I could tackle this by the lengthy/daunting method of explicitly creating a list of the range of each iteration using something like the following:
def log(c,x0):
return c*x0*(1-x)
def logiter(c,x0,n):
i = 0
y = []
while i <= n:
val = log(c,x0)
y.append(val)
x0 = val
i += 1
return y
But this seems really cumbersome and I was wondering if there were a better way. Thanks
Some different options
This is really a matter of style. Your solution works and is not very difficult to understand. If you want to go on on those lines, then I would just tweak it a bit:
def logiter(c, x0, n):
y = []
x = x0
for i in range(n):
x = c*x*(1-x)
y.append(x)
return np.array(y)
The changes:
for loop is easier to read than a while loop
x0 is not used in the iteration (this adds one more variable, but it is mathematically easier to understand; x0 is a constant)
the function is written out, as it is a very simple one-liner (if it weren't, its name should be changed to be something else than log, which is very easy to confuse with logarithm)
the result is converted into a numpy array. (Just what I usually do, if I need to plot something)
In my opinion the function is now legible enough.
You might also take an object-oriented approach and create a logistic function object:
class Logistics():
def __init__(self, c, x0):
self.x = x0
self.c = c
def next_iter(self):
self.x = self.c * self.x * (1 - self.x)
return self.x
Then you may use this:
def logiter(c, x0, n):
l = Logistics(c, x0)
return np.array([ l.next_iter() for i in range(n) ])
Or if you may make it a generator:
def log_generator(c, x0):
x = x0
while True:
x = c * x * (1-x)
yield x
def logiter(c, x0, n):
l = log_generator(c, x0)
return np.array([ l.next() for i in range(n) ])
If you need performance and have large tables, then I suggest:
def logiter(c, x0, n):
res = np.empty((n, len(x0)))
res[0] = c * x0 * (1 - x0)
for i in range(1,n):
res[i] = c * res[i-1] * (1 - res[i-1])
return res
This avoids the slowish conversion into np.array and some copying of stuff around. The memory is allocated only once, and the expensive conversion from a list into an array is avoided.
(BTW, if you returned an array with the initial x0 as the first row, the last version would look cleaner. Now the first one has to be calculated separately if copying the vector around is desired to be avoided.)
Which one is best? I do not know. IMO, all are readable and justified, it is a matter of style. However, I speak only very broken and poor Pythonic, so there may be good reasons why still something else is better or why something of the above is not good!
Performance
About performance: With my machine I tried the following:
logiter(3.2, linspace(0,1,1000), 10000)
For the first three approaches the time is essentially the same, approximately 1.5 s. For the last approach (preallocated array) the run time is 0.2 s. However, if the conversion from a list into an array is removed, the first one runs in 0.16 s, so the time is really spent in the conversion procedure.
Visualization
I can think of two useful but quite different ways to visualize the function. You mention that you will have, say, 100 or 1000 different x0's to start with. You do not mention how many iterations you want to have, but maybe we will start with just 100. So, let us create an array with 100 different x0's and 100 iterations at c = 3.2.
data = logiter(3.6, np.linspace(0,1,100), 100)
In a way a standard method to visualize the function is draw 100 lines, each of which represents one starting value. That is easy:
import matplotlib.pyplot as plt
plt.plot(data)
plt.show()
This gives:
Well, it seems that all values end up oscillating somewhere, but other than that we have only a mess of color. This approach may be more useful, if you use a narrower range of values for x0:
data = logiter(3.6, np.linspace(0.8,0.81,100), 100)
you may color-code the starting values by e.g.:
color1 = np.array([1,0,0])
color2 = np.array([0,0,1])
for i,k in enumerate(np.linspace(0, 1, data.shape[1])):
plt.plot(data[:,i], '.', color=(1-k)*color1 + k*color2)
This plots the first columns (corresponding to x0 = 0.80) in red and the last columns in blue and uses a gradual color change in between. (Please note that the more blue a dot is, the later it is drawn, and thus blues overlap reds.)
However, it is possible to take a quite different approach.
data = logiter(3.6, np.linspace(0,1,1000), 50)
plt.imshow(data.T, cmap=plt.cm.bwr, interpolation='nearest', origin='lower',extent=[1,21,0,1], vmin=0, vmax=1)
plt.axis('tight')
plt.colorbar()
gives:
This is my personal favourite. I won't spoil anyone's joy by explaining it too much, but IMO this shows many peculiarities of the behaviour very easily.
Here's what I was aiming for; an indirect approach to understanding (by visualization) the behavior of initial conditions of the function g(c, x) = cx(1-x):
def jam(c, n):
x = np.linspace(0,1,100)
y = c*x*(1-x)
for i in range(n):
plt.plot(x, y)
y = c*y*(1-y)
plt.show()

python return array from iteration

I want to plot an approximation of the number "pi" which is generated by a function of two uniformly distributed random variables. The goal is to show that with a higher sample draw the function value approximates "pi".
Here is my function for pi:
def pi(n):
x = rnd.uniform(low = -1, high = 1, size = n) #n = size of draw
y = rnd.uniform(low = -1, high = 1, size = n)
a = x**2 + y**2 <= 1 #1 if rand. draw is inside the unit cirlce, else 0
ac = np.count_nonzero(a) #count 1's
af = np.float(ac) #create float for precision
pi = (af/n)*4 #compute p dependent on size of draw
return pi
My problem:
I want to create a lineplot that plots the values from pi() dependent on n.
My fist attempt was:
def pipl(n):
for i in np.arange(1,n):
plt.plot(np.arange(1,n), pi(i))
print plt.show()
pipl(100)
which returns:
ValueError: x and y must have same first dimension
My seocond guess was to start an iterator:
def y(n):
n = np.arange(1,n)
for i in n:
y = pi(i)
print y
y(1000)
which results in:
3.13165829146
3.16064257028
3.06519558676
3.19839679359
3.13913913914
so the algorithm isn't far off, however i need the output as a data type which matplotlib can read.
I read:
http://docs.scipy.org/doc/numpy/reference/routines.array-creation.html#routines-array-creation
and tried tom implement the function like:
...
y = np.array(pi(i))
...
or
...
y = pi(i)
y = np.array(y)
...
and all the other functions that are available from the website. However, I can't seem to get my iterated y values into one that matplotlib can read.
I am fairly new to python so please be considerate with my simple request. I am really stuck here and can't seem to solve this issue by myself.
Your help is really appreciated.
You can try with this
def pipl(n):
plt.plot(np.arange(1,n), [pi(i) for i in np.arange(1,n)])
print plt.show()
pipl(100)
that give me this plot
If you want to stay with your iterable approach you can use Numpy's fromiter() to collect the results to an array. Like:
def pipl(n):
for i in np.arange(1,n):
yield pi(i)
n = 100
plt.plot(np.arange(1,n), np.fromiter(pipl(n), dtype='f32'))
But i think Numpy's vectorize would be even better in this case, it makes the resulting code much more readable (to me). With this approach you dont need the pipl function anymore.
# vectorize the function pi
pi_vec = np.vectorize(pi)
# define all n's
n = np.arange(1,101)
# and plot
plt.plot(n, pi_vec(n))
A little side note, naming a function pi which does not return a true pi seems kinda tricky to me.

Categories