How to plot using arays in an array? - python-3.x

I have this coupled mass system code that runs good and prints results. But I have trouble plotting the graphs for positions and velocities since I am unable to extract values from arrays. I would appreciate some help!
import numpy as np
%matplotlib inline
import matplotlib.pyplot as pl
from scipy.integrate import odeint
def vectorfield(w, t, p):
x1, y1, x2, y2 = w
m1, m2, k1, k2, kc = p
# Create f = (x1',y1',x2',y2'):
f = [y1, (-x1*(k1+kc) + x2*kc)/m1, y2, (x1*kc - x2*(k2+kc)) / m2]
return f
# Parameter values
# Masses:
m1 = 1.0
m2 = 1.0
# Spring constants
k1 = 4.0
k2 = 1.0
kc = 0.1
# Initial conditions
# x1 and x2 are the initial displacements; y1 and y2 are the initial velocities
x1 = -2.0
y1 = 5.0
x2 = 2.0
y2 = 10.0
# ODE solver parameters
abserr = 1.0e-8
relerr = 1.0e-6
stoptime = 100.0
numpoints = 250
t = [stoptime * float(i) / (numpoints - 1) for i in range(numpoints)]
# Pack up the parameters and initial conditions:
p = [m1, m2, k1, k2, kc]
w0 = [x1, y1, x2, y2]
# Call the ODE solver.
wsol = odeint(vectorfield, w0, t, args=(p,), atol=abserr, rtol=relerr)
# Print solution
for t1, w1 in zip(t, wsol):
AZ = [t1, w1[0], w1[1], w1[2], w1[3]]
print(AZ)
I have tried searching the web but wasnt unable to find a fitting solution to plot this. I tried
with open('coupled_masses.dat', 'w') as f:
for t1, w1 in zip(t, wsol):
print(f, t1, w1[0], w1[1], w1[2], w1[3])
import matplotlib.pyplot as plt;
from matplotlib.font_manager import FontProperties;
# get saved values from saved file
t, x1, y1, x2, y2 = np.loadtxt('coupled_masses.dat', unpack=True);
but it doesnt work

Is this what you want? Using list comprehension here and then convert to numpy array.
from scipy.integrate import odeint
def vectorfield(w, t, p):
x1, y1, x2, y2 = w
m1, m2, k1, k2, kc = p
# Create f = (x1',y1',x2',y2'):
f = [y1, (-x1*(k1+kc) + x2*kc)/m1, y2, (x1*kc - x2*(k2+kc)) / m2]
return f
# Parameter values
# Masses:
m1 = 1.0
m2 = 1.0
# Spring constants
k1 = 4.0
k2 = 1.0
kc = 0.1
# Initial conditions
# x1 and x2 are the initial displacements; y1 and y2 are the initial velocities
x1 = -2.0
y1 = 5.0
x2 = 2.0
y2 = 10.0
# ODE solver parameters
abserr = 1.0e-8
relerr = 1.0e-6
stoptime = 100.0
numpoints = 250
t = [stoptime * float(i) / (numpoints - 1) for i in range(numpoints)]
# Pack up the parameters and initial conditions:
p = [m1, m2, k1, k2, kc]
w0 = [x1, y1, x2, y2]
# Call the ODE solver.
wsol = odeint(vectorfield, w0, t, args=(p,), atol=abserr, rtol=relerr)
# Print solution
data = np.array([[t1, w1[0], w1[1], w1[2], w1[3]] for t1, w1 in zip(t, wsol)])
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7.2, 7.2/2))
ax1.plot(data[:, 0], data[:, 1])
ax2.plot(data[:, 0], data[:, 3])

Related

How to fill between two lines with different x and y?

