简体   繁体   中英

How to plot scatter plot points on a colorbar?

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:

cbar0

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:

cbar1

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:

cbar2

With y:

Plot:

cbar3

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM