Matplotlib - Assign specific colors to a surface - python

This snippet of code is going to generate the following two pictures, which represents a complex function. Is it possible to apply the colors of the first image to the surface? If so, how?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import hsv_to_rgb
def saw_func(x, dx, a, b):
x = x / dx - np.floor(x / dx)
return a + (b - a) * x
def domain_coloring(mag, arg, phaseres=20):
arg[arg < 0] += 2 * np.pi
arg /= (2 * np.pi)
blackp = saw_func(arg, 1 / phaseres, 0.75, 1)
blackm = saw_func(np.log(mag), 2 * np.pi / phaseres, 0.75, 1)
black = blackp * blackm
H = arg
S, V = np.ones_like(H), black
return (hsv_to_rgb(np.dstack([H, S, V])) * 255).astype(np.uint8)
x = y = np.linspace(-2, 2, 500)
x, y = np.meshgrid(x, y)
z = x + 1j * y
f = (z - 1) / (z**2 + z + 1)
mag, arg = np.absolute(f), np.angle(f)
img = domain_coloring(mag, arg)
fig1, ax1 = plt.subplots()
ax1.imshow(
img,
extent = [np.amin(x), np.amax(x), np.amin(y), np.amax(y)],
interpolation = "nearest",
origin = "lower",
)
plt.show()
fig2 = plt.figure()
ax2 = fig2.add_subplot(1, 1, 1, projection="3d")
ax2.plot_surface(x, y, mag)
ax2.set_zlim([0, 10])
plt.show()

This tutorial example uses a parameter facecolors=. The colors need to be rgb values between 0 and 1. The example code uses a 200x200 grid, as 500x500 is rather slow (and also has more problems with artifacts at the asymptotes). rstride and cstride are set to 1 as default plot_surface skips points.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import hsv_to_rgb
def saw_func(x, dx, a, b):
x = x / dx - np.floor(x / dx)
return a + (b - a) * x
def domain_coloring(mag, arg, phaseres=20):
arg[arg < 0] += 2 * np.pi
arg /= (2 * np.pi)
blackp = saw_func(arg, 1 / phaseres, 0.75, 1)
blackm = saw_func(np.log(mag), 2 * np.pi / phaseres, 0.75, 1)
black = blackp * blackm
H = arg
S, V = np.ones_like(H), black
return hsv_to_rgb(np.dstack([H, S, V]))
x = y = np.linspace(-2, 2, 200)
x, y = np.meshgrid(x, y)
z = x + 1j * y
f = (z - 1) / (z**2 + z + 1)
mag, arg = np.absolute(f), np.angle(f)
img = domain_coloring(mag, arg)
fig2 = plt.figure()
ax2 = fig2.add_subplot(1, 1, 1, projection="3d")
ax2.plot_surface(x, y, mag, facecolors=img)
ax2.set_zlim([0, 10])
plt.show()

Related

I want to Plot Circle and its Solid Revolution (Sphere) but get Error: loop of ufunc does not support argument 0 o