How to fill between two lines with different x and y? Now, the filling is for two y functions with the common x-axis, which is not true. When I tried x1, x2, y1, y2 I have got a worse result than displayed below.
import matplotlib.pyplot as plt
import numpy as np
from numpy import exp, sin
def g(y):
amp = 0.6
return amp*exp(-2.5*y)*sin(9.8*y)
def g_e(y):
amp = 0.66
return amp*exp(-2.5*y_e)*sin(8.1*y_e)
y = np.linspace(0, 0.83, 501)
y_e = np.linspace(0, 1.08, 501)
values = g(y)
values_e = g_e(y)
theta = np.radians(-65.9)
c, s = np.cos(theta), np.sin(theta)
rot_matrix = np.array(((c, s), (-s, c)))
xy = np.array([y, values]).T # rot_matrix
theta_e = np.radians(-60)
c_e, s_e = np.cos(theta_e), np.sin(theta_e)
rot_matrix_e = np.array(((c_e, s_e), (-s_e, c_e)))
xy_e = np.array([y, values_e]).T # rot_matrix_e
fig, ax = plt.subplots(figsize=(5,5))
ax.axis('equal')
x_shift = 0.59
y_shift = 0.813
x_shift_e = 0.54
y_shift_e = 0.83
ax.plot(xy[:, 0]+x_shift, xy[:, 1]+y_shift, c='red')
ax.plot(xy_e[:, 0]+x_shift_e, xy_e[:, 1]+y_shift_e, c='black')
ax.fill_between(xy[:, 0]+x_shift, xy[:, 1]+y_shift, xy_e[:, 1]+y_shift_e)
plt.show()
Script for additional question:
for i in range(len(x)-1):
for j in range(i-1):
xs_ys = intersection(x[i],x[i+1],x[j],x[j+1],y[i],y[i+1],y[j],y[j+1])
if xs_ys in not None:
xs.append(xs_ys[0])
ys.append(xs_ys[1])
I got an error:
if xs_ys in not None:
^
SyntaxError: invalid syntax
Here is an approach creating a "polygon" by concatenating the reverse of one curve to the other curve. ax.fill() can be used to fill the polygon. Note that fill_between() can look strange when the x-values aren't nicely ordered (as is the case here after the rotation). Also, the mirror function fill_betweenx() wouldn't be adequate in this case.
import matplotlib.pyplot as plt
import numpy as np
def g(y):
amp = 0.6
return amp * np.exp(-2.5 * y) * np.sin(9.8 * y)
def g_e(y):
amp = 0.66
return amp * np.exp(-2.5 * y_e) * np.sin(8.1 * y_e)
y = np.linspace(0, 0.83, 501)
y_e = np.linspace(0, 1.08, 501)
values = g(y)
values_e = g_e(y)
theta = np.radians(-65.9)
c, s = np.cos(theta), np.sin(theta)
rot_matrix = np.array(((c, s), (-s, c)))
xy = np.array([y, values]).T # rot_matrix
theta_e = np.radians(-60)
c_e, s_e = np.cos(theta_e), np.sin(theta_e)
rot_matrix_e = np.array(((c_e, s_e), (-s_e, c_e)))
xy_e = np.array([y, values_e]).T # rot_matrix_e
fig, ax = plt.subplots(figsize=(5, 5))
ax.axis('equal')
x_shift = 0.59
y_shift = 0.813
x_shift_e = 0.54
y_shift_e = 0.83
xf = np.concatenate([xy[:, 0] + x_shift, xy_e[::-1, 0] + x_shift_e])
yf = np.concatenate([xy[:, 1] + y_shift, xy_e[::-1, 1] + y_shift_e])
ax.plot(xy[:, 0] + x_shift, xy[:, 1] + y_shift, c='red')
ax.plot(xy_e[:, 0] + x_shift_e, xy_e[:, 1] + y_shift_e, c='black')
ax.fill(xf, yf, color='dodgerblue', alpha=0.3)
plt.show()

Using colormap in cycle (python)

