Related
I am trying to use the 3D surface plot feature in matplotlib. I always get a single color in the main 3D plot even though the colorbar has the correct color distribution. I have tried adjusting the vmin and vmax values. It changes the displayed color, but it is still a single color.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
import matplotlib.colors as colors
plt.rc('font', size=20) # controls default text sizes
plt.rc('axes', titlesize=20) # fontsize of the axes title
plt.rc('axes', labelsize=20) # fontsize of the x and y labels
plt.rc('xtick', labelsize=20) # fontsize of the tick labels
plt.rc('ytick', labelsize=20) # fontsize of the tick labels
plt.rc('legend', fontsize=20) # legend fontsize
plt.rc('figure', titlesize=20) # fontsize of the figure title
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
X = np.linspace(1, 9, 9)
Y = np.linspace(0.1, 0.9, 9)
X, Y = np.meshgrid(X, Y)
y14=[0.4452739,0.30183285,0.25813195,0.22200696,0.19410882,0.17159065,0.15946234,0.1454833,0.13729666]
y24=[0.36556191,0.26622398,0.20779134,0.17347617,0.15454879,0.13959851,0.12783846,0.1125244,0.0991787]
y34=[0.28298545,0.20158779,0.15011216,0.13871456,0.12187855,0.1108228,0.09260828,0.09191485,0.08405019]
y44=[0.23466043,0.1570963,0.12579934,0.11918668,0.0973392,0.08328725,0.08287371,0.07223769,0.06703042]
y54=[0.20135427,0.14908527,0.11954249,0.09954416,0.08083851,0.07613027,0.06216689,0.06148425,0.05450287]
y64=[0.18790923,0.13138967,0.09762079,0.08155587,0.06951088,0.06225487,0.05563515,0.05375833,0.04966462]
y74=[0.1646632,0.11620533,0.08697924,0.06734929,0.06212874,0.05564317,0.05146634,0.05027161,0.04692116]
y84=[0.15172702,0.09854979,0.07125092,0.06229793,0.05398641,0.05226622,0.05084956,0.0496555,0.05421488]
y94=[0.13190896,0.07993282,0.06037859,0.05867347,0.0576491,0.05695472,0.05695472,0.05876029,0.05545337]
Z=[y14,y24,y34,y44,y54,y64,y74,y84,y94]
Z=np.array(Z)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, linewidth=0, antialiased=False)
# Customize the z axis.
ax.set_zlim(0, 0.45)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Please find the attached image for the result I get: output image
It seems you are using an old version of matplotlib. In this case the rstride and cstride arguments are set to 10. However you have less than 10 points along each dimension in your plot, hence only a single point is used for the color information.
Use
ax.plot_surface(..., rstride=1, cstride=1, ...)
to have every point's color information visualized in the plot.
In general, always refer to the examples of your matplotlib version. E.g. if you were using matplotlib 1.4.1, look at
https://matplotlib.org/1.4.1/examples/mplot3d/surface3d_demo.html
I'm working with python 3.4. I'm trying to plot a simple surface from a 2D array (11x13), but the colour map is not graduating properly. There's only a small range, but the colour bar looks reasonable while the plot just has stripes. Doesn't seem to matter what colourmap I use I get an equivalent result.
From another post, I tried using the rstride & cstride parameters, but that just turned the entire surface pink (with this map).
Any suggestions? I adapted the code from one of the mplot3d tutorial examples - basically just replaced X, Y, Z and the axis limits and tried different colour maps.
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
# Make data.
X = np.arange(0,550,50)
Y = np.arange(-12,1,1)
X, Y = np.meshgrid(X, Y)
# Array calculated with a process in excel...I'll learn to python it later.
Z = np.array([[0,0,0,0,0,0,0,0,9.318546297,9.32278014,9.324432509],
[0,0,0,0,0,0,9.270465014,9.281098393,9.287418343,9.291620087,9.293257704],
[0,0,0,9.183895053,9.20724459,9.226419172,9.239450746,9.25002849,9.257383697,9.261920422,9.263632585],
[9,9.086332608,9.126397936,9.153091476,9.176369804,9.195477721,9.210108238,9.22128034,9.229169896,9.233975347,9.235758722],
[9,9.0556775,9.095671635,9.125345711,9.149164982,9.168378335,9.183464661,9.194945002,9.203079816,9.208024884,9.209844315],
[9,9.040637647,9.075058225,9.10310915,9.126085,9.144796641,9.15970021,9.171125191,9.179264934,9.184223248,9.186039585],
[9,9.031750626,9.060617885,9.085619791,9.106813693,9.12444679,9.13872781,9.149807723,9.157769849,9.162644172,9.164426795],
[9,9.025687536,9.049859786,9.071632721,9.09067842,9.106911657,9.120316269,9.130877982,9.138559174,9.14329971,9.145034568],
[9,9.021085904,9.041333766,9.060092969,9.076965929,9.091711302,9.104158214,9.114155647,9.121547513,9.126169075,9.127867857],
[9,9.017274923,9.034147314,9.050188629,9.065030255,9.07836292,9.08991453,9.099425441,9.106628029,9.111235402,9.112955947],
[9,9.01382656,9.027663537,9.041265696,9.054295453,9.066400007,9.077233581,9.086451516,9.09368943,9.098527457,9.100440892],
[9,9.010336943,9.021310255,9.032733661,9.044224745,9.055367181,9.065750219,9.074968252,9.082599449,9.088144367,9.090799207],
[9,9.00619218,9.014431776,9.023994936,9.034293996,9.04481216,9.055077078,9.064646767,9.073106766,9.080108346,9.085588416]])
# replacing the zeroes with NaN
for i in range(np.shape(Z)[0]):
for j in range(np.shape(Z)[1]):
if Z[i,j] == 0:
Z[i,j] = float('nan')
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.cool,
linewidth=0, antialiased=False)
# Customize the z axis.
ax.set_zlim(9, 9.5)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
For anyone else that finds this thread with a similar question:
After reading a question about handling of NaN cells, I tried modifying the ax.plot_surface command with nanmin and nanmax arguments and that sorted out the colour stretching:
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, linewidth=0, antialiased=False, rstride=1, cstride=1,
vmin=np.nanmin(Z), vmax=np.nanmax(Z))
I have an issue (bug?) with 3D plotting in matplotlib that I wonder if anyone may be able to help with please?
As can be seen by the matplotlib gallery example plots (e.g. from: https://matplotlib.org/examples/mplot3d/surface3d_demo.html), when the user sets the axis limits manually, and a tick is placed at the limit, the axis bound is extended a little:
I want the axis to show the 1.01 tick label, but this should be the vertex of the cube (with no grey space / black axis line above it). Is this possible please?
As a separate, more minor request, I'd then like to draw a solid black line around the edge of the grid to make it stand out. This is less important than fixing the bounds, however.
For reference, here is the code that makes the above plot:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
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)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, linewidth=0, antialiased=False)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
I try to make colorful scatter plot using third variable to define color. It is simple to use the following code:
plt.scatter(mH, mA, s=1, c=mHc)
plt.colorbar()
plt.show()
But I do not have many choices to modify the frame of the plot. I am trying the following code to make colorful scatter plot, at the same time I try to optimize the frame of the plot:
import numpy as np
import math
from matplotlib import rcParams
import matplotlib.pyplot as plt
from matplotlib.ticker import AutoMinorLocator
fig, ax = plt.subplots()
cax = ax.scatter(mH,mA,s=0.5,c=mHc) ### mH, mA, mHC are the dataset
fig.colorbar(cax)
minor_locator1 = AutoMinorLocator(6)
minor_locator2 = AutoMinorLocator(6)
ax.xaxis.set_minor_locator(minor_locator1)
ax.yaxis.set_minor_locator(minor_locator2)
ax.tick_params('both', length=10, width=2, which='major')
ax.tick_params('both', length=5, width=2, which='minor')
ax.set_xlabel(r'$m_H$')
ax.set_ylabel(r'$m_A$')
ax.set_xticks([300,600,900,1200,1500])
ax.set_yticks([300,600,900,1200,1500])
plt.savefig('mH_mA.png',bbox_inches='tight')
plt.show()
But the plot I got is black-white. It looks like the problem lies in the marker size argument, but I do not have much idea how to correct it. I want to have smaller marker size. Anyone can offer me some idea to approach this issue. Thanks.
size=0.5 is extremely small - probably all you are seeing is the marker outlines. I would suggest you increase the size a bit, and perhaps pass edgecolors="none" to turn off the marker edge stroke:
import numpy as np
from matplotlib import pyplot as plt
n = 10000
x, y = np.random.randn(2, n)
z = -(x**2 + y**2)**0.5
fig, ax = plt.subplots(1, 1)
ax.scatter(x, y, s=5, c=z, cmap="jet", edgecolors="none")
You might also want to experiment with making the points semi-transparent using the alpha= parameter:
ax.scatter(x, y, s=20, c=z, alpha=0.1, cmap="jet", edgecolors="none")
It can be difficult to get scatter plots to look nice when you have such a massive number of overlapping points. I would be tempted to plot your data as a 2D histogram or contour plot instead, or perhaps even a combination of a scatter plot and a contour plot:
density, xe, ye = np.histogram2d(x, y, bins=20, normed=True)
ax.hold(True)
ax.scatter(x, y, s=5, c=z, cmap="jet", edgecolors="none")
ax.contour(0.5*(xe[:-1] + xe[1:]), 0.5*(ye[:-1] + ye[1:]), density,
colors='k')
I have a simple task that should have a simple solution, but I have been trying for days now. I try to be specific.
I try to plot a surface using matplotlib's mplot3d and plot_surface.
When I plot the surface of a dataset 'z' and try to scale the colormap to a certain maximum value I change the 'vmax' property to this value. That works great.
When I try to plot a surface of one dataset (z) and use the facecolors of a second dataset (fc), this also works fine.
When I want to scale the colormap of the facecolors, the vmax property is overruled by the facecolors values. Vmax therefore has no effect (attempt1). The lines also disappeared, but that's another issue.
Also trying to change the values of the facecolor dataset (fc) did not have the desired effect (attempt2).
I try to get a figure with a scaled colormap (as in the figure 'scaled' below) but scaled to the facecolors, and not the z-values.
The code below is what I have now, and the results look like this:
Does anyone know what I am missing here? Any thoughts are appreciated!
import pylab as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
plt.ion()
# creating dataset
profile = np.arange(20)**2
z = profile.repeat(20).reshape(20,20)
fc= np.rot90(z.copy())
x = np.arange(z.shape[0])
y = np.arange(z.shape[1])
X, Y = np.meshgrid(x,y)
# plotting
vmax = 100
fig = plt.figure()
ax = fig.add_subplot(1,4,1, projection='3d', azim=210)
ax.plot_surface(X,Y,z, cmap=plt.cm.jet, cstride=1, rstride=1)
ax.set_title('normal')
ax = fig.add_subplot(1,4,2, projection='3d', azim=210)
ax.plot_surface(X,Y,z, cmap=plt.cm.jet, cstride=1, rstride=1, vmax=vmax)
ax.set_title('scaled')
ax = fig.add_subplot(1,4,3, projection='3d', azim=210)
ax.plot_surface(X,Y,z, facecolors=plt.cm.jet(fc), cstride=1, rstride=1, vmax=vmax)
ax.set_title('rotated (attempt1)')
ax = fig.add_subplot(1,4,4, projection='3d', azim=210)
fc[fc> vmax] = vmax
ax.plot_surface(X,Y,z, facecolors=plt.cm.jet(fc), cstride=1, rstride=1)
ax.set_title('rotated (attempt2)')
One - dirty - solution would be to rescale the clipped facecolors such that the maximum is equal to the maximum of your height map (in addition to basically what you suggested as attempt 2):
ax.plot_surface(X,Y,z, facecolors=plt.cm.jet(np.clip(fc,0,vmax)*np.max(z)/vmax), cstride=1, rstride=1, vmax=vmax)
Does this give the result you are looking for?