facecolor for 3d plot doesn't work - python-3.x

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)

Related

Slider is not updating my diagram correctly

I am trying to plot the biffurcation diagram and its equation.
My problem is that I want to put a slider for when I change the rate in the logistic map equation, but I can't seem to understand what I need to code in the update function.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
rate = np.linspace(1, 4, 1000)
N = 1000
x = np.zeros(N) + 0.5
count = np.arange(round(N*0.9), N)
y = np.zeros(N) + 0.5
#t = 1
# Biffurcation
for rs in range(len(rate)):
for n in range(N-1):
x[n+1] = rate[rs] * x[n] * (1-x[n])
u = np.unique(x[count])
r = rate[rs] * np.ones(len(u))
for i in range(N - 1):
y[i + 1] = rate[rs] * y[i] * (1 - y[i])
# plotting
plt.plot(r, u, '.', markersize=2)
plt.ylabel(ylabel='X')
plt.xlabel(xlabel='r')
plt.title('Biffurcation')
# Plotting
fig, ax = plt.subplots()
axes, = ax.plot(y, 'o-')
ax.set_ylabel(ylabel='X')
ax.set_xlabel(xlabel='Time')
ax.set_title('$x_{n+1}$ = r * $x_{n}$ * (1-$x_{n}$)')
# defining axSlider
fig.subplots_adjust(bottom=0.25)
ax_slider = fig.add_axes([0.15, 0.1, 0.65, 0.03])
slider = Slider(ax_slider, label='r', valmin=1, valmax=4, valinit=1, valstep=rate)
# updating the plot
def update(val):
current_v = slider.val
rate[rs] = current_v
axes.set_ydata(rate[rs])
fig.canvas.draw()
slider.on_changed(update)
plt.show()
I tried to update my plot for when I change the rate on my slider, but it is not working properly.
def update(val):
current_v = slider.val
rate[rs] = current_v
axes.set_ydata(rate[rs])
fig.canvas.draw()

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 plot the figure in the desired fashion?

How to edit this code to have the same width and colour map as in the following figure? The script is based on this question.
import numpy as np
import matplotlib.pyplot as plt
dpi = 100
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,:]
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]
x = np.linspace(-3, 3, 100)
y = -(1/4*x**4 - 1.6*x**2)
fig, ax=plt.subplots(figsize=(4,2.5), dpi=dpi)
cmap = plt.get_cmap('Greys_r')
lw = 2.
lines = []
width_l = ax.get_ylim()[1] - ax.get_ylim()[0]
for t in np.linspace(0, 1, 40):
l, = ax.plot(x, y - t * 0.1 * width_l, color=cmap(t/2 + 0.25))
lines.append(l)
def plot_rainbow(event=None):
# initialization of lists
xr, yr = 6*[None], 6*[None]
xr[0],yr[0] = offset_curve(ax, x,y, lw/2.)
xr[1],yr[1] = offset_curve(ax, x,y, -lw/2.)
xr[2],yr[2] = offset_curve(ax, xr[0],yr[0], lw)
xr[3],yr[3] = offset_curve(ax, xr[1],yr[1], -lw)
xr[4],yr[4] = offset_curve(ax, xr[2],yr[2], lw)
xr[5],yr[5] = offset_curve(ax, xr[3],yr[3], -lw)
for i in range(6):
lines[i].set_data(xr[i], yr[i])
plot_rainbow()
fig.canvas.mpl_connect("resize_event", plot_rainbow)
fig.canvas.mpl_connect("button_release_event", plot_rainbow)
plt.show()
The figure above was created by the following script:
import numpy as np
import matplotlib.pyplot as plt
import math
dpi = 100
# 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
fig, ax=plt.subplots(figsize=(4,2.5), dpi=dpi)
cmap = plt.get_cmap('Greys_r')
x = np.linspace(-1, 1, 100)
y = -x**2
ax.set_ylim(-1.02, 0.3)
ax.scatter(1/2*(ax.get_xlim()[0] + ax.get_xlim()[1]), 0.145, marker = 'o', s=900, facecolors='none')
width_l = ax.get_ylim()[1] - ax.get_ylim()[0]
for t in np.linspace(0, 1, 40):
length = -0.1*width_l*t
ax.plot(*get_parallels(length=length), color=cmap(t/2 + 0.25))
plt.tight_layout()
plt.show()
Several curves are plotted in camp and the length is set.
I would like to have the same "shadow" for the curve in the first scrip. How to do that, please?

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)

Resources