How to edit the for cycles under #ax5 and #ax6 to plot graphs in the same fashion? Now, the lower figure has no colour transit, as opposed to the upper one. The colour transit appears in the lower figure after increasing of dpi, however, some unwanted stuff also appears. Is there a scalling problem? Thank you
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
import math
fig, ax = plt.subplots()
plt.rcParams["figure.figsize"] = [8, 8]
# Function for plotting parallels to curves
def get_parallels(length=.1):
px, py = [], []
for idx in range(len(x)-1):
x0, y0, xa, ya = x[idx], y[idx], x[idx+1], y[idx+1]
dx, dy = xa-x0, ya-y0
norm = math.hypot(dx, dy) * 1/length
dx /= norm
dy /= norm
px.append(x0-dy)
py.append(y0+dx)
return px, py
def offset(x,y, o):
""" Offset coordinates given by array x,y by o """
X = np.c_[x,y].T
m = np.array([[0,-1],[1,0]])
R = np.zeros_like(X)
S = X[:,2:]-X[:,:-2]
R[:,1:-1] = np.dot(m, S)
R[:,0] = np.dot(m, X[:,1]-X[:,0])
R[:,-1] = np.dot(m, X[:,-1]-X[:,-2])
On = R/np.sqrt(R[0,:]**2+R[1,:]**2)*o
Out = On+X
return Out[0,:], Out[1,:]
dpi = 20
def offset_curve(ax, x,y, o):
""" Offset array x,y in data coordinates
by o in points """
trans = ax.transData.transform
inv = ax.transData.inverted().transform
X = np.c_[x,y]
Xt = trans(X)
xto, yto = offset(Xt[:,0],Xt[:,1],o*dpi/72. )
Xto = np.c_[xto, yto]
Xo = inv(Xto)
return Xo[:,0], Xo[:,1]
fig = plt.figure(constrained_layout=True)
gs = GridSpec(3, 6, figure=fig)
ax5 = fig.add_subplot(gs[1, 3:6])
ax6 = fig.add_subplot(gs[2, :3])
ax7 = fig.add_subplot(gs[2, 3:6])
cmap = plt.get_cmap('Greys_r')
# ax5
x = np.linspace(-1, 1, 100)
y = -x**2
ax5.set_ylim(-1.02, 0.3)
width_l = ax5.get_ylim()[1] - ax5.get_ylim()[0]
for t in np.linspace(0, 1, 40):
length = -0.1*width_l*t
ax5.plot(*get_parallels(length=length), color=cmap(t/2 + 0.25))
# ax6
x = np.linspace(-3, 3, 100)
y = -(1/4*x**4 - 1.6*x**2)
ax6.plot(x, y)
ax6.set_xlim(ax6.get_xlim()[0]-0.5, ax6.get_xlim()[1]+0.5)
ax6.scatter(1/2*(ax6.get_xlim()[0] + ax6.get_xlim()[1]), 1.2, marker = 'o', s=900, facecolors='none')
lines = []
width_l = ax6.get_ylim()[1] - ax6.get_ylim()[0]
for t in np.linspace(0, 1, 40):
l, = ax6.plot(x, y - t * 0.1 * width_l, color=cmap(t/2 + 0.25))
lines.append(l)
def plot_rainbow(event=None):
x0 = x
y0 = y
for i in range(len(lines)):
xx, yy = offset_curve(ax, x0, y0, -width_l)
lines[i].set_data(xx, yy)
lines[i].set_linewidth(1.1*width_l)
x0 = xx
y0 = yy
plot_rainbow()
fig.canvas.mpl_connect("resize_event", plot_rainbow)
fig.canvas.mpl_connect("button_release_event", plot_rainbow)
plt.savefig('fig.pdf')

How to draw a semicircle using matplotlib

I want to draw a semicircle using matplotlib.
Here I have a court
import numpy as np
import matplotlib.pyplot as plt
x_asix = np.array([0,0,100,100, 0])
y_asix = np.array([0,100,100,0, 0])
x_coordenates = np.concatenate([ x_asix])
y_coordenates = np.concatenate([y_asix])
plt.plot(x_coordenates, y_coordenates)
See image here:
I want to add one semicircle that stars at point (0,50) with radius = 10.
The result should be something like this:
Here is a function that draws semicircles, using numpy:
import matplotlib.pyplot as plt
import numpy as np
def generate_semicircle(center_x, center_y, radius, stepsize=0.1):
"""
generates coordinates for a semicircle, centered at center_x, center_y
"""
x = np.arange(center_x, center_x+radius+stepsize, stepsize)
y = np.sqrt(radius**2 - x**2)
# since each x value has two corresponding y-values, duplicate x-axis.
# [::-1] is required to have the correct order of elements for plt.plot.
x = np.concatenate([x,x[::-1]])
# concatenate y and flipped y.
y = np.concatenate([y,-y[::-1]])
return x, y + center_y
example:
x,y = generate_semicircle(0,50,10, 0.1)
plt.plot(x, y)
plt.show()
You could simply use the equation of the ellipse, to easily draw the portion of the ellipse you are interested in.
If you want to draw the part of the ellipse you have in your image, unfortunately you cannot simply write it as: y = f(x), but you can use the common trick of plotting x = f(y) instead:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1)
ax.set_aspect('equal')
x_asix = np.array([0,0,100,100, 0])
y_asix = np.array([0,100,100,0, 0])
x_coordenates = np.concatenate([ x_asix])
y_coordenates = np.concatenate([y_asix])
ax.plot(x_coordenates, y_coordenates)
# ((x - x0) / a) ** 2 + ((y - y0) / b) ** 2 == 1
a = 20
b = 15
x0 = 50
y0 = 0
x = np.linspace(-a + x0, a + x0)
y = b * np.sqrt(1 - ((x - x0) / a) ** 2) + y0
ax.plot(y, x)

