List values being replaced instead of being appended - python

I am attempting to append a value #y that is calculated using the ODEINT onto a list called #y_list. i created a new function called #saves_vals which does this at every iteration point. The list is growing as the iterations run(which is good) however the new value of #y replaces all the values previously generated. i have attempted to create a copy of the #y values using #y[:] however this continues to fail. i am fairly new to python. please assist
from matplotlib import pyplot as plt
import numpy as np
from scipy.integrate import odeint
y_list =[]
def saves_vals(list_y,y):
print (" the value of y being used now is " +str(y))
list_y.append(y[:])
print ( " this is the y_list, as it grows " + str(list_y))
return (list_y)
def model(y,t):
k= saves_vals(y_list,y)
dydt = - 2.0 *y
return dydt
t = np.linspace(0, 10, 10)
y_0 = 10
y = odeint(model,y_0,t)
plt.figure(figsize =(4,4))
plt.plot(t,y)
plt.show()
i am expecting the list of the y values to grow as the iterations progress however to keep the results of the past iterations for later comparison

Related

Curve Fitting Two Series Python

I am trying to curve fit a sinusoidal shaped data set, but I a getting an error saying 'Only size-1 arrays can be converted to Python scalars'. How do I correctly pass my two series for X and Y values to fit the curve?
def objective(x, a, b, c, d):
return a * math.sin(b - x) + c * x**2 + d
# choose the input and output variables
x = moon_data["Full Moon"].values.squeeze()
y = moon_data["Full Moon Price"].values.squeeze()
plt.scatter(x,y) # This works!
# curve fit
popt, _ = curve_fit(objective, x, y) # This is the line causing the error
Moon Data is a Dataframe that I turned into a Series using .squeeze(). The original data looks like this (first 3 rows):
Full Moon
Full Moon Price
1488
2020-05-07
10001.0
1489
2020-06-05
9617.17
1490
2020-07-05
9083.8
Only Size 1 Arrays Error is a TypeError that gets triggered when you enter an array as a parameter in a function or method which accepts a single scalar value. So, the problem in your function is here: math.sin(b - x)
x can only be a single scalar value but what you are assigning is moon_data["Full Moon"] as x which is an array. Change it to np.sin(b*x) it will work but I guess you want something else so you will have to change the function accordingly.
You can't put datetime object inside sin(). Math.sin() takes a single number, not array. So, use np.sin() instead. Convert the moon_data["Full Moon"] column to datetime then toordinal so that you can put it into sin.
import pandas as pd
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
def objective(x, a, b, c,d):
return a * np.sin(b*x) + c * x**2+d
# choose the input and output variables
x = moon_data["Full Moon"]
y = moon_data["Full Moon Price"]
X=pd.to_datetime(x).apply(lambda x:x.toordinal())
plt.scatter(x,y) # This works!
# curve fit
popt, _ = curve_fit(objective, X, y)

plot multiple curves on same plot inside function

I have a following function with takes 2 arguments psi,lam and returns 1 array y.
lam=np.arange(0,1,0.1)
psi=np.deg2rad(np.arange(0,361,1))
def test(psi,lam):
y=[]
for i in range(len(lam)):
sin_psi = np.sin(psi)
cos_psi = np.cos(psi)
sin_beta = lam*sin_psi
cos_beta = np.sqrt(1.0 - sin_beta**2)
ssin_pb = sin_psi*sin_beta
y.append((lam*(cos_psi/cos_beta)**2 - ssin_pb)/cos_beta + cos_psi)
plt.plot(psi,y[i])
return y
I would like the function to return range(len(lam))=10 plots of y on the vertical axis against psi on x axis.
However, it seems to be only plotting the same curve multiple times. Not sure what I am missing?
import matplotlib.pyplot as plt
import numpy as np
lam=np.arange(0,1,0.1)
psi=np.deg2rad(np.arange(0,361,1))
def test(angle,var):
sin_psi = np.sin(psi)
cos_psi = np.cos(psi)
sin_beta = var*sin_psi
cos_beta = np.sqrt(1.0 - sin_beta**2)
ssin_pb = sin_psi*sin_beta
return ((var*(cos_psi/cos_beta)**2 - ssin_pb)/cos_beta + cos_psi)
for i in lam:
plt.plot(psi,test(psi,i))
plt.show()
I moved the variable outside of the function, this way you may also use it for other cases. The only other thing is that you should call plt.show() after you're done drawing.
Your code has several problems the main being that the return function was inside the loop interrupting it after the first iteration. Imitating your code structure as closely as possible, we can rewrite the code as:
import numpy as np
import matplotlib.pyplot as plt
def test(psi,lam):
y=[]
for curr_lam in lam:
sin_psi = np.sin(psi)
cos_psi = np.cos(psi)
sin_beta = curr_lam*sin_psi
cos_beta = np.sqrt(1.0 - sin_beta**2)
ssin_pb = sin_psi*sin_beta
val = (curr_lam * (cos_psi/cos_beta)**2 - ssin_pb)/cos_beta + cos_psi
y.append(val)
plt.plot(psi, val)
plt.show()
return y
lam=np.arange(0, 1, 0.1)
psi=np.deg2rad(np.arange(0,361,1))
y = test(psi, lam)
print(y)
Sample output:
As Johan mentioned in the comments, you should also directly iterate over list/arrays. If you need to combine arrays, use
for x1, x2 in zip(arr1, arr2):
If you absolutely need the index value, use
for i, x in enumerate(arr):

Why does nothing showing up on my plot even with defined variables

So i made this code to create a plot that should look like this[This image was done in Mathematica] 1 but for some reason nothing shows up on the plot plot i made.does it have to something with the gam(x_2) or gam itself because i tried defining that as a range but still nothing. please teach me. From the plot made in matematica it seems like he set both the x and y ranges all the way up to 10,000.
import matplotlib.pyplot as plt
import numpy as np
import math
import pylab
%matplotlib inline
gam0 = 72.8
temp = 293.15
def gam(x_2):
return gam0 - 0.0187 * temp * math.log10(1+628.14*55.556*x_2)
x = range(0, 10000)
x_2= x
plt.plot('gam(x_2), x_2')
plt.xlabel('Log_10x_2')
plt.ylabel('gamma (erg cm^2)')
A few fixes needed; defining your function, there's an indent missing, also multiplying the whole array with ' * ' isn't working, so you can save up the values in a separate array through a for loop:
EDIT: Oh, and also while plotting, you don't put the variable names as strings, you just call them as they are.
import matplotlib.pyplot as plt
import numpy as np
import math
import pylab
%matplotlib inline
gam0 = 72.8
temp = 293.15
x = range(0, 10000)
x_2= x
def gam(x_2):
returns = []
for x_i in x_2:
returns.append(gam0 - 0.0187 * temp * math.log10(1+628.14*55.556*x_i))
return returns
plt.plot(gam(x_2), x_2)
plt.xlabel('Log_10x_2')
plt.ylabel('gamma (erg cm^2)')
plt.show()
Indent your function
def gam(x_2):
return gam0 - 0.0187 * temp * math.log10(1+628.14*55.556*x_2)
Find gam(x_2) for each item(x_2) in list x
gam_x = [gam(x_2) for x_2 in x]
Finally, plot and show.
plt.plot(gam_x, x)
plt.xlabel('Log_10x_2')
plt.ylabel('gamma (erg cm^2)')
plt.show()

Creating a bifurcation diagram in python

I am trying to come up with a code that will allow me to plot a diagram for period doubling bifurcation.
I am using the equation x = rx − 1(1 − x), and am trying to model it with r values from 0.5 to 4. Here is code that I am working with
startr = 0.5
finalr = 4
max_time = 200
x = [0.1]
r= np.linspace(.5,4,200)
for n in range(0,200):
x = np.append(r * x[n] * (1-x[n]))
plt.plot(x, label='x');
plt.xlabel('t');
This keeps getting kicked out
TypeError: append() missing 1 required positional argument: 'values'
The are the two absolutely necessary arguments for numpy.append(), taken from the Numpy reference.
arr : array_like Values are appended to a copy of this array.
values :
array_like These values are appended to a copy of arr. It must be of
the correct shape (the same shape as arr, excluding axis). If axis is
not specified, values can be any shape and will be flattened before
use.
Therefore, try using
np.append(x, r * x[n] * (1-x[n]))
inside your loop.
Logistic Map
Save file and run, png image file of graph will save in the same folder
import numpy as np
import matplotlib.pyplot as plt
Many =50000
x = np.random.rand(Many)
r = np.linspace(0,4.0, num= Many)
for i in range(1, 54):
x_a = 1-x
Data= np.multiply(x,r)
Data= np.multiply(Data, x_a)
x = Data
plt.title(r'Logistic map: $x_{n+1} = r x_{n} (1-x_{n}).$ n = '+ str(i) )
plt.ylabel('x-Random number')
plt.xlabel('r-Rate')
plt.scatter(r, Data, s=0.1, c='k')
plt.show()
plt.savefig(str(i) + " Logistic Map.png", dpi = 300)
plt.clf()

How to do the loop along a 3D vector with a known length by python

I have done a point filter programme in a 3D plane, but I need to do a loop along a known 3D normal vector with a known length. Many thanks for the help.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
point = sta[10] #starting points
normal = axe[10] #normal vector
d = -point.dot(normal)
# create x,y
xx, yy = np.meshgrid(np.linspace(-3.,-2.,101), np.linspace(-11.,-10.,101))
# calculate corresponding z
z = (-normal[0] * xx - normal[1] * yy - d) * 1. /normal[2]
f=[]
for i in xrange(len(xx)-1):
for j in xrange(len(xx)-1):
if (xx[i][j]-sta[10][0])**2 + (yy[i][j]-sta[10][1])**2 + (z[i][j]-sta[10][2])**2 > float(rad[0])**2:
xx[i][j]=NaN
yy[i][j]=NaN
z[i][j]=NaN
Since you're using meshgrid and xx, yy and z have the same shape, numpy's broadcasting policy will automatically do what you need. Try this:
invalid = (xx-sta[10,0])**2 + (yy-sta[10,1])**2 + (z-sta[10,2])**2 > float(rad[0])**2
xx[invalid]=np.NaN
yy[invalid]=np.NaN
z[invalid]=np.NaN
It creates a boolean mask invalid which contains True for all entries that satisfy the condition. You can then use this mask to set the corresponding values to NaN.
Note that you can use tuples to index numpy arrays. I.e. myArray[a][b] is equivalent to myArray[a, b].
Also note that I assumed you excluded the last entries by accident. If it was on purpose that you used xrange(len(xx)-1) rather than xrange(len(xx)), it is getting a bit uglier and you have to do it like this:
invalid = (xx[:-1,:-1]-sta[10,0])**2 + (yy[:-1,:-1]-sta[10,1])**2 + (z[:-1,:-1]-sta[10,2])**2 > float(rad[0])**2
xx[:-1,:-1][invalid]=np.NaN
yy[:-1,:-1][invalid]=np.NaN
z[:-1,:-1][invalid]=np.NaN

Categories

Resources