I am writing a programme which takes a circular membrane and models its evolution under certain forces. The programme is as follows (with the details of the evolution omitted)
import numpy as np
import math
from matplotlib import pyplot as plt
xCoords = {"%s" % i: np.array([math.cos(2*math.pi*i/360),0,0,0,0,0,0,0,0,0], dtype=float)
for i in range(0, 360)} #coordinates stored in arrays whose entries correspond to time evolution
yCoords = {"%s" % i: np.array([math.sin(2*math.pi*i/360),0,0,0,0,0,0,0,0,0], dtype=float)
for i in range(0, 360)}
#fill out arrays using diff eq.
x = np.zeros((360,10), dtype = float)
y = np.zeros((360,10), dtype = float)
for i in range(0,360):
for j in range(0,10):
x[i][j] = xCoords["%s" % i][j]
y[i][j] = yCoords["%s" % i][j]
If I want to now plot the evolution of the coordinates over time, how would I do that?
I tried to plot with the following.
plt.plot(x,y)
plt.show
but it just outputs
In particular, how do I get a plot of just (x[i][j],y[i][j]) at time j?
I then tried
for j in range(0,62):
for i in range(0,360):
plt.plot(x[i][j],y[i][j])
plt.show()
but that didn't work either as it didn't give a new 'circle' everytime.
I think you are looking for something like this:
fig = plt.figure()
ax = fig.gca()
h, = ax.plot([],[])
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
for time_ind in range(0,10):
h.set_data(x[:, time_ind], y[:, time_ind])
plt.draw()
plt.pause(0.5)
Related
I tried to make graph with matplotlib, and my graph should start from 1 not 0, But I don't know how to do. I can do this by writing all figures in x_coords and y_coords, but I want to know the code I can use while I use f = open(). Sorry that I'm not fluent in English
import matplotlib.pyplot as plt
import numpy as np
avg_prices = []
labels = (i for i in range(1, 53))
f = open('C:/1994_Weekly_Gas_Averages.txt', 'r')
for line in f:
avg_prices.append(float(line))
plt.plot(avg_prices, 'o--', label=labels)
plt.title('1994 Weekly Gas Prices')
plt.xlabel('Weeks')
plt.ylabel('Average prices')
plt.grid()
plt.xticks(np.arange(0, 60, 10))
plt.yticks(np.arange(1, 1.17, 0.025))
plt.show()
Just include the corresponding x coordinate in before the y coordinate.
x = list(range(1,53))
plt.plot(x, avg_prices)
labels = (i for i in range(0, 53)) should work. range function will start from the first parameter and run al the way till the n-1 of the second parameter.
labels = (i for i in range(0, 53)) will give labels from 0.....52
labels = (i for i in range(1, 53)) will give labels from 1.....52
labels = (i for i in range(1, 54)) will give labels from 1.....53
labels = (i for i in range(0, 54)) will give labels from 0.....53
I'm trying to build a simulator for some BOID objects, but I'm having some trouble with matplotlib's animation module (not helped by the very obtuse documentation).
Here's the code:
from mpl_toolkits.mplot3d import Axes3D #Import axes
import matplotlib.pyplot as plt #Import plotting library
from matplotlib import animation
import numpy as np #Import numpy library
dim = 2 #Defines the dimensionality of the system
n = 6 #Number of BOIDS
tmax = 5 #Length of sim
o = np.zeros(dim) #Origin as vector
r = np.random.rand(n,dim) #Places BOIDs randomly with co-ordinates (x,y,z) from 0 to 1. Has dimensions n and dim
v = 2*np.random.rand(n,dim)-1#Sets initial velocity of each BOID from -1 to 1 in each cardinal direction
rt = np.zeros((tmax,n,dim)) #This array contains the whole system's positions at each point in time
x = np.empty(n)
y = np.empty(n)
"""rt[a]is r at t=a
rt[a][b] is r array for t=a and n=b
rt[0][a][b] is the x co-ordinate of boid n=b at t=a"""
fig = plt.figure() #Setting up a plotting figure for animation
ax = fig.add_subplot(111) #Establishes a subplot with axes
ax.grid(True,linestyle='-',color='0.75') #Sets up a grid on subplot
ax.set_xlim(-50,50)
ax.set_ylim(-50,50) #Set limits for x and y axes
for t in range (0,tmax):
for i in range (0,n):
r[i] = r[i] + v[i]
rt[t][i] = r[i]
def init():
for i in range (0,n):
x[i] = rt[0][0][i]
y[i] = rt[1][0][i]
print(i)
return x,y,
def update(j):
for i in range (0,n):
x[i] = rt[0][j][i]
y[i] = rt[1][j][i]
return x,y
anim = animation.FuncAnimation(fig, update, frames=tmax, init_func=init, interval=20, blit=True)
My problem is two-fold; Currently the code gives me this error:
x[i] = rt[0][0][i]
IndexError: index 2 is out of bounds for axis 0 with size 2
suggesting that I've mismatched the dimensions of the two array elements, but they should both just be a single number and not an array so I don't understand what's wrong.
Also, I don't really understand the need for the functions init and update. Can I not simply animate slices of rt instead?
Thanks in advance.
I am doing a Kernel Density Estimation in Python and getting the contours and paths as shown below. (here is my sample data: https://pastebin.com/193PUhQf).
from numpy import *
from math import *
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x_2d = []
y_2d = []
data = {}
data['nodes'] = []
# here is the sample data:
# https://pastebin.com/193PUhQf
X = [.....]
for Picker in xrange(0, len(X)):
x_2d.append(X[Picker][0])
y_2d.append(X[Picker][1])
# convert to arrays
m1 = np.array([x_2d])
m2 = np.array([y_2d])
x_min = m1.min() - 30
x_max = m1.max() + 30
y_min = m2.min() - 30
y_max = m2.max() + 30
x, y = np.mgrid[x_min:x_max:200j, y_min:y_max:200j]
positions = np.vstack([x.ravel(), y.ravel()])
values = np.vstack([m1, m2])
kde = stats.gaussian_kde(values)
z = np.reshape(kde(positions).T, x.shape)
fig = plt.figure(2, dpi=200)
ax = fig.add_subplot(111)
pc = ax.pcolor(x, y, z)
cb = plt.colorbar(pc)
cb.ax.set_ylabel('Probability density')
c_s = plt.contour(x, y, z, 20, linewidths=1, colors='k')
ax.plot(m1, m2, 'o', mfc='w', mec='k')
ax.set_title("My Title", fontsize='medium')
plt.savefig("kde.png", dpi=200)
plt.show()
There is a similar way to get the contours using R, which is described here:
http://bl.ocks.org/diegovalle/5166482
Question: how can I achieve the same output using my python script or as a start point?
the desired output should be like contours_tj.json which can be used by leaflet.js lib.
UPDATE:
My input data structure is composed of three columns, comma separated:
first one is the X value
second one is the Y value
third one is the ID of my data, it has no numerical value, it is simply an identifier of the data point.
Update 2:
Question, if simply put, is that I want the same output as in the above link using my input file which is in numpy array format.
update 3:
my input data structure is of list type:
print type(X)
<type 'list'>
and here are the first few lines:
print X[0:5]
[[10.800584, 11.446064, 4478597], [10.576840,11.020229, 4644503], [11.434276,10.790881, 5570870], [11.156718,11.034633, 6500333], [11.054956,11.100243, 6513301]]
geojsoncontour is a python library to convert matplotlib contours to geojson
geojsoncontour.contour_to_geojson requires a contour_levels argument. The levels in pyplot.contour are chosen automatically, but you can access them with c_s._levels
So, for your example you could do:
import geojsoncontour
# your code here
c_s = plt.contour(x, y, z, 20, linewidths=1, colors='k')
# Convert matplotlib contour to geojson
geojsoncontour.contour_to_geojson(
contour=c_s,
geojson_filepath='out.geojson',
contour_levels=c_s._levels,
ndigits=3,
unit='m'
)
I'm using the example dendrogram from this post in my work but would also like to keep track of which row / column is from which piece of data.
I've edited the code with records of names of the data as names as follows and would like to print out the names at the bottom and to the right of the distance matrix visualization. I've tried adding labels = names in the call to dendrogram but this didn't help.
Does anyone know how to add labels to this?
import scipy
import pylab
import scipy.cluster.hierarchy as sch
# Generate random features and distance matrix.
x = scipy.rand(40)
D = scipy.zeros([40,40])
for i in range(40):
for j in range(40):
D[i,j] = abs(x[i] - x[j])
### new code
names = [ ]
for i in range(40):
names.append( 'str%i'%( i ) )
print names[-1]
### end new code
# Compute and plot first dendrogram.
fig = pylab.figure(figsize=(8,8))
ax1 = fig.add_axes([0.09,0.1,0.2,0.6])
Y = sch.linkage(D, method='centroid')
Z1 = sch.dendrogram(Y, orientation='right')
ax1.set_xticks([])
ax1.set_yticks([])
# Compute and plot second dendrogram.
ax2 = fig.add_axes([0.3,0.71,0.6,0.2])
Y = sch.linkage(D, method='single')
Z2 = sch.dendrogram(Y)
ax2.set_xticks([])
ax2.set_yticks([])
# Plot distance matrix.
axmatrix = fig.add_axes([0.3,0.1,0.6,0.6])
idx1 = Z1['leaves']
idx2 = Z2['leaves']
D = D[idx1,:]
D = D[:,idx2]
im = axmatrix.matshow(D, aspect='auto', origin='lower', cmap=pylab.cm.YlGnBu)
axmatrix.set_xticks([])
axmatrix.set_yticks([])
# Plot colorbar.
#axcolor = fig.add_axes([0.91,0.1,0.02,0.6])
#pylab.colorbar(im, cax=axcolor)
fig.show()
fig.savefig('dendrogram.png')
The python package heatmapcluster (available on PyPI) that I wrote accepts (in fact, requires) labels.
Here's a simplified version of your script using heatmapcluster:
import numpy as np
import matplotlib.pyplot as plt
from heatmapcluster import heatmapcluster
# Generate random features and distance matrix.
x = np.random.rand(40)
D = np.abs(np.subtract.outer(x, x))
names = ['str%i' % i for i in range(len(x))]
h = heatmapcluster(D, names, names,
num_row_clusters=3, num_col_clusters=3,
label_fontsize=8,
xlabel_rotation=-75,
cmap=plt.cm.coolwarm,
show_colorbar=True,
top_dendrogram=True)
plt.show()
And here is the plot it generates:
(Note that, for a symmetric array like D, there is really no point in clustering both axes. By symmetry, they will generate the same dendrogram.)
I'm plotting multiple lines on the same graph using matplotlib in Python by using a for-loop to add each line to the axis.
When plotted in 2D with each line on top of the other this works fine.
When plotting in 3D however, python displays the same graphed data each time I run through the for-loop, even though the data is significantly different.
Edit: I don't believe that this question is a duplicate of "How can I tell if NumPy creates a view or a copy?" as it highlights one particular instance of unexpected behaviour.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
###### Unimportant maths not relevant to the question ######
def rossler(x_n, y_n, z_n, h, a, b, c):
#defining the rossler function
x_n1=x_n+h*(-y_n-z_n)
y_n1=y_n+h*(x_n+a*y_n)
z_n1=z_n+h*(b+z_n*(x_n-c))
return x_n1,y_n1,z_n1
#defining a, b, and c
a = 1.0/5.0
b = 1.0/5.0
c = 5
#defining time limits and steps
t_0 = 0
t_f = 50*np.pi
h = 0.01
steps = int((t_f-t_0)/h)
#create plotting values
t = np.linspace(t_0,t_f,steps)
x = np.zeros(steps)
y = np.zeros(steps)
z = np.zeros(steps)
##### Relevant to the question again #####
init_condition_array = [[0,0,0],[0.1,0,0],[0.2,0,0],[0.3,0,0]]
color_array = ["red","orange","green","blue"]
color_counter = 0
zs_array = [0, 0.1, 0.2, 0.3]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for row in init_condition_array:
x[0] = row[0]
y[0] = row[1]
z[0] = row[2]
for i in range(x.size-1):
#re-evaluate the values of the x-arrays depending on the initial conditions
[x[i+1],y[i+1],z[i+1]]=rossler(x[i],y[i],z[i],t[i+1]-t[i],a,b,c)
plt.plot(t,x,zs=zs_array[color_counter],zdir="z",color=color_array[color_counter])
color_counter += 1
ax.set_xlabel('t')
ax.set_ylabel('x(t)')
plt.show()
As you can see, the graphs should look incredibly different;
this is a 2D image of the graphs on the same axis with a few alterations to the code (shown below):
Whilst this is the graph produced by the 3D plot:
.
The 2D plot was created by making these small alterations to the code; nothing above the first line was changed:
init_condition_array = [[0,0,0],[0.1,0,0],[0.2,0,0],[0.3,0,0]]
color_array = ["red","orange","green","blue"]
color_counter = 0
fig = plt.figure()
ax = fig.add_subplot(111)
for row in init_condition_array:
x[0] = row[0]
y[0] = row[1]
z[0] = row[2]
for i in range(x.size-1):
#re-evaluate the values of the x-arrays depending on the initial conditions
[x[i+1],y[i+1],z[i+1]]=rossler(x[i],y[i],z[i],t[i+1]-t[i],a,b,c)
plt.plot(t,x,color=color_array[color_counter],lw=1)
color_counter += 1
ax.set_xlabel('t')
ax.set_ylabel('x(t)')
plt.show()
Moving x = np.zeros(steps) inside the for row in init_condition_array loop fixes/avoids the problem. x is stored inside the Line3D objects returned by plt.plot, and mutating x affects the values stored in the other Line3Ds.
If you trace through the source code for Line3D you'll find
that the data that you pass to plt.plot ends up in a Line3D's _verts3d
attribute. The data is not copied; the _verts3d tuple holds references to the
exact same arrays.
And this _verts3d attribute is directly accessed later when rendering:
def draw(self, renderer):
xs3d, ys3d, zs3d = self._verts3d
Thus mutating the data -- even after calling plt.plot -- mutates self._verts3d.
This simple example demonstrates the problem:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
t = np.linspace(0, 1, 5)
x = np.sin(t)
line, = plt.plot(t, x, 0)
Here we have the original values of x:
print(line._verts3d[1])
# [ 0. 0.24740396 0.47942554 0.68163876 0.84147098]
And this shows that mutating x modifies line._verts3d:
x[:] = 1
print(line._verts3d[1])
# [ 1. 1. 1. 1. 1.]
# The result is a straight line, not a sine wave.
plt.show()
This surprising pitfall does not happen when making 2D line plots because there the Line2D._xy attribute which holds the data used for rendering stores a copy of the original data.
This problem could be fixed in the source code by changing this line in art3d.Line3D.set_3d_properties from
self._verts3d = art3d.juggle_axes(xs, ys, zs, zdir)
to
import copy
self._verts3d = copy.deepcopy(art3d.juggle_axes(xs, ys, zs, zdir))