I have a simple surface plot for an evaluation function that I plot in 3d by using
surf = ax.plot_surface(xx, yy, zz)
for the x, y and z axes.
Using the surf object, I also create a colorbar
fig.colorbar(surf, shrink=0.5, aspect=5)
I then draw the points on the surface plot with a simple scatter function
plot = ax.scatter(xs=[], ys=[], zs=[], c="black", alpha=1.0, zorder=50)
This works well, I get a nice surface plot with points drawn on it. I also get a color bar next to it showing the evaluation function gradient.
I now want to plot the same points that I plot with scatter, but on the color bar. This way, I want to show how close the points are to the desired value. I have searched the documentation for a while, but I am quite new to matplotlib so I do not know how the colorbar can be manipulated so that it shows the points. If you could help me just draw a single point at a ranndom location on the colorbar, then I would take it from there.
Not sure whether this is what you're looking for.
I adapted the example at this tutorial and selected 20 random points. Those points are scattered on the surface. And their z-value is plotted on the colorbar. To not have all values on a straigth line, a randomized x-coordinate is used for positioning in the colorbar.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
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)
surf = ax.plot_surface(X, Y, Z, cmap=plt.cm.coolwarm,
linewidth=0, antialiased=True)
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
cbar = fig.colorbar(surf, shrink=0.8, aspect=8)
num_selected = 20
selection = (np.random.randint(0, 40, num_selected), np.random.randint(0, 40, num_selected))
plot = ax.scatter(xs=X[selection], ys=Y[selection], zs=Z[selection], c="black", alpha=1.0, zorder=50)
cbar.ax.scatter(x=np.random.uniform(*cbar.ax.set_xlim(), num_selected), y=Z[selection], c='k', s=5)
plt.show()
Yes, it is possible to plot on colorbar
. You just need to rescale your data.
Let's generate some surface with points on it, I am going to mimic optimizer (random optimizer) and plot its steps on the surface:
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import axes3d
def zfun(x, y):
"""For computing Z"""
return x * np.cos(x) - y * np.cos(y)
# reproducibility first
np.random.seed(2020)
# Get some data
# define Space
X = np.linspace(-5, 5, 20)
Y = np.linspace(-5, 5, 20)
X, Y = np.meshgrid(X, Y)
Z = zfun(X, Y)
# Prepare fig
fw, fh = 10, 5
view = (65, 30)
fig = plt.figure(figsize=(fw, fh))
ax = fig.add_subplot(111, projection='3d')
ax.view_init(view[0], view[-1])
# Plot surface
surf = ax.plot_surface(X, Y, Z, cmap='jet', zorder=-1)
# Here is our test points: optimizer steps a kind of :)
x = np.random.choice(np.arange(-3, 3, 0.25), 7)
y = np.random.choice(np.arange(-5, 5, 0.25), 7)
z = zfun(x, y)
# I use plot3D, I think in 3D space it does better than scatter
# And you can connect all the dots to get a line
ax.plot3D(x, y, z, 'o-', c='k', markersize=5, zorder=3)
# Put a starting point
ax.plot3D([x[0]], [y[0]], [z[0]], 'o', c='r', markersize=5, zorder=3)
# Put the end
ax.plot3D([x[-1]], [y[-1]], [z[-1]], 'o', c='b', markersize=5, zorder=3)
# get some bars
cb = fig.colorbar(surf)
Plot:
We need an ax
to plot smth on it. Thankfully colorbar
has this feature:
print('ax' in dir(cb))
Out:
True
But it has its own y and x limits, how they are computed it's still a magic to me, but seems they are defined by z min and max values, we can look at them using get_xlim()
and get_ylim()
methods:
print('cbar xlimits:', cb.ax.get_xlim())
print('cbar ylimits:', cb.ax.get_ylim())
print('Z min, max:', Z.min(), Z.max())
Out:
cbar xlimits: (-6.095315696318178, 6.095315696318178)
cbar ylimits: (-6.095315696318178, 6.095315696318178)
Z min, max: -6.5766626168117845 6.5766626168117845
So, if you want to put amth on colorbar you need to rescale it. we will use this function:
def rescale(arr, min_=0, max_=1):
scale = (max_ - min_) / (arr.max() - arr.min())
arr = arr * scale + min_ - arr.min() * scale
return arr
Now we can do plotting on colorbar. Let's first plot an order of iterations:
...
cb = fig.colorbar(surf)
# we need this line now
cb.ax.set_aspect('auto')
# Put some labels
cb.ax.set_xlabel('iteration ->')
cb.ax.set_ylabel('z')
# get vals for rescale function
min_, max_ = cb.ax.get_xlim()
# generate and iter sequence [0, 1, 2, 3...]
iters = np.arange(len(z))
# rescale it
iters = rescale(iters, min_, max_)
# Now plot it!
cb.ax.scatter(iters, z, s=50, c='k', edgecolor='w') # add points
cb.ax.plot(iters, z, '--', c='k') # add line
cb.ax.plot(iters[0], z[0], 'o', c='r', markersize=5, label='start')
cb.ax.plot(iters[-1], z[-1], 'o', c='b', markersize=5, label='end')
cb.ax.legend()
Plot:
You can also plot x and y values on cbar, you jus need to rescale it. Here is x values on x-axis, and z on y-axis of the cbar:
...
cb = fig.colorbar(surf)
# we need this line now
cb.ax.set_aspect('auto')
# Put some labels
cb.ax.set_xlabel('x')
cb.ax.set_ylabel('z')
# get vals for rescale function
min_, max_ = cb.ax.get_xlim()
# rescale
x = rescale(x, min_, max_)
cb.ax.scatter(x, z, s=50, c='k', edgecolor='w') # add points
cb.ax.plot(x, z, '--', c='k') # add line
cb.ax.plot(x[0], z[0], 'o', c='r', markersize=5, label='start')
cb.ax.plot(x[-1], z[-1], 'o', c='b', markersize=5, label='end')
cb.ax.legend()
Plot:
With y:
Plot:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.