I'm currently trying to plot a graph of iterations of a certain function in python. I have defined the function as stated below but I am unsure on how to plot the graph such that the y value is on the y axis and the iteration number is on the x axis.
So, I have tried using the plt.plot function with different values in as my x values but using logistic(4, 0.7) as the y value for the y axis.
def logistic(A, x):
y = A * x * (1 - x)
return y
But each return an error. Can anyone shed any light on this, I want to do a total of 1000 iterations.
I dont understand much what you are saying concerning x being number ofiteration while you are showing us function logistic(4, 0.7). As far as I know, iterations is integer, whole number. You cant iterate just halfly or partially
def logistic(A, x):
y = A * x * (1 - x)
return y
A = 1
x_vals = []
y_vals = []
for x in range(1,1000):
x_vals.append(x)
y_vals.append(logistic(A,x))
#plt.plot(x_vals,y_vals) # See every iteration
#plt.show()
plt.plot(x_vals,y_vals) # See all iterations at once
plt.show()
Ah, the logistic map. Are you trying to make a cobweb plot? If so, your error may be elsewhere. As others have mentioned, you should post the error message and your code, so we can better help you. However, based on what you've given us, you can use numpy.arrays to achieve your desired result.
import numpy as np
import matplotlib.pyplot as plt
start = 0
end = 1
num = 1000
# Create array of 'num' evenly spaced values between 'start' and 'end'
x = np.linspace(start, end, num)
# Initialize y array
y = np.zeros(len(x))
# Logistic function
def logistic(A, x):
y = A * x * (1 - x)
return y
# Add values to y array
for i in range(len(x)):
y[i] = logistic(4, x[i])
plt.plot(x,y)
plt.show()
However, with numpy.arrays, you can omit the for loop and just do
x = np.linspace(start, end, num)
y = logistic(4, x)
and you'll get the same result, but faster.
Related
Thanks to Veritasium great video about the topic, I was planning to do a quick replication of the animation he showed in the video where the number bouncing up and down until hit the number 1, depending on the initial number.
Below I figured out a version of code to implement the animation. But I have a question and confusion while constructing the code.
I found that if I don't initialize the y-data as y=np.empty(100) instead with a empty list, it will throw an error list assignment index out of range
So I'm very confused why I can't start with a empty list, because I know, depending on the value of y_start the len(y) varies. If I can collect those calculated y value into a list (converting them into array later) then I don't have to go the whole night-yard setting plt.xlim(1,100) (instead, I could just set plt.xlim(0,len(y)) also due to the potential remaining 0.0 value in the final y-data, I have to add additional condition (2nd after and) in the if statement -> if y[i] % 2 == 0 and y[i] != 0: Otherwise, it goes haywire even after y reached the value 1....
In addition, I want to add y-data's value displaying on top of the each individual point, but I have no clue how to implement that in the code...It would be greatly appreciate if anyone can help on this issue to make the animation looks more "complete"!
Here is the code that I've tested
import numpy as np
from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt
def odd(num):
return (num*3)+1
def even(num):
return num // 2
y_start = 33
x = np.linspace(0, 100, 100)
# y = []
def collatz():
y = np.empty(100)
y[0] = y_start
for i in range(0,100):
if y[i] % 2 == 0 and y[i] != 0:
y[i+1] = even(y[i])
else:
y[i+1] = odd(y[i])
if y[i+1] == 1:
break
return y
y = collatz()
fig = plt.figure()
plt.xlim(1,100)
plt.ylim(1,max(y))
draw, = plt.plot([],[])
def update(idx):
draw.set_data(x[:idx], y[:idx])
return draw,
a = FuncAnimation(fig, update, frames=len(x), interval=90)
plt.show()
So again, my questions are,
why starting with an empty list to contain calculated y fails?
Also, in the early version, inside the collatz function definition, my code was like:
def collatz():
y = np.empty(100)
y[0] = y_start
for i in range(0,100):
while y[i] != 1:
if y[i] % 2 == 0 and y[i] != 0:
y[i+1] = even(y[i])
else:
y[i+1] = odd(y[i])
if y[i+1] == 1:
break
return y
The compilation freezes, the code seems undergoes an infinite cycle...I don't know, is it the usage of the while statement ? what should I do/add to correct it?
I have rewritten your code (works on my machine), and will try to answer your questions
You cannot start from an empty list for y because the collatz() function needs a starting point. Hence, if y is empty, there is nothing to start from and the function fails. In the new code below I have added a parameter start to your function (in the code: 49). This is now the new starting point of your function. Note that if you want a random starting point instead of one defined by you, you can delete start, and replace y = [start] with y = [int(np.random.randint(1, 100, 1))] or another code that draws a random integer.
Now collatz uses a while loop: it works as long as y is larger than 1 (hence for y = 0 or 1 it will stop). Note that the -1 operator means 'the last element added to y'. For each number it does the even() or odd() function, and then it adds the number to the list using append. This ensures that the list is only as long as it needs to be. Note that in this case a while loop is the best option since you don't know how long the loop will last. When you have a fixed amount of iterations, a for loop should be chosen.
Finally, x is determined based on the length of y.
from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt
def odd(num):
return (num*3)+1
def even(num):
return num // 2
def collatz(start):
y = [start]
while y[-1] > 1:
if y[-1] % 2 == 0:
y.append(even(y[-1]))
else:
y.append(odd(y[-1]))
return y
y = collatz(49)
x = list(range(len(y)))
fig = plt.figure()
plt.xlim(1,len(y))
plt.ylim(1,max(y))
draw, = plt.plot([],[])
def update(idx):
draw.set_data(x[:idx], y[:idx])
return draw
a = FuncAnimation(fig, update, frames=len(x), interval=90)
plt.show()
I've already created a code for random walk of 10000 steps and then repeated it 12 times and stored each run in a separate text file (which was required in the question). I then calculated the mean square displacement of it(not sure if it's done correct). I now need to 'plot my Mean Square Displacement as a function of δt, including errorbars σ = std(MSD)/√N, where std(MSD) is the standard deviation among the different runs and N is the number of runs.' and then compute the diffusion constant D from the curve and check that D = 2 (∆/dt) where dt = 1.
Here is my code so far:
import numpy as np
import matplotlib.pyplot as plt
import random as rd
import math
a = (np.zeros((10000, 2), dtype=np.float))
def randwalk(x,y):
theta= 2*math.pi*rd.random()
x+=math.cos(theta); # This uses the equation given, since we are told the spatial unit = 1
y+=math.sin(theta);
return (x,y)
x, y = 0.,0.
for i in range(10000): # Using for loop and range function to initialize the array
x, y = randwalk(x,y)
a[i,:] = x,y
fn_base = "random_walk_%i.txt" # Saves each run in a numbered text file, fn_base is a varaible to hold format
N = 12
for j in range(N):
rd.seed(j) # seed(j) explicitly sets the seed to random numbers
x , y = 0., 0.
for i in range(10000):
x, y = randwalk(x,y)
a[i,:] = x, y
fn = fn_base % j
np.savetxt(fn, a)
destinations = np.zeros((12, 2), dtype=np.float)
for j in range(12):
x, y = 0., 0.
for i in range(10000):
x, y = randwalk(x, y)
destinations[j] = x, y
square_distances = destinations[:,0] ** 2 + destinations[:,1] ** 2
m_s_d = np.mean(square_distances)
I think that to do it I just have to plot the msd against the number of steps? But I'm not sure how to do this. I saw a similar question on stackoverflow but the code for it is different than mine and I don't understand how to use that for my code.
I tried to do next
plt.figure()
t = 10000
plt.plot(m_s_d, t)
plt,show()
But this gives an error as the dimensions are not equal.
Edit ** I think my issue is that I am trying to plot it against number of steps when I should be plotting it against the change in time. However I can’t work out how to calculate the change in time dt?
Apologies in advance is question isn't formulated well, I am fairly new to computing. Thank you.
I tried to plot pairs (x,y) which are solutions to the equation y^2 + y = x^3 + y(x^2) using the following code:
import numpy as np
y = np.arange(0,12,.01)
x = np.arange(0,18,.01)
for i in enumerate(y):
for j in enumerate(x):
if (i**2)+i == j**3 + i*(j**2):
plot(i,j)
However, I got the following error:
"TypeError: unsupported operand type(s) for ** or pow(): 'tuple' and 'int'"
Anybody can help me to figure out how can I plot solutions?
I have also another question: Is it possible to store each pair of solution in a variable so we can use specific pairs of solutions in the future?
enumerate yields (index, value) tuples, you can use unpacking to get each one separately in the loop header:
for i_ind, i in enumerate(y):
for j_ind, j in enumerate(x):
I suggest you modify your formulation and plot the square difference between LHS and RHS instead:
x = np.linspace(-1, 1, 100)
y = np.linspace(-1, 1, 100)
X, Y = np.meshgrid(x, y)
def F(p):
x, y = p
v = y**2 + y - x**3 - y * (x**2)
return v**2
Z = F((X, Y))
plt.contourf(X, Y, Z)
plt.colorbar()
idx = np.where(np.abs(Z) < 1e-4)
plt.scatter(X[idx], Y[idx], marker='+', color='w')
You can also use scipy.optimize.fmin(F, [1, 1]) to get the exact solution of F=0, where [1, 1] is your initial guess. In this case, different initial guess will result in different solution.
while the other answer describes the mechanical transform needed to stop that exception being thrown, it's not going to get any points in your plot. Numpy is a numeric library, while you want/need to solve the equation.
numpy.arange(0, 12, 0.01) generates a finite series of numbers starting at 0 and incrementing by 0.01 until it hits 12. you give an equation above which is mostly translated into Python code, and evaluate it on these finite series of numbers and ask it to plot values where both expressions evaluate to the same number. floats in Python are 64-bit floats so this equality is checked to approx 15 decimal digits, which will basically not happen for your numbers.
instead of doing what you're attempting to do you want to use something like Sympy which would actually help you. to get started we do:
from sympy import symbols, solveset, simplify, lambdify
x, y = symbols('x y')
eq1 = y**2 + y
eq2 = x**3 + x*y**2
ss = solveset(eq1 - eq2, y)
which names a pair of symbols, puts them into some equations and solves for when eq1 == eq2 (equivalently when their difference is zero).
next you want to plot these solutions, which can be done in this case:
import numpy as np
import matplotlib.pyplot as plt
xx = np.linspace(-5, 4, 101)
for eq in ss:
fn = lambdify(x, eq)
yy = fn(xx)
# hide complex solutions
yy[~np.isreal(yy)] = np.nan
plt.plot(xx, np.real(yy), label=simplify(eq))
plt.legend()
this starts by pulling in numpy and matplotlib, then sampling points on the x-axis at which we want to evaluate the functions, then loop through solutions turning them into Python functions that we can evaluate to get numeric answers, next we evaluate this on our sampled points, discard complex solutions, and plot the results.
this gives:
the gap around x = -4.5 is due to sampling at this point being sparse. we can check by evaluating our equations at x=-4.5, y=10, and I get ~110 for both equations
I have a set of data in a numpy array - x-values, lets say between 0-100, and y-values. I need to get the gradient to a specific x-value ex. x=20 but I can only get the np.gradient function to give me the gradient at a certain index-value. right now I have:
g=np.gradient(y)
print(g[20])
but this of course gives me the gradient at i=20 and not x=20
I have both the x and y values in one 2D array and 2 x 1D arrays defined in my script
EDIT:
I actually came to solve it like this:
def grad(x, value):
def find_nearest(x, value):
x = np.asarray(Timeppmh)
idx = (np.abs(x - value)).argmin()
i = x.tolist().index(x[idx])
return i
g=np.gradient(yp,x)
find_nearest(x,value)
return g[find_nearest(x,value)]
If the value 20 is in x you could just do j[x == 20]. However, if that is not the case, you would need to approximate the gradient value. You can use for example linear interpolation.
import numpy as np
x = np.linspace(0, 100, 80)
print(20 in x) # 20 is not in x
# False
y = x * x + 3 * x + 2
# Pass x as second argument for value spacing
g = np.gradient(y, x)
print(np.interp(20, x, g)) # Should be 43
# 43.00000000000001
I want to create a logarithmic function with base x then plot it: y=logx10.
So I use:
y= math.log(10,x)
but it returned an error said: only length-1 array can be converted to Python scalars.
So what is the correct way to create a log function with base x?
The simple way to get a "smoother" line is by increasing the number of points (i.e., make length bigger.)
Also, you likely want to sort your x list before calculating and plotting:
length = 100 # or higher
:
x = sorted([random.uniform(rand_min, rand_max) for r in xrange(length)])
y = [math.log(10, _x) for _x in x]
Since you want 2 lists of values (x, y), you will have to generate the x list first, and use it to generate the y list:
import math
import random
length = 10
rand_min = 0.02
rand_max = 0.91
x = [random.uniform(rand_min, rand_max) for r in xrange(length)]
y = [math.log(10, _x) for _x in x]
Here you have lists x and y, both of length length.