I have add the assumption of nonnegative for variables x and r so why I can't plot this?
this is my code:
# Calculate the surface area of y = sqrt(r^2 - x^2)
# revolved about the x-axis
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
x = sy.Symbol("x", nonnegative=True)
r = sy.Symbol("r", nonnegative=True)
def f(x):
return sy.sqrt(r**2 - x**2)
def fd(x):
return sy.simplify(sy.diff(f(x), x))
def f2(x):
return sy.sqrt((1 + (fd(x)**2)))
def vx(x):
return 2*sy.pi*(f(x)*sy.sqrt(1 + (fd(x) ** 2)))
vxi = sy.Integral(vx(x), (x, -r, r))
vxf = vxi.simplify().doit()
vxn = vxf.evalf()
n = 100
fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
x = np.linspace(1, 3, 3)
# Plot the circle
y = np.sqrt(r ** 2 - x ** 2)
t = np.linspace(0, np.pi * 2, n)
xn = np.outer(x, np.cos(t))
yn = np.outer(x, np.sin(t))
zn = np.zeros_like(xn)
for i in range(len(x)):
zn[i:i + 1, :] = np.full_like(zn[0, :], y[i])
ax1.plot(x, y)
ax1.set_title("$f(x)$")
ax2.plot_surface(xn, yn, zn)
ax2.set_title("$f(x)$: Revolution around $y$")
# find the inverse of the function
y_inverse = x
x_inverse = np.sqrt(r ** 2 - y_inverse ** 2)
xn_inverse = np.outer(x_inverse, np.cos(t))
yn_inverse = np.outer(x_inverse, np.sin(t))
zn_inverse = np.zeros_like(xn_inverse)
for i in range(len(x_inverse)):
zn_inverse[i:i + 1, :] = np.full_like(zn_inverse[0, :], y_inverse[i])
ax3.plot(x_inverse, y_inverse)
ax3.set_title("Inverse of $f(x)$")
ax4.plot_surface(xn_inverse, yn_inverse, zn_inverse)
ax4.set_title("$f(x)$: Revolution around $x$ \n Surface Area = {}".format(vxn))
plt.tight_layout()
plt.show()
That's because at this line of code:
y = np.sqrt(r ** 2 - x ** 2)
r is still a Sympy's symbol. You need to assign a number to r.

How to plot a vector field using Numpy?

The idea is to plot the following vector field:
I have two main issue with it:
1) I do not know how to make sure that the arrows are not too long (I know I have to use length, but how?).
2) I am told to use Numpyto draw the vector field but again, how?
This is what I have tried:
# The components of the vector field
F_x = y*e**x
F_y = x**2 + e**x
F_z = z**2*e**z
# The grid
xf = np.linspace(-0.15, 2.25, 8)
yf = np.linspace(-0.15, 2.25, 8)
zf = np.linspace(-0.75, 2.50, 8)
X_grid, Y_grid, Z_grid = np.meshgrid(xf, yf, zf)
# The arrows; how to deal with them?
dx = 1
#dy = ...
#dz = ...
# Standardize the arrows; In this way all arrows have the same length.
length = np.sqrt(dx**2 + dy**2 + dz**2)
dx_N = dx/length
dy_N = dy/length
dz_N = dz/length
#how to involve numpy in the process??
# Drawing the figure
fig, ax = plt.subplots(1, 1)
ax.quiver(X_grid, Y_grid, Z_grid, dx_N, dy_N, dz_N, dy, dz, cmap=plt.get_cmap('gnuplot2'))
plt.show()
Thanks
EDIT
Based on the provided link I tried:
from sympy import *
x,y,z = sp.symbols('x y z', real = True)
import matplotlib.pyplot as plt
x, y, z = np.meshgrid(np.arange(0, 2 * np.pi, .2), np.arange(0, 2 * np.pi, .2), np.arange(0, 2 * np.pi, .2))
F_x = y * exp(x)
F_y = x**2 + exp(x)
F_z = z**2 * exp(z)
# Normalize the arrows:
F_x = F_x / np.sqrt(F_x**2 + F_y**2 + F_z**2)
F_y = F_y / np.sqrt(F_x**2 + F_y**2 + F_z**2)
F_z = F_z / np.sqrt(F_x**2 + F_y**2 + F_z**2)
plt.figure()
plt.title('Vector field')
Q = plt.quiver(x, y, z, F_x, F_y, F_z, units='width')
qk = plt.quiverkey(Q, 0.9, 0.9, 2, r'$2 \frac{m}{s}$', labelpos='E',
coordinates='figure')#I don't understand this line
The TypeError: Shape should contain integers only comes up.
The problem is that I don't understand this part of the code:
qk = plt.quiverkey(Q, 0.9, 0.9, 2, r'$2 \frac{m}{s}$', labelpos='E',
coordinates='figure')
I am still stuck on how to plot this vector field
Assume that you want a 3D quiver, you can check out the matplotlib tutorial on quiver3D. And to control the arrow size, check out the Axes3d.quiver library doc, especially the parameters.
A quick snippet:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
x, y, z = np.meshgrid(np.arange(0, 2*np.pi, .5), np.arange(0, 2*np.pi, .5), np.arange(0, 2*np.pi, .5))
F_x = y * np.exp(x)
F_y = x**2 + np.exp(x)
F_z = z**2 * np.exp(z)
fig = plt.figure()
ax = fig.gca(projection='3d')
Q = ax.quiver(x, y, z, F_x, F_y, F_z, length=0.3, normalize=True)
But 3d quiver plot can be very crowded! : )
The quiver() method is a great tool to render vector fields. Since Matplotlib is a two-dimensional plotting library, we need to import the mplot3d toolkit to generate a three-dimensional plot.
Here's a good example:
Dependencies:
Axes3D for 3D rendering
Pyplot to get a MATLAB-like plotting framework
Numpy for numeric-array manipulation
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
x, y, z = np.meshgrid(np.arange(-0.8, 1, 0.25),
np.arange(-0.8, 1, 0.25),
np.arange(-0.8, 1, 0.8))
u = np.sin(np.pi * x) * np.cos(np.pi * y) * np.cos(np.pi * z)
v = -np.cos(np.pi * x) * np.sin(np.pi * y) * np.cos(np.pi * z)
w = (np.sqrt(2.0 / 3.0) * np.cos(np.pi * x) * np.cos(np.pi * y) * np.sin(np.pi * z))
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.quiver(x, y, z, u, v, w,
length=0.15,
color='Purple'
)
ax.view_init(elev=10, azim=30)
ax.dist=8
plt.show()

Spherical coordinates plot in pyqtgraph

I'm just starting with pyqtgraph and I want to make 3d surface plots in spherical coordinates. I've taken a look at the example GLSurfacePlot.py from the documentation but there are only plots in cartesian coordinates.
This is the plot I want to make (it's a half wave dipole radiation pattern):
How to plot r(theta, phi) with pyqtgraph?
EDIT: I could do it with matplotlib mplot3d, here is the script:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
k = 2*np.pi
long = 0.5
theta = np.linspace(0, np.pi, 361)
phi = np.linspace(0, 2*np.pi, 361)
PHI, THETA = np.meshgrid(phi, theta)
R = np.absolute((np.cos(k*long/2*np.cos(THETA))-np.cos(k*long/2))/np.sin(THETA))
R = np.nan_to_num(R)
X = R * np.sin(THETA) * np.cos(PHI)
Y = R * np.sin(THETA) * np.sin(PHI)
Z = R * np.cos(THETA)
fig = plt.figure()
ax = fig.add_subplot(111, projection = '3d')
cmap = plt.get_cmap('jet')
plot = ax.plot_surface(X, Y, Z, rstride=10, cstride=10, facecolors=cmap(R),linewidth=0, antialiased=False, alpha=1)
plt.show()
The problem is that it's too slow when rotating and zooming it, and I definitely need that feature for my application, that's why I'm trying to do it with pyqtgraph.
Drawing this type of equations is not possible through GLSurfacePlotItem, in this case you must use GLMeshItem, but for this you must create an appropriate MeshData, so it takes as a reference sphere obtaining the following function:
def DipoleData(rows, cols, func, args=None):
verts = np.empty((rows+1, cols, 3), dtype=float)
phi = (np.arange(rows+1) * 2*np.pi *(1+2/rows)/ rows).reshape(rows+1, 1)
th = ((np.arange(cols) * np.pi / cols).reshape(1, cols))
if args is not None:
r = func(th, phi, *args)
else:
r = func(th, phi)
s = r* np.sin(th)
verts[...,2] = r * np.cos(th)
verts[...,0] = s * np.cos(phi)
verts[...,1] = s * np.sin(phi)
verts = verts.reshape((rows+1)*cols, 3)[cols-1:-(cols-1)] ## remove redundant vertexes from top and bottom
faces = np.empty((rows*cols*2, 3), dtype=np.uint)
rowtemplate1 = ((np.arange(cols).reshape(cols, 1) + np.array([[0, 1, 0]])) % cols) + np.array([[0, 0, cols]])
rowtemplate2 = ((np.arange(cols).reshape(cols, 1) + np.array([[0, 1, 1]])) % cols) + np.array([[cols, 0, cols]])
for row in range(rows):
start = row * cols * 2
faces[start:start+cols] = rowtemplate1 + row * cols
faces[start+cols:start+(cols*2)] = rowtemplate2 + row * cols
faces = faces[cols:-cols] ## cut off zero-area triangles at top and bottom
## adjust for redundant vertexes that were removed from top and bottom
vmin = cols-1
faces[faces<vmin] = vmin
faces -= vmin
vmax = verts.shape[0]-1
faces[faces>vmax] = vmax
return gl.MeshData(vertexes=verts, faces=faces)
It is then used in the following example:
app = QtGui.QApplication([])
w = gl.GLViewWidget()
w.opts['distance'] = 3
w.show()
w.setWindowTitle('Half Wave Dipole Radiation Pattern')
def r_theta_phi(theta, phi, k, l):
return np.absolute((np.cos((k*l/2)*np.cos(theta)) -np.cos(k*l/2))/np.sin(theta))
p = 2*np.pi
q = 0.5
md = DipoleData(100, 100, r_theta_phi, args=(p, q))
colors = np.ones((md.faceCount(), 4), dtype=float)
colors[:,0] = np.linspace(0.1, 0.2, colors.shape[0])
colors[:,1] = np.linspace(0.2, 0.9, colors.shape[0])
colors[:,2] = np.linspace(0.0, 0.1, colors.shape[0])
md.setFaceColors(colors)
m = gl.GLMeshItem(meshdata=md, smooth=False)
w.addItem(m)
ax = gl.GLAxisItem()
ax.setSize(100,100,100)
w.addItem(ax)
g = gl.GLGridItem()
g.scale(0.2, 0.2, 0.2)
w.addItem(g)
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
Obtaining what is shown in the following image:

Arc between points in circle

I'm trying to plot a Chord diagram using Matplotlib. I am aware that already existing libraries, such as Plotly give me that functionality but I would really like to do it in matplotlib.
The code I have so far looks like this:
import itertools
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
fig, ax = plt.subplots()
ax.axhline(0, color='black', linestyle='--')
ax.axvline(0, color='black', linestyle='--')
npoints = 3
# Calculate the xy coords for each point on the circle
s = 2 * np.pi / npoints
verts = np.zeros((npoints, 2))
for i in np.arange(npoints):
angle = s * i
x = npoints * np.cos(angle)
y = npoints * np.sin(angle)
verts[i] = [x, y]
# Plot the arcs
numbers = [i for i in xrange(npoints)]
for i, j in itertools.product(numbers, repeat=2):
if i == j:
continue
x1y1 = x1, y1 = verts[i]
x2y2 = x2, y2 = verts[j]
# Calculate the centre of the Arc
mxmy = mx, my = [(x1 + x2) / 2, (y1 + y2) / 2]
r = np.sqrt((x1 - mx)**2 + (y1 - my)**2)
xy = [mx - r, my - r]
width = 2 * r
height = 2 * r
start_angle = np.arctan2(y1 - my, x1 - mx) * 180 / np.pi
end_angle = np.arctan2(y2 - my, x2 - mx) * 180 / np.pi
arc = patches.Arc(mxmy, width, height, start_angle, end_angle)
ax.add_patch(arc)
# Plot the points
x, y = verts.T
ax.scatter(x, y, marker='o', s=50, c='r')
ax.annotate("1", (x[0], y[0]), xytext=(x[0] + .5, y[0] + .5))
ax.annotate("2", (x[1], y[1]), xytext=(x[1] - 1, y[1] + .5))
ax.annotate("3", (x[2], y[2]), xytext=(x[2] - 1, y[2] - 1))
ax.set_xlim(-npoints - 5, npoints + 6)
ax.set_ylim(-npoints - 5, npoints + 6)
ax.set(aspect=1)
Is anyone able to tell me why my plot looks like this?
I'm expecting something more like the following (image taken from Plotly)
Edit 1
I would like to draw arcs between the following points:
1 and 2
1 and 3
2 and 3
These arcs should ideally be on the inside.
Edit 2
After some further investigation I figured that the end_angle seems to be the root of the problem.
After #f5r5e5d pointing out the Bézier curve used in plotly, I've decided to give this one a go. It looks like this is the way to go in my case, too.
import itertools
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import numpy as np
import sys
%matplotlib inline
fig, ax = plt.subplots()
npoints = 5
# Calculate the xy coords for each point on the circle
s = 2 * np.pi / npoints
verts = np.zeros((npoints, 2))
for i in np.arange(npoints):
angle = s * i
x = npoints * np.cos(angle)
y = npoints * np.sin(angle)
verts[i] = [x, y]
# Plot the Bezier curves
numbers = [i for i in xrange(npoints)]
bezier_path = np.arange(0, 1.01, 0.01)
for a, b in itertools.product(numbers, repeat=2):
if a == b:
continue
x1y1 = x1, y1 = verts[a]
x2y2 = x2, y2 = verts[b]
xbyb = xb, yb = [0, 0]
# Compute and store the Bezier curve points
x = (1 - bezier_path)** 2 * x1 + 2 * (1 - bezier_path) * bezier_path * xb + bezier_path** 2 * x2
y = (1 - bezier_path)** 2 * y1 + 2 * (1 - bezier_path) * bezier_path * yb + bezier_path** 2 * y2
ax.plot(x, y, 'k-')
x, y = verts.T
ax.scatter(x, y, marker='o', s=50, c='r')
ax.set_xlim(-npoints - 5, npoints + 6)
ax.set_ylim(-npoints - 5, npoints + 6)
ax.set(aspect=1)
The code above plots what I wanted it do to. Some modifications on the style and it should be good to go.
Since the underlying problem was "how can I draw a chord diagram in matplotlib", I just want to let you know that there is now a python library to do that: mpl-chord-diagram.
You can just do pip install mpl-chord-diagram.
[disclaimer] I am the current maintainer [/disclaimer]

Matlab plot equivalent in Python [duplicate]

I'd like to plot pulse propagation in such a way at each step, it plots the pulse shape. In other words, I want a serie of x-z plots, for each values of y. Something like this (without color):
How can I do this using matplotlib (or Mayavi)? Here is what I did so far:
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
surf = ax.plot_wireframe(T, z, abs(U))
Change to:
ax.plot_wireframe(T, z, abs(U), cstride=1000)
and call:
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
will create the following graph:
If you need the curve been filled with white color:
import numpy
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot
from matplotlib.collections import PolyCollection
def drawPropagation(beta2, C, z):
""" beta2 in ps / km
C is chirp
z is an array of z positions """
T = numpy.linspace(-10, 10, 100)
sx = T.size
sy = z.size
T = numpy.tile(T, (sy, 1))
z = numpy.tile(z, (sx, 1)).T
U = 1 / numpy.sqrt(1 - 1j*beta2*z * (1 + 1j * C)) * numpy.exp(- 0.5 * (1 + 1j * C) * T * T / (1 - 1j*beta2*z*(1 + 1j*C)))
fig = pyplot.figure()
ax = fig.add_subplot(1,1,1, projection='3d')
U = numpy.abs(U)
verts = []
for i in xrange(T.shape[0]):
verts.append(zip(T[i, :], U[i, :]))
poly = PolyCollection(verts, facecolors=(1,1,1,1), edgecolors=(0,0,1,1))
ax.add_collection3d(poly, zs=z[:, 0], zdir='y')
ax.set_xlim3d(numpy.min(T), numpy.max(T))
ax.set_ylim3d(numpy.min(z), numpy.max(z))
ax.set_zlim3d(numpy.min(U), numpy.max(U))
drawPropagation(1.0, 1.0, numpy.linspace(-2, 2, 10))
pyplot.show()

Categories

Resources