Unable to get the simplified coordinates using sympy - python

I have x2, x3, y2, y3, d1, d2, d3 values which is,
x2 = 0
x3 = 100
y2 = 0
y3 = 0
d1 = 100
d2 = 100
d3 = 87
When I use the below script,
from sympy import symbols, Eq, solve
x, y = symbols('x y')
eq1 = Eq((x - x2) ** 2 + (y - y2) ** 2 - d2 ** 2)
eq2 = Eq((x - x3) ** 2 + (y - y3) ** 2 - d3 ** 2)
sol_dict = solve((eq1, eq2), (x, y))
I got the ans as,
sol_dict = [(12431/200, -87*sqrt(32431)/200), (12431/200, 87*sqrt(32431)/200)]
How can I achieve the simplified solution like
sol_dict = [(62.155, -78.33), (62.155, 78.33)]
in python?
You can numerically evaluate the solution to get floats:
In [40]: [[x.evalf(3) for x in s] for s in sol_dict]
Out[40]: [[62.2, -78.3], [62.2, 78.3]]
I would only recommend doing that for display though. If you want to use the values in sol_dict for further calculations it's best to keep them as exact rational numbers.

facecolor for 3d plot doesn't work

I am new to Python and trying to do a 3d plot and color it with a 4th variable. I use facecolors for this, and for one example below, it doesn't work properly. I have positive value but facecolor only displays negatives. Much appreciate if anybody looks into this.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
from scipy import ndimage
import scipy.ndimage.filters
def RP_source(theta,phi,MT):
x1 = np.sin(theta)*np.cos(phi)
x2 = np.sin(theta)*np.sin(phi)
x3 = np.cos(theta)
#
M11 = MT[0,0]
M22 = MT[1,1]
M33 = MT[2,2]
M12 = MT[0,1]
M23 = MT[1,2]
M13 = MT[0,2]
core = M11*x1*x1 + M22*x2*x2 + M33*x3*x3 + 2*M12*x1*x2 + 2*M13*x1*x3 + 2*M23*x2*x3
## S-wave
# S-wave displacement RP 3-components
us1 = (x1*M11 + x2*M12 + x3*M13) - x1*core
us2 = (x1*M12 + x2*M22 + x3*M23) - x2*core
us3 = (x1*M13 + x2*M23 + x3*M33) - x3*core
# transform S-wave displacement vector to the spherical coordinate (r,theta, phi)
USV = np.cos(theta)*np.cos(phi)*us1 + np.cos(theta)*np.sin(phi)*us2 - np.sin(theta)*us3;
return USV, us1, us2, us3
####################################################################
phi = np.linspace(0., 360., 90) # (degrees) azimuth angle with the x1-axis
theta = np.linspace(0., 180. ,45) #(degrees) angle with x3-axis (assumes positive x3 upward)
# convert to radian
theta = np.radians(theta)
phi = np.radians(phi)
theta, phi = np.meshgrid(theta, phi)
st = np.sin(theta)
ct = np.cos(theta)
sp = np.sin(phi)
cp = np.cos(phi)
# generate the propagation ray vectror
x1 = st*cp
x2 = st*sp
x3 = ct
# define moment-tensor matrix
MT = np.array([[0, 1., 0.],[1., 0., 0.],[0., 0., 0.]])
USV, us1,us2,us3 = RP_source(theta,phi,MT)
#########################
# first plot
scale = np.abs(USV)
x1_sv = scale*x1
x2_sv = scale*x2
x3_sv = scale*x3
fig =plt.figure()
ax1 = fig.gca(projection='3d')
surf1 = ax1.plot_surface(x1_sv,x2_sv,x3_sv,rstride=1, cstride=1, facecolors=cm.jet(USV), alpha=0.6)
plt.ylabel('y-axis')
plt.xlabel('x-axis')
m1 = cm.ScalarMappable(cmap=cm.jet)
m1.set_array(USV)
plt.colorbar(m1)
cm.jet wants a number in the interval [0, 1].
Replace your surf1 =... line with the following line:
surf1 = ax1.plot_surface(x1_sv,x2_sv,x3_sv,rstride=1, cstride=1, facecolors=cm.jet(USV-np.min(USV.ravel())), alpha=0.6)

Resources