I would like to know, if there is a way to redraw already created PolyCollection.
MWP
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.0, 2, 0.01)
y = np.sin(2*np.pi*x)
fig, (ax,ax2) = plt.subplots(1,1)
polycolelction = ax.fill_between(x, y)
for i in range(10):
y = 1.2*np.sin(i*np.pi*x)
# here should be data update, probably something like set_offset or set_verts?
polycolelction.set_verts([x,y])
fig.canvas.draw()
fig.canvas.flush_events()
It could be easier to create the polygon from scratch and then update its vertices. That way, we have precise control over the number of vertices and how the polygon is represented.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
x = np.arange(0.0, 2, 0.01)
y = np.sin(2 * np.pi * x)
fig, ax = plt.subplots()
points = np.array([x, y]).T
points = np.vstack([points, [points[-1, 0], 0], [points[0, 0], 0]])
polycollection = PatchCollection([Polygon(points, closed=True)])
pathcollection = ax.add_collection(polycollection)
ax.set_xlim(x[0], x[-1])
ax.set_ylim(-1.3, 1.3)
for i in range(10):
y = 1.2 * np.sin(i * np.pi * x)
points = np.array([x, y]).T
points = np.vstack([points, [points[-1, 0], 0], [points[0, 0], 0]])
pathcollection.get_paths()[0].vertices = points
fig.canvas.draw()
fig.canvas.flush_events()
Related
I would like to set the same scale for the X and Y axis on a 3D plot. Here is a sample plot:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
X = np.array([-3, 5, 6])
Y = np.array([14, -2, -31])
Z = np.array([0.1, 0, -0.1])
ax = plt.axes(projection='3d')
ax.plot(X, Y, Z)
plt.show()
The scale for the X and Y axis is such that they take up the same amount of space even though the true scale of the Y axis is larger than that of the X axis.
How do I make it so that they have an equal scale?
Edit: ax.set_xlim(Y.min(), Y.max()) worked.
In addition to answer above you can use set_box_aspect.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
X = np.array([-3, 5, 6])
Y = np.array([14, -2, -31])
Z = np.array([0.1, 0, -0.1])
ax = plt.axes(projection='3d')
ax.set_box_aspect([1,1,1]) #aspect ratio x,y,z
ax.plot(X, Y, Z)
plt.show()
How to rotate a function by the desired angle (for instance, 30 degrees)?
import matplotlib.pyplot as plt
import numpy as np
from numpy import exp, sin
def g(y):
return exp(-y)*sin(4*y)
y = np.linspace(0, 1.8, 501)
values = g(y)
fig, ax = plt.subplots(figsize=(5,5))
plt.plot(y, values)
plt.show()
Using the cosine and sine of the angle, you can create a rotation matrix. Multiplying each point (y, g(y)) with that matrix create a rotation around 0,0.
Here is some Python/numpy code to illustrate how everything could work together:
import matplotlib.pyplot as plt
import numpy as np
def g(y):
return np.exp(-y) * np.sin(4 * y)
y = np.linspace(0, 1.8, 501)
values = g(y)
theta = np.radians(30)
c, s = np.cos(theta), np.sin(theta)
rot_matrix = np.array(((c, s), (-s, c)))
xy = np.array([y, values]).T # rot_matrix
fig, ax = plt.subplots(figsize=(5, 5))
plt.plot(y, values)
plt.plot(xy[:, 0], xy[:, 1])
plt.axis('equal') # so angles on the screen look like the real angles
plt.show()
PS: To rotate around another point, first subtract the rotation center, do the rotation and then add it again:
center = np.array([0.9, 0])
xy = (np.array([y, values]).T - center) # rot_matrix + center
For example, I have 4 control point, and I know it should be a closed contour.
Firstly, I use the scipy.interpolate to interpolate the contour, and the code is:
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
t = np.arange(0, 1.25, 0.25)
x = np.sin(2*np.pi*t)
y = np.cos(2*np.pi*t)
tck,u = interpolate.splprep([x,y], s=0)
unew = np.arange(0, 1.01, 0.01)
out = interpolate.splev(unew, tck)
plt.figure()
plt.plot(x, y, 'x', out[0], out[1])
plt.axis([-1.05, 1.05, -1.05, 1.05])
plt.title('Spline of parametrically-defined curve')
plt.show()
And the result is:
In my thought, the four point should be interpolated into a circle. However, the result is kindly differ from a circle. Then, I find interpolate.CubicSpline may be a solution. The code is:
theta = 2 * np.pi * np.linspace(0, 1, 5)
y = np.c_[np.cos(theta), np.sin(theta)]
cs = interpolate.CubicSpline(theta, y, bc_type='periodic')
# cs = interpolate.CubicSpline(y[:, 0], y[:, 1], bc_type='periodic')
xs = 2 * np.pi * np.linspace(0, 1, 100)
ys = cs(xs)
fig, ax = plt.subplots(figsize=(6.5, 4))
ax.plot(np.cos(xs), np.sin(xs), 'r', label='true')
ax.plot(ys[:, 0], ys[:, 1], label='spline')
ax.axes.set_aspect('equal')
ax.legend(loc='center')
plt.show()
And the result is:
The result is actually what I need. However, in the really application, I don't know the theta, because the real control may be not a circle. In this way, if I only have the control point (n*2), how can we interpolate it into a close contour?
Any suggestion is appreciated!
I have an array of shape(512,512).
Looks like, (row=x, column=y, density=z=the number of the array)
[[0.012825 0.020408 0.022976 ... 0.015938 0.02165 0.024357]
[0.036332 0.031904 0.025462 ... 0.031095 0.019812 0.024523]
[0.015831 0.027392 0.031939 ... 0.016249 0.01697 0.028686]
...
[0.024545 0.011895 0.022235 ... 0.033226 0.03223 0.030235]]
I had already drawn it into a 2D density plot. My goal is to find the center of the circle and draw a vertical and horizontal cross-section in one figure.
Now, I have the trouble to find the center of the circle and combine two cross-sections in one figure.
Please help.
This is my code:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy.ndimage
data = pd.read_csv('D:/BFP.csv', header=None)
# create data
data = np.array(data)
print(data)
#plot data
side = np.linspace(-1.5,1.5,512)
x,y = np.meshgrid(side,side)
z = [[data[i][j] for i in range(len(data[0]))]for j in range(len(data))]
#-- Extract the line...
# Make a line with "num" points...
x0, y0 = 270, 0 # These are in _pixel_ coordinates!!
x1, y1 = 270, 500
num = 512
x_, y_ = np.linspace(x0, x1, num), np.linspace(y0, y1, num)
# Extract the values along the line, using cubic interpolation
zi = scipy.ndimage.map_coordinates(z, np.vstack((x_,y_)))
#-- Plot...
fig, axes = plt.subplots(nrows=2)
axes[0].imshow(z,origin='lower')
axes[0].plot([x0, x1], [y0, y1], 'ro-')
#axes[0].axis('image')
axes[1].plot(zi)
plt.savefig('D:/vertical.png')
plt.show()
image here:
I cannot help you with finding the center of the circle, but you can create a nice visualization of the cross section by creating 3 axes in a grid. Usually, I would use GridSpec for this, but imhsow has a tendency to mess up the relative size of the axes to maintain square pixels. Thankfully, the AxesGrid toolkit can help.
The base of the code is inspired by this matplotlib example.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy.stats import multivariate_normal
import scipy
fig, main_ax = plt.subplots(figsize=(5, 5))
divider = make_axes_locatable(main_ax)
top_ax = divider.append_axes("top", 1.05, pad=0.1, sharex=main_ax)
right_ax = divider.append_axes("right", 1.05, pad=0.1, sharey=main_ax)
# make some labels invisible
top_ax.xaxis.set_tick_params(labelbottom=False)
right_ax.yaxis.set_tick_params(labelleft=False)
main_ax.set_xlabel('dim 1')
main_ax.set_ylabel('dim 2')
top_ax.set_ylabel('Z profile')
right_ax.set_xlabel('Z profile')
x, y = np.mgrid[-1:1:.01, -1:1:.01]
pos = np.empty(x.shape + (2,))
pos[:, :, 0] = x; pos[:, :, 1] = y
rv = multivariate_normal([-0.2, 0.2], [[1, 1.5], [0.25, 0.25]])
z = rv.pdf(pos)
z_max = z.max()
cur_x = 110
cur_y = 40
main_ax.imshow(z, origin='lower')
main_ax.autoscale(enable=False)
right_ax.autoscale(enable=False)
top_ax.autoscale(enable=False)
right_ax.set_xlim(right=z_max)
top_ax.set_ylim(top=z_max)
v_line = main_ax.axvline(cur_x, color='r')
h_line = main_ax.axhline(cur_y, color='g')
v_prof, = right_ax.plot(z[:,int(cur_x)],np.arange(x.shape[1]), 'r-')
h_prof, = top_ax.plot(np.arange(x.shape[0]),z[int(cur_y),:], 'g-')
plt.show()
Just for fun, you can even make it interactive
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from scipy.stats import multivariate_normal
import scipy
fig, main_ax = plt.subplots(figsize=(5, 5))
divider = make_axes_locatable(main_ax)
top_ax = divider.append_axes("top", 1.05, pad=0.1, sharex=main_ax)
right_ax = divider.append_axes("right", 1.05, pad=0.1, sharey=main_ax)
# make some labels invisible
top_ax.xaxis.set_tick_params(labelbottom=False)
right_ax.yaxis.set_tick_params(labelleft=False)
main_ax.set_xlabel('dim 1')
main_ax.set_ylabel('dim 2')
top_ax.set_ylabel('Z profile')
right_ax.set_xlabel('Z profile')
x, y = np.mgrid[-1:1:.01, -1:1:.01]
pos = np.empty(x.shape + (2,))
pos[:, :, 0] = x; pos[:, :, 1] = y
rv = multivariate_normal([-0.2, 0.2], [[1, 1.5], [0.25, 0.25]])
z = rv.pdf(pos)
z_max = z.max()
main_ax.imshow(z, origin='lower')
main_ax.autoscale(enable=False)
right_ax.autoscale(enable=False)
top_ax.autoscale(enable=False)
right_ax.set_xlim(right=z_max)
top_ax.set_ylim(top=z_max)
v_line = main_ax.axvline(np.nan, color='r')
h_line = main_ax.axhline(np.nan, color='g')
v_prof, = right_ax.plot(np.zeros(x.shape[1]),np.arange(x.shape[1]), 'r-')
h_prof, = top_ax.plot(np.arange(x.shape[0]),np.zeros(x.shape[0]), 'g-')
def on_move(event):
if event.inaxes is main_ax:
cur_x = event.xdata
cur_y = event.ydata
v_line.set_xdata([cur_x,cur_x])
h_line.set_ydata([cur_y,cur_y])
v_prof.set_xdata(z[:,int(cur_x)])
h_prof.set_ydata(z[int(cur_y),:])
fig.canvas.draw_idle()
fig.canvas.mpl_connect('motion_notify_event', on_move)
plt.show()
NB: the lag is just due to the convertion in gif, the update is much smoother on my machine
I want to randomly generate n points on this plot.
I have used the .scatter method, but the points don't seem to be random. is there a way I could simply pass a number and it to generate that number of points?
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
def f(t):
s1 = np.cos(2*np.pi*t)
e1 = np.exp(-t)
return np.multiply(s1,e1)
t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.02)
t3 = np.arange(0.0, 2.0, 0.01)
fig = plt.figure(figsize=plt.figaspect(2.))
ax = fig.add_subplot(2, 1, 2, projection='3d')
X = np.arange(-20, 20, 0.25)
xlen = len(X)
Y = np.arange(-20, 20, 0.25)
ylen = len(Y)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color='yellow',
linewidth=0, antialiased=False)
scatteredpoints = ax.scatter(X[1::20, 1::20],Y[1::20, 1::20],Z[1::20, 1::20],linewidth=0, antialiased=False)
ax.set_zlim3d(-1, 1)
plt.show()
You need to feed random data to plt.scatter.
def scatterRandomPoints(n):
plt.scatter(*np.random.randint(100, size = (2, n)))