matplotlib fill_between issue with x argument - matplotlib

I try to fill a space below my plot, the plot is y=x so it is a straight line with an angle of 45 deg. I try to fill the area below the curve from x=1 to x=10, how to do that using fill_between?

That's what where keyword argument is for.
where :
If None, default to fill between everywhere. If not None, it is an N-length numpy boolean array and the fill will only happen over the
regions where where==True.
For example:
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> fig, ax = plt.subplots()
>>> x = np.linspace(0, 10, 50)
>>> y = x**2
>>> ax.plot(x, y, 'r-')
[<matplotlib.lines.Line2D object at 0x1e91250>]
>>> wh = (x>1) & (x<10)
>>> ax.fill_between(x, y, where=wh, alpha=0.2)
<matplotlib.collections.PolyCollection object at 0x24dd210>
>>> plt.show()

Related

matplotlib - mask portion of standalone colorbar

Below is the code to build a standalone continuous colorbar. I would like to mask, with black, all values between -3 and 3.
import matplotlib.pyplot as plt
import matplotlib as mpl
fig, ax = plt.subplots(figsize=(8, .25))
cmap = mpl.cm.twilight
norm = mpl.colors.Normalize(vmin=-9.6, vmax=9.6)
cbar = mpl.colorbar.ColorbarBase(ax, cmap=cmap, norm=norm, orientation='horizontal', ticks=[-3,3])
The function colors.ListedColormap creates a new colormap from a list of colors. The following code retrieves these colors from an existing map and makes the desired modifications:
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
cmap = mpl.cm.get_cmap('twilight', 256)
norm = mpl.colors.Normalize(vmin=-9.6, vmax=9.6)
maskedcolors = cmap(np.linspace(0, 1, 256))
black = np.array([0, 0, 0, 1])
maskedcolors[int(round(norm(-3) * 256)) : int(round(norm(3) * 256)) + 1] = black
maskedcmp = mpl.colors.ListedColormap(maskedcolors)
fig, ax = plt.subplots(figsize=(8, .5))
cbar = mpl.colorbar.ColorbarBase(ax, cmap=maskedcmp, norm=norm, orientation='horizontal', ticks=[-3, 3])
fig.subplots_adjust(bottom=0.5)
plt.show()

Triangular surface plot matplotlib

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
ax.plot_trisurf(X, Y, Z, cmap='viridis', edgecolor='none')
plt.show()
I tried to plot this data in form of triangular data but I get this error:
ValueError: x and y must be equal-length 1-D arrays
Can someone help me on it?
In triangular surface plot X,Y,Z must be one dimensional array rather than two dimensional as in case of wireframe and surface plot.
Don't use np.meshgrid().

Plot 2D array of (x,y,z) points in 3D space (Matplotlib)

I'm a beginner in Python and specially in Matplotlib. I have a 22797x3 array, built from a multiplication between two other arrays, one 22797x400 long and the other 400x3 long. In the resulted array (22797x3),each line represents a point with (x,y,z) coordinates, hence the 3 columns. How could I plot that resulted array in a 3D surface, where I can see all the 22797 points spread in 3D space? This data is for future Kmeans clustering, so I need to visualise it.
So far I've tried:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
#building the 22797x3 array:
#loading the first array from .txt file, 22797x400 long.
array = np.loadtxt('C:\Users\Scripts/final_array.txt', usecols=range(400))
array = np.float32(array)
#loading the second array from .txt file, 400x3 long.
small_vh2 = np.loadtxt('C:\Users\Scripts/small_vh2.txt', usecols=range(3))
small_vh2 = np.float32(small_vh2)
#multiplying and getting result array 22797x3 long:
Y = np.array(np.matmul(array,small_vh2))
#I've checked Y dimensions, it's 22797x3 long, working fine.
#now I must plot it in 3D:
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(Y[:, 0], Y[:, 1], Y[:, 2])
plt.show()
I keep getting the result shown in the image below:
https://i.stack.imgur.com/jRyHM.jpg
What I need is to get is the 22797 points, and I keep getting only 4 points plotted. Does anybody know what is wrong with the code?
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib import pyplot as plt
# made 2 random arrays of the same size as yours
array = np.random.rand(22797, 400)
small_vh2 = np.random.rand(400,3)
Y = np.matmul(array,small_vh2)
#now I must plot it in 3D:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(Y[:, 0], Y[:, 1], Y[:, 2], alpha = 0.1)
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.show()

unexpected constant color using matplotlib surface_plot and facecolors

I am plotting a function on the surface of a sphere. To test my code, I simply plot the spherical coordinate phi divided by pi. I get
Unexpectedly, half of the sphere is of the same color, and the colors on the other half aren't correct (at phi=pi, i should get 1, not 2). If I divide the data array by 2, the problem disappears. Can someone explain to me what is happening?
Here is the code I use:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
# prepare the sphere surface
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')
phi = np.linspace(0,2*np.pi, 50)
theta = np.linspace(0, np.pi, 25)
x=np.outer(np.cos(phi), np.sin(theta))
y=np.outer(np.sin(phi), np.sin(theta))
z=np.outer(np.ones(np.size(phi)), np.cos(theta))
# prepare function to plot
PHI=np.outer(phi,np.ones(np.size(theta)))
THETA=np.outer(np.ones(np.size(phi)),theta)
data = PHI/np.pi
# plot
surface=ax.plot_surface(x, y, z, cstride=1, rstride=1,
facecolors=cm.jet(data),cmap=plt.get_cmap('jet'))
# add colorbar
m = cm.ScalarMappable(cmap=surface.cmap,norm=surface.norm)
m.set_array(data)
plt.colorbar(m)
plt.show()
There is a little bit of chaos in the code.
When specifying facecolors, there is no reason to supply a colormap, because the facecolors do not need to be retrieved from a colormap.
Colormaps range from 0 to 1. Your data ranges from 0 to 2. Hence half of the facecolors are just the same. So you first need to normalize the data to the (0,1)-range, e.g. using a Normalize instance, then you can apply the colormap.
norm = plt.Normalize(vmin=data.min(), vmax=data.max())
surface=ax.plot_surface(x, y, z, cstride=1, rstride=1,
facecolors=cm.jet(norm(data)))
For the colorbar you should then use the same colormap and the same normalization as for the plot itself.
m = cm.ScalarMappable(cmap=cm.jet,norm=norm)
m.set_array(data)
Complete code:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
# prepare the sphere surface
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')
phi = np.linspace(0,2*np.pi, 50)
theta = np.linspace(0, np.pi, 25)
x=np.outer(np.cos(phi), np.sin(theta))
y=np.outer(np.sin(phi), np.sin(theta))
z=np.outer(np.ones(np.size(phi)), np.cos(theta))
# prepare function to plot
PHI=np.outer(phi,np.ones(np.size(theta)))
THETA=np.outer(np.ones(np.size(phi)),theta)
data = PHI/np.pi
# plot
norm = plt.Normalize(vmin=data.min(), vmax=data.max())
surface=ax.plot_surface(x, y, z, cstride=1, rstride=1,
facecolors=cm.jet(norm(data)))
# add colorbar
m = cm.ScalarMappable(cmap=cm.jet,norm=norm)
m.set_array(data)
plt.colorbar(m)
plt.show()

Label is Missing from matplotlib legend

I'm plotting subplots with matplotlib and the legend does not show up for some plots.
In this example, the scatter plot legend does not show up.
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
from matplotlib.legend_handler import HandlerLine2D
from matplotlib.patches import Rectangle, Circle
fig = plt.figure()
plt.cla()
plt.clf()
x = np.arange(5) + 1
y = np.full(5, 10)
fig, subplots = plt.subplots(2, sharex=False, sharey=False)
subplots[0].bar(x, y, color='r', alpha=0.5, label='a')
scat = subplots[0].scatter(x, y-1, color='g', label='c')
subplots[0].set_yscale('log')
subplots[1].bar(x, y, color='r', alpha=0.5, label='a')
x = [2, 3]
y = [4, 4]
subplots[1].bar(x, y, color='b', alpha=1, label='b')
subplots[1].set_yscale('log')
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), handler_map={scat: HandlerLine2D(numpoints=4)})
plt.show()
Here is what I tried as a workaround:
p1 = Rectangle((0, 0), 1, 1, fc="r", alpha=0.5)
p2 = Rectangle((0, 0), 1, 1, fc="b")
p3 = Circle((0, 0), 1, fc="g")
legend([p1, p2, p3], ['a', 'b', 'c'], loc='center left', bbox_to_anchor=(1, 0.5))
I really prefer to fix this without the workaround so if anyone knows how to fix it please let me know.
Also, an issue with the workaround is that the Circle object still appears as a bar on the legend.
plt.legend starts with a gca() (which returns the current axes):
# from pyplot.py:
def legend(*args, **kwargs):
ret = gca().legend(*args, **kwargs)
So calling plt.legend will only get you a legend on your last subplot. But it is also possible to call e.g. ax.legend(), or in your case subplots[0].legend(). Adding that to the end of your code gives me a legend for both subplots.
Sample:
for subplot in subplots:
subplot.legend(loc='center left', bbox_to_anchor=(1, 0.5))