I want to plot two numpy arrays Z1 and Z2 in the same figure, Z2 on top of Z1. The array Z2 contains only 0's and 1's, and I want 0's to be fully transparent (alpha = 0) and 1's transparent with some alpha > 0.
Here's the code and the resulting image:
import numpy as np
import matplotlib.pyplot as plt
N = 10
x = np.arange(0, N)
y = np.arange(0, N)
Z1 = np.random.rand(N,N)
Z2 = np.ones((N, N))
Z2[0:N//2, 0:N] = 0
X, Y = np.meshgrid(x, y)
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(8, 6))
plt.pcolormesh(X, Y, Z1, cmap=plt.cm.Blues)
plt.colorbar()
plt.pcolormesh(X, Y, Z2, cmap=plt.cm.Reds_r, alpha=0.3)
ax.set_xlabel(r'$x$', fontsize=22)
ax.set_ylabel(r'$y$', fontsize=22)
plt.show()
There are two problems:
Appearance of the unwanted grid lines
The 0's of Z2 are not fully transparent as needed
To get rid of the grid lines we can use imshow instead of pcolor, but I really want to use the values of x and y.
The easiest option to get some of the pixels transparent is to not draw them at all. This would be done by setting them to NaN (not a number).
import numpy as np
import matplotlib.pyplot as plt
N = 10
x = np.arange(0, N)
y = np.arange(0, N)
Z1 = np.random.rand(N,N)
Z2 = np.ones((N, N))
Z2[0:N//2, 0:N] = np.nan
X, Y = np.meshgrid(x, y)
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(8, 6))
plt.pcolormesh(X, Y, Z1, cmap=plt.cm.Blues)
plt.colorbar()
plt.pcolormesh(X, Y, Z2, cmap=plt.cm.Reds, vmin=0,vmax=1,alpha=0.3)
ax.set_xlabel(r'$x$', fontsize=22)
ax.set_ylabel(r'$y$', fontsize=22)
plt.show()
Related
I've been trying to plot a (3d) sphere with some curves on it using Matplotlib, but so far the my results are disappointing.
I've tried with several RGB colors, opacities and colormaps, but the output is similar.
How could I do something like this Bloch Sphere? That's just what I'm looking for.
Thanks in advance!
To get a 3d plot more similar to the one you're showing, you can add some circular curves and lines along each axis. For example:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# Make data
r = 10
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = r * np.outer(np.cos(u), np.sin(v))
y = r * np.outer(np.sin(u), np.sin(v))
z = r * np.outer(np.ones(np.size(u)), np.cos(v))
# Plot the surface
ax.plot_surface(x, y, z, color='linen', alpha=0.5)
# plot circular curves over the surface
theta = np.linspace(0, 2 * np.pi, 100)
z = np.zeros(100)
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, color='black', alpha=0.75)
ax.plot(z, x, y, color='black', alpha=0.75)
## add axis lines
zeros = np.zeros(1000)
line = np.linspace(-10,10,1000)
ax.plot(line, zeros, zeros, color='black', alpha=0.75)
ax.plot(zeros, line, zeros, color='black', alpha=0.75)
ax.plot(zeros, zeros, line, color='black', alpha=0.75)
plt.show()
I have a list and i want to plot the list in such a way that for certain range of x axis the lines are dotted while for other range it is solid.
e.g.:
y=[11,22,33,44,55,66,77,88,99,100]
x=[1,2,3,4,5,6,7,8,9,10]
i did this:
if i range(4,8):
plt.plot(x,y,marker='D')
else :
plt.plot(x,y,'--')
plt.show()
but this doesnot work.
can someone help?
Slice the data into 3 intervals
import matplotlib.pyplot as plt
import numpy as np
# Data for plotting
x = [1,2,3,4,5,6,7,8,9,10]
y = [11,22,33,44,55,66,77,88,99,100]
fig, ax = plt.subplots()
m, n = 4, 8
x1, x2, x3 = x[:m+1], x[m:n+1], x[n:]
y1, y2, y3 = y[:m+1], y[m:n+1], y[n:]
ax.plot(x1, y1, color='red', linestyle='solid', marker='D')
ax.plot(x2, y2, color='blue', linestyle='dashed')
ax.plot(x3, y3, color='red', linestyle='solid', marker='D')
plt.show()
Here is a solution with the same colours for the whole line:
import matplotlib.pyplot as plt
x = [1,2,3,4,5,6,7,8,9,10]
y = [11,22,33,44,55,66,77,88,99,100]
fig, ax = plt.subplots()
x1, y1 = x[:4], y[:4]
x2, y2 = x[3:8], y[3:8]
x3, y3 = x[7:], y[7:]
ax.plot(x1, y1, marker='D', color='b')
ax.plot(x2, y2, '--', color='b')
ax.plot(x3, y3, marker='D', color='b')
Change line characteristics based on the value of x:
import numpy as np
from matplotlib import pyplot as plt
Make arrays of the lists;
y = np.array([11,22,33,44,55,66,77,88,99,100])
x = np.array([1,2,3,4,5,6,7,8,9,10])
make a boolean array based on your condition(s);
dashed = np.logical_or(x<4,x>=8)
use the boolean array to filter the data when you plot.
plt.plot(x[~dashed],y[~dashed],color='blue',marker='D')
plt.plot(x[dashed],y[dashed],color='blue',ls='--')
Is there any way to extend gridlines into the data area of a 3d plot?
I have this plot, and all of the plots are at 1 for the z-axis (confirmed by checking the array values), but this doesn't look obvious to me. I'm hoping that adding internal gridlines will help to clarify it. I generated it with this code:
fig = plt.figure(figsize = (10,10))
ax = plt.axes(projection ='3d')
x, y, z = np.array(list1), np.array(list2), np.array(list3)
c = x+y
ax.scatter(x, y, z, c=c)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.set_title(f'Title')
plt.show()
Thanks!
Option 1
If all the points are at a single Z value, then only plot a single plane
import matplotlib.pyplot as plt
import numpy as np
# test data
np.random.seed(365)
x, y = np.random.randint(2500, 20000, size=(7, )), np.random.randint(0, 1600, size=(7, ))
fig, ax = plt.subplots(figsize=(6, 6))
ax.scatter(x=x, y=y)
ax.set(title='Plane at Z=1')
Option 2
Plot lines at the axis ticks
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection='3d')
# test data
np.random.seed(365)
x, y, z = np.random.randint(2500, 20000, size=(7, )), np.random.randint(0, 1600, size=(7, )), np.ones(7)
c = x+y
ax.scatter(x, y, z, c=c)
# get the x and y tick locations
x_ticks = ax.get_xticks()
y_ticks = ax.get_yticks()
# add lines
for y1 in y_ticks:
x1, x2 = x_ticks[0], x_ticks[-1]
ax.plot([x1, x2], [y1, y1], [1, 1], color='lightgray')
for x1 in x_ticks:
y1, y2 = y_ticks[0], y_ticks[-1]
ax.plot([x1, x1], [y1, y2], [1, 1], color='lightgray')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.set_title(f'Title')
plt.show()
Say I want to inset a plot to a figure, but the inset plot has different axis range than the one I am marking the inset to. For example:
fig, ax = plt.subplots()
axins = inset_axes(ax, 1,1 , loc=2, bbox_to_anchor=(0.35,0.85),bbox_transform=ax.figure.transFigure)
x = np.linspace(0, 3, 100)
y = x**2
ax.plot(x, y)
axins.plot(x, x**3)
x1, x2, y1, y2 = 2.,3, 6, 8 # specify the limits
axins.set_xlim(x1, x2) # apply the x-limits
axins.set_ylim(y1, y2) # apply the y-limits
plt.xticks(visible=False)
plt.yticks(visible=False)
mark_inset(ax, axins, loc1=4, loc2=1)#, fc="none")#, ec="0.5")
The result is an empty inset plot:
But this is obvious, since I set the limits of x and y to ranges where x**3 does not pass.
What I want to see is, for example, a plot of x**3 for 0 to 1 in the inset plot, while the mark_inset will still 'zoom' to the region boxed above, which is of different range.
How can I do this?
In that case you cannot use mark_inset directly, because that is exactly what this function does: synchronizing the marker with the axes limits of the inset.
Using a rectangle
Instead you may position some rectangle whereever you want it to be and use ConnectionPatches to draw some lines in between the inset and the rectangle.
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.axes_grid1.inset_locator as il
import matplotlib.patches as mpatches
fig, ax = plt.subplots()
axins = il.inset_axes(ax, 1,1 , loc=2, bbox_to_anchor=(0.35,0.85),bbox_transform=ax.figure.transFigure)
x = np.linspace(0, 3, 100)
y = x**2
ax.plot(x, y)
axins.plot(x, x**3)
x1, x2, y1, y2 = 2.,3, 6, 8 # specify the limits
rect = mpatches.Rectangle((x1,y1), width=x2-x1, height=y2-y1, facecolor="None", edgecolor="k", linewidth=0.8)
fig.canvas.draw()
p1 = mpatches.ConnectionPatch(xyA=(1,0), xyB=(x2,y1), coordsA="axes fraction", coordsB="data", axesA=axins, axesB=ax)
p2 = mpatches.ConnectionPatch(xyA=(1,1), xyB=(x2,y2), coordsA="axes fraction", coordsB="data", axesA=axins, axesB=ax)
ax.add_patch(rect)
ax.add_patch(p1)
ax.add_patch(p2)
plt.show()
Use dummy axes
You may also simply add an additional inset, just for the purpose of using mark_inset with it.
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.axes_grid1.inset_locator as il
fig, ax = plt.subplots()
axins_dummy = il.inset_axes(ax, 1,1 , loc=2, bbox_to_anchor=(0.35,0.85),bbox_transform=ax.figure.transFigure)
axins = il.inset_axes(ax, 1,1 , loc=2, bbox_to_anchor=(0.35,0.85),bbox_transform=ax.figure.transFigure)
x = np.linspace(0, 3, 100)
y = x**2
ax.plot(x, y)
axins.plot(x, x**3)
x1, x2, y1, y2 = 2.,3, 6, 8 # specify the limits
axins_dummy .set_xlim(x1, x2) # apply the x-limits
axins_dummy .set_ylim(y1, y2) # apply the y-limits
axins_dummy.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False )
il.mark_inset(ax,axins_dummy , loc1=4, loc2=1)#, fc="none")#, ec="0.5")
plt.show()
In both cases, the resulting plot would look like
Maybe it's worth noting that the resulting graph is of course incorrect. Any reader would assume that the inset shows part of the curve, which is not the case. Hence make sure not to use such graph in a publication or report.
I would like to fill the area between the curve y1=x^3 and then line y2=3x-2.
Below is code I have that will do this, however, I want to place the restriction that y1 < y2 (which I have done with the where option of fill_between) and that x<1.
The problem that occurs with the code below is that the area between the curve is filled for x>1. I would like to plot these graphs on the range [-2.5,2.5]. How do I get matplotlib to stop filling between the curves for x>1?
My code:
import matplotlib.pyplot as plot
import numpy as np
x = np.linspace(-2.5, 2.5, 100)
y1 = np.array([i**3 for i in x])
y2 = np.array([3*i-2 for i in x])
fig = plot.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(x, y1, label=r"$y=x^3$")
ax.plot(x, y2, label=r"$y=3x-2$")
ax.spines['left'].set_position('center')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('center')
ax.spines['top'].set_color('none')
ax.spines['left'].set_smart_bounds(True)
ax.spines['bottom'].set_smart_bounds(True)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.fill_between(x, y1, y2, where=y2<y1, facecolor='green')
ax.legend()
plot.show()
I got it. The easiest fix is to define 3 new variables, u,v, and w, where u holds the x values for v and w, and v = x^3, w=3x-2.
u=x[x<1]
v=y1[y1<1]
w=y2[y2<1]
Then plot these values with fill_between:
ax.fill_between(u, v, w, where=w<v, facecolor='green')