plotting single 3D point on top of plot_surface in python matplotlib - python

I have some code to plot 3D surfaces in Python using matplotlib:
import math
import numpy as np
import matplotlib.pyplot as plt
from pylab import meshgrid,cm,imshow,contour,clabel,colorbar,axis
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import seaborn as sns
sns.set(style="white")
def surface_map(func, xmin=0, xmax=1, ymin=0, ymax=1, step_size=0.05, maxz=25000):
X, Y = meshgrid(
np.arange(xmin, xmax, step_size),
np.arange(ymin, ymax, step_size))
Z = np.zeros(X.shape)
for i in range(X.shape[0]):
for j in range(X.shape[1]):
Z[i, j] = min(func(X[i, j], Y[i, j]), maxz)
return X, Y, Z
def plot_surface(X, Y, Z, xlabel, ylabel, zlabel, title, point=None, size=25):
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z,
rstride=1, cstride=1, vmin=0, vmax=20*1000,
cmap=cm.RdBu, linewidth=0, antialiased=True)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_zlabel(zlabel)
ax.set_title(title)
fig.colorbar(surf, shrink=0.5, aspect=5)
if point:
ax.hold(True)
func, fpr, recall = point
ax.scatter([fpr], [recall], [
func(fpr, recall)
], s=size, c='b', marker='.', zorder=10)
plt.show()
And then I call it like so:
# create mesh
R, FPR, FuncValue = surface_map(my_function, xmin=0, xmax=1, ymin=0, ymax=1, step_size=0.05, maxz=20*1000)
# plot it
plot_surface(R, FPR, FuncValue,
xlabel="Recall",
ylabel="FPR",
zlabel="Function Value",
title="Recall Settings Payout Function",
point=(my_function, 0.5, 0.5))
I'm setting ax.scatter to use large marker sizes and a high zorder, but no point gets drawn on the surface when the plot gets rendered.
What am I missing?

The point you are looking for is there, but hidden "inside" the surface. This is a common problem in matplotlib.
I see two options here:
Make the surface plot semitransparent, i.e. use alpha=.8 or similar.
Use plot instead of scatter.

Related

How to get the slice of a plot3d object?

I have some points and I plot the surface of them using the code below:
import matplotlib.pyplot as plt
from matplotlib import cm, colors
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# Create a sphere
r = 1
pi = np.pi
cos = np.cos
sin = np.sin
phi, theta = np.mgrid[0.0:pi:20j, 0.0:2.0*pi:20j]
radis=np.random.normal(1,0.2,(20,20))
x = radis*sin(phi)*cos(theta)
y = radis*sin(phi)*sin(theta)
z = radis*cos(phi)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(
x, y, z, rstride=1, cstride=1, color='c', alpha=0.3, linewidth=0)
ax.scatter3D(x,y,z, c='r')
ax.set_xlim([-1,1])
ax.set_ylim([-1,1])
ax.set_zlim([-1,1])
# ax.set_aspect("equal")
plt.tight_layout()
plt.show()
Then I get the 3d plot result:
The thing I want to do is that get the image of any plane, like z=0.
Is there any method or library can cover this problem?

X custom data, Y custom data, how to fill gradient color in area chart?

I have custom data on X and Y.
Actually i'm using plt.fill_between to have an area chart with fixed color.
I would like to have gradient color instead of fixed color.
import matplotlib.pyplot as plt
import pylab
import numpy as np
import matplotlib
x1 = ['LUG','17','18','19','22','23','24','25','26','29','30','31','AGO','2']
z = [0,0.27,0.6,0.42,-0.48,-0.53,0.41,-0.61,0.48,-0.25,1.04,1.57,1.07,1.69]
plt.subplot(4, 1, 4)
plt.fill_between(x1, z, color='yellow', alpha=0.1)
plt.fill_between( x1, z, color="yellow", alpha=0.1)
plt.plot(x1, z, color="red", alpha=0.6)
plt.axhline(y=0, linewidth=1, color='pink')
plt.xlabel('time (day)')
#legend
plt.legend(['Equity'], loc='lower left')
plt.tight_layout()
plt.show()

Removing floor from 3D surface plot

I am trying to "remove the floor" from a 3D surface plot. For example, in this matplotlib demo code:
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, alpha=0.3)
cset = ax.contour(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)
cset = ax.contour(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)
ax.set_xlabel('X')
ax.set_xlim(-40, 40)
ax.set_ylabel('Y')
ax.set_ylim(-40, 40)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)
I am trying to just get the top half of the 3d surface, without the blue floor and the bottom hump. I'd like them transparent.
I've tried setting vmin appropriately, and even using a masked array but I still get the "floor" of color in my plots.
Note: My real situation is plotting a KDE generated on some data, on a grid of points and I dont want the entire bottom of my plot to be the same blue color.
The idea can be to set the unwanted part to a transparent color, using a normalization of the colormap.
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib.colors
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
norm = matplotlib.colors.Normalize(0,100)
cmap = cm.coolwarm
cmap.set_under((0,0,0,0), alpha=0.0)
ax.plot_surface(X, Y, Z, rstride=8, cstride=8, norm=norm, cmap=cmap)
ax.set_xlabel('X')
ax.set_xlim(-40, 40)
ax.set_ylabel('Y')
ax.set_ylim(-40, 40)
ax.set_zlabel('Z')
ax.set_zlim(-100, 100)
plt.show()

Surface and 3d contour in matplotlib

I would like to plot a surface with a colormap, wireframe and contours using matplotlib. Something like this:
Notice that I am not asking about the contours that lie in the plane parallel to xy but the ones that are 3D and white in the image.
If I go the naïve way and plot all these things I cannot see the contours (see code and image below).
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
X, Y = np.mgrid[-1:1:30j, -1:1:30j]
Z = np.sin(np.pi*X)*np.sin(np.pi*Y)
ax.plot_surface(X, Y, Z, cmap="autumn_r", lw=0.5, rstride=1, cstride=1)
ax.contour(X, Y, Z, 10, lw=3, cmap="autumn_r", linestyles="solid", offset=-1)
ax.contour(X, Y, Z, 10, lw=3, colors="k", linestyles="solid")
plt.show()
If a add transparency to the surface facets then I can see the contours, but it looks really cluttered (see code and image below)
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
X, Y = np.mgrid[-1:1:30j, -1:1:30j]
Z = np.sin(np.pi*X)*np.sin(np.pi*Y)
ax.plot_surface(X, Y, Z, cmap="autumn_r", lw=0.5, rstride=1, cstride=1, alpha=0.5)
ax.contour(X, Y, Z, 10, lw=3, cmap="autumn_r", linestyles="solid", offset=-1)
ax.contour(X, Y, Z, 10, lw=3, colors="k", linestyles="solid")
plt.show()
Question: Is there a way to obtain this result in matplotlib? The shading is not necessary, though.
Apparently it is a bug, if you try this
import numpy as np
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
X, Y = np.mgrid[-1:1:30j, -1:1:30j]
Z = np.sin(np.pi*X)*np.sin(np.pi*Y)
ax.plot_surface(X, Y, Z, cmap="autumn_r", lw=0, rstride=1, cstride=1)
ax.contour(X, Y, Z+1, 10, lw=3, colors="k", linestyles="solid")
plt.show()
And rotate around, you will see the contour lines disappearing when they shouldn't
I think you want to set the offset to the contour :
ax.contour(X, Y, Z, 10, offset=-1, lw=3, colors="k", linestyles="solid", alpha=0.5)
See this example for more:
http://matplotlib.org/examples/mplot3d/contour3d_demo3.html
And the docs here:
http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#contour-plots
offset: If specified plot a projection of the contour lines on this position in plane normal to zdir
Note, zdir = 'z' by default, but you can project in the x or y direction be setting the zdir accordingly.

matplotlib's colormap

I'm new to python and after installing it I've accomplished to plot my 3d data using matplotlib. Sadly the only thing I don't know how to get done is the color part. My image just shows the surface but doesn't use the color bar at all. Here is my code.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
from matplotlib.mlab import griddata
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
data = np.genfromtxt('Uizq.txt')
x = data[:,0]
y = data[:,1]
z = data[:,2]
xi = np.linspace(min(x), max(x))
yi = np.linspace(min(y), max(y))
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('U')
X, Y = np.meshgrid(xi, yi)
Z = griddata(x, y, z, xi, yi)
ax.set_zlim3d(np.min(Z), np.max(Z))
surf = ax.plot_surface(X, Y, Z, rstride=2, cstride=2, cmap=cm.jet,
linewidth=0.5, antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
you can obviously see that it is all blue, and I want to relate the color with "U" using the full cm.jet spectrum. This might be a very noob question, so sorry if you rolled your eyes.
Add the line
surf.set_clim([np.min(Z),np.max(Z)])
before you add the color bar.
It seems that the 3D plotting does not take into account the masking, so you are including NaN in the data, which confuses the automatic color limits.

Categories

Resources