I'm new to Python am trying to plot a graph based on the pyODE tutorial found here. I'm using pylab for the plotting.
Below is the main part of the code and #added represents the code I've added in order to try and display the graph. When looking at the values themselves, y and v are the ones that change and x,z,u,w remain 0.000. When I run the program, the axis scale keeps scaling, implying that something is happening regarding the values, but no line is displayed. What am I doing wrong?
Thanks
yplot = 0 #added
#do the simulation
total_time = 0.0
dt = 0.04
while total_time<2.0:
x,y,z = body.getPosition()
u,v,w = body.getLinearVel()
print "%1.2fsec: pos=(%6.3f,%6.3f,%6.3f) vel=(%6.3f,%6.3f,%6.3f)" % \
(total_time, x,y,z,u,v,w)
world.step(dt)
total_time += dt
yplot += y #added
plot(total_time, yplot) #added
xlabel('Time') #added
ylabel('Height') #added
show() #added
The trick is to accumulate all the values you want to plot first, and then just call plot once.
yplot = 0 #added
#do the simulation
total_time = 0.0
dt = 0.04
times=[]
yvals=[]
while total_time<2.0:
x,y,z = body.getPosition()
u,v,w = body.getLinearVel()
print "%1.2fsec: pos=(%6.3f,%6.3f,%6.3f) vel=(%6.3f,%6.3f,%6.3f)" % \
(total_time, x,y,z,u,v,w)
world.step(dt)
total_time += dt
yplot += y
times.append(total_time)
yvals.append(yplot)
plot(times, yvals,'r-')
xlabel('Time') #added
ylabel('Height') #added
show() #added
The third argument to plot, 'r-', tells pylab to draw a red line connecting the points listed in times,yvals. When you plot points one-at-a-time, there is no way to tell pylab to connect the dots because each plot contains only a single point. Calling plot for each point is also highly inefficient.
Related
I'm trying to plot an orbit of a moon around Jupiter using gravitational acceleration.
I cannot seem to determine how to use the solve_ivp function appropriately. Something is just not clicking... I have created ODEs for a moon, related to Jupiter at the origin.
year = np.arange(0,31536000,3600)
G = 6.67408e-11
jupiter_xpos = 0
jupiter_ypos = 0
jupiter_vel = (0,0)
jupiter_mass = 1.89819e27
Io_orbit = 421700000
Io_xpos = -421700000
Io_ypos = 0
Io_xvel = 0
Io_yvel = -1773400
Io_mass = 8.9319e22
Io = [Io_xpos,Io_xvel,Io_ypos,Io_yvel]
def ode(Moon,t_max):
#Moon[0,1,2,3]=[x,v_x,y,v_y]
output=[0,0,0,0]
R = ((Moon[0]**2 + Moon[2]**2)**(3/2))
output[0]=Moon[1]
output[1]= -G*jupiter_mass*Moon[0]/R
output[2]=Moon[3]
output[3]= -G*jupiter_mass*Moon[2]/R
return output
#This is where the problem is
sol= solve_ivp(ode,Io,year)
plt.plot(sol[:,0],sol[:,2],0,0,'ro')
plt.axis('equal')
plt.grid(True)
plt.show()
I'm hoping to achieve a 2D orbital plot like this...
and also track and plot each change in x and y position and velocity against time.
The documentation for solve_ivp shows that the parameters are
sol = solve_ivp(ode, [t0,tf], u0, tspan=year, atol = 100, rtol=1e-9)
where year=np.arange(t0,tf,hour). Then you find the solution values in sol.t for the repeated times and sol.y for the values.
I wrote the code below, but when I run it, it shows me a linear plot instead of an exponential function curve.
I would appreciate your help if someone can tell me where I am wrong.
I expect an exponential curve when I do plotting instead of a linear graph.
import numpy as np
import matplotlib.pyplot as plt
######### Constants
El = -0.70 # resting membrane potential [V]
thresh = 3 # spiking threshold [V]
# VOLTAGE
T = 100 # total simulation length [s]
dt = 0.2 # step size [s]
time = np.arange(0, T+dt, dt) # time has 501 elements
V = np.zeros(len(time)) # array for saving Voltage history
V[0] = El
I = np.zeros(len(time))
I[100] = 1
counter=0
t_ref=5
tau=1.25
Weight=5
######### Simulation
def eps(s):
return (s/tau)*np.exp(1-(s/tau))
for t in range(len(time)):
spike_trains_window= I[:counter+1] #read I till counter says
temp=0
for i in range(len(spike_trains_window)):
if spike_trains_window[i]==1:
s= t-i
temp+=eps(s) #use an exponential function for computing temp
V[t]= Weight*temp
if V[t]> thresh:
V[t-1]=3.5
V[t] = El
I= np.delete(I, np.s_[0:counter+t_ref], axis=0) #removing previous firing times+ incoming spikes in refractory period
counter = 0
else:
counter+=1
######### Plotting
fig = plt.figure()
line = plt.plot(V)
plt.show()
While I do not completely understand what your code is supposed to do, I see the following issue:
You have only on value in in I which is non-zero, so this part will be TRUE only
once:
if spike_trains_window[i]==1:
s = t-i
temp+=eps(s)
This will assign a non-zero value to V[t] and V[t-1]. Because the value is bigger than tresh, we have V[t]=EL=-0.7 and V[t-1]=3.5, this is exactly what I get in the plot.
So I think your code is working, there is no error, but probably it is not doing what you want it to do because you don't make it do what you want it to do
I am working with signal data and am trying to find the instance (or close to it) before a peak starts to form. For example:
The red stars and orange x's are currently calculated using scipy.signal.find_peaks to find the first minimum peak before two peaks greater than 50 in a row. The ideal location I want is the area with the red stars and the second and third orange x.
My problem is that sometimes there is not a minimum value right before that first hump forms and that causes a problem like with the first orange x on the left.
What would be a better method or a way to improve my current method to get that spot right before the hump forms (rough arrow location):
My current code looks something like this, and it runs for the blue and green lines separately:
step_peak, _ = find_peaks(z, height=60, distance=40)
step_min, _ = find_peaks(-1*z, height=-60)
contact = []
for i in range(len(step_peak)-1):
if step_peak[i+1] - step_peak[i] < 100:
for min in reversed(step_min):
if min < step_peak[i]:
contact.append(min)
break
This method works for about 90% of the entire dataset, there are only a few that end up like the first orange x that I need to account for.
Any help would be greatly appreciated.
First, let's look at the function scipy.signal.peak_widths. Without access to your data, I used a sample curve:
from scipy.signal import chirp, find_peaks, peak_widths
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 6 * np.pi, 1000)
x = np.sin(x) + 0.6 * np.sin(2.6 * x)
peaks, _ = find_peaks(x)
results_full = peak_widths(x, peaks, rel_height=1)
results_full[0] # widths
plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.hlines(*results_full[1:], color="C3")
plt.show()
We can parse the results of peak_widths to discard those values that are inside of another widths.
peak_begin = np.array(results_full)
peak_begin = peak_begin[:, np.argsort( peak_begin[2] ) ]
_, b = peak_begin.shape
width_to_delete = []
i= 1
while i < b:
if peak_begin[2][i] < peak_begin[3][i-1]:
peak_begin = np.delete(peak_begin,i,1)
b = b-1
else:
i = i+1
plt.plot(x)
plt.hlines(*results_full[1:], color="r")
plt.plot(peaks, x[peaks], "x")
plt.plot(peak_begin[2], peak_begin[1], "o", color="g")
plt.show()
I hope that I got what you want to achieve.
I am using PyQtGraph for a speedy visualization of my data acquisition. For this I am redrawing the data constantly using a while loop. A simplified version of this code is given by:
import time
import numpy
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
x = numpy.linspace(-2 * numpy.pi, 2 * numpy.pi, 1000)
y = numpy.cos(x)
# Plot
win = pg.GraphicsWindow()
win.resize(800, 800)
p = win.addPlot()
p.plot(x, y, pen = "y")
i = 0
while i < 5000:
start_time = time.time()
noise = numpy.random.normal(0, 1, len(y))
y_new = y + noise
p.plot(x, y_new, pen = "y", clear = True)
p.enableAutoRange("xy", False)
pg.QtGui.QApplication.processEvents()
i += 1
end_time = time.time()
print("It has been {0} seconds since the loop started".format(end_time - start_time))
win.close()
When I time each iteration I find that I am not properly clearing the graph. The iteration time just keeps on increasing, and I am slowing down my data acquisition. For the example above, the iteration time in the beginning is about 0.009 s whereas at the end it is about 0.04 s. I therefore have a memory-leak.
I know that in matplotlib I should be calling be clf() to properly clear the plot. Unfortunately I am not that familiar with PyQtGraph and thought the clear = True would take care of this issue. I am confident it should be possible as PyQtGraph was designed for this type of usage.
How should I clear the graph each iteration to make sure I am not slowing down my data acquisition?
When you call plot on you plotItem, you create a new plotDataItem. All these plotDataItems doesn't seem to clear up properly. You can instead try to use only one plotDataItem and update the contents of it. Do this by using
plot = p.plot(x, y, pen = "y")
and then inside your loop
plot.setData(x, y_new)
I am wanting to plot two list in real time using matplotlib animation, with the help of the community I was able to plot my graph. I am now wanting to simplify my real time animation a bit as well as re-structure my graph.
Here are my objectives:
Plot x-axis: length of list "my_average"
Plot y-axis: elements in list "my_average"
y-axis limit -1 to 1 (all my elements in list "my_average" are between -1 and 1)
I do not know what I am doing wrong with my code thus far:
class StdOutListener(StreamListener):
def on_data(self, data):
json_load = json.loads(data)
texts = json_load['text'] # string
#print(texts)
#drop zero in list
if 0 in my_list: my_list.remove(0)
#print
#calculate average
average = numpy.mean(my_list)
b = my_average.append(average)
print "average =", my_average
def __init__(self):
self.start_time = time.time()
self.x = [len(my_average)]
self.y = [my_average]
self.my_average = []
self.line_actual, = plot(self.x, self.y) # line stores a Line2D we can update
self.line_average, = plot(self.x, self.my_average) # line stores a Line2D we can update
def on_data(self, new_value):
time_delta = time.time() - self.start_time # on our x axis we store time since start
self.x.append(time_delta)
self.y.append(new_value)
self.my_average.append(numpy.mean(self.y))
self.line_actual.set_data(self.x, self.y)
self.line_average.set_data(self.x, self.my_average)
ylim([min(self.y), max(self.y)]) # update axes to fit the data
xlim([0, max(self.x)])
draw() # redraw the plot
ion() # ion() allows matplotlib to update animations.
out_listener = StdOutListener()
for i in range(10000):
out_listener.on_data(i + numpy.random.randint(-5,5))
Thank you in Advance
So:
I'm not sure what you mean by plot length of the list. But I assume you want to create an index array with indices from 0 to len(my_average). That is what range is for:
self.x = range(len(my_average))
You already use the ylim function, which does exactly what you want. But instead of passing the min/max of your data you just have to pass your desired static values:
ylim(-1, 1)