Как построить точечные точки рассеяния на цветовой панели? - PullRequest
1 голос
/ 05 февраля 2020

У меня есть простой график поверхности для функции оценки, который я строю в 3d с помощью

surf = ax.plot_surface(xx, yy, zz)

для осей x, y и z.

Используя объект прибоя, я также создайте цветную полосу

fig.colorbar(surf, shrink=0.5, aspect=5)

Затем я рисую точки на графике поверхности с помощью простой функции разброса

plot = ax.scatter(xs=[], ys=[], zs=[], c="black", alpha=1.0, zorder=50)

Это хорошо работает, я получаю хороший график поверхности с точками, нарисованными на Это. Я также получаю цветную полосу рядом с ней, показывающую градиент функции оценки.

Теперь я хочу нарисовать те же точки, что и я, с разбросом, но на цветной полосе. Таким образом, я хочу показать, насколько близки точки к желаемому значению. Я некоторое время искал документацию, но я новичок в matplotlib, поэтому не знаю, как можно манипулировать цветовой шкалой, чтобы она показывала точки. Если бы вы могли помочь мне просто нарисовать одну точку в произвольном месте на цветовой панели, я бы взял ее оттуда.

Ответы [ 2 ]

0 голосов
/ 06 февраля 2020

Да, можно строить на colorbar. Вам просто нужно изменить масштаб ваших данных.

Давайте сгенерируем некоторую поверхность с точками на ней, я собираюсь mimi c оптимизатор (случайный оптимизатор) и нарисуйте его шаги на поверхности:

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)

Сюжет:

cbar0

Нам нужен ax, чтобы построить что-то на нем. К счастью, colorbar имеет эту функцию:

print('ax' in dir(cb))

Out:

True

Но у него есть свои пределы y и x, как они вычисляются, это все еще волхвы c для меня, но, кажется, они определяются значениями z min и max, мы можем посмотреть на них, используя get_xlim() и get_ylim() методы:

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

Итак, если вы хотите разместить amth на цветовой шкале, вам нужно изменить его масштаб. мы будем использовать эту функцию:

def rescale(arr, min_=0, max_=1):
    scale = (max_ - min_) / (arr.max() - arr.min())
    arr = arr * scale + min_ - arr.min() * scale
    return arr

Теперь мы можем сделать черчение на цветовой панели. Давайте сначала построим порядок итераций:

...
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()

Участок:

cbar1

Вы также можете построить график Значения x и y на cbar, вам просто необходимо изменить его масштаб. Вот значения x по оси x и z по оси y 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()

График:

cbar2

С y:

Сюжет:

cbar3

0 голосов
/ 06 февраля 2020

Не уверен, что это то, что вы ищете.

Я адаптировал пример на этого урока и выбрал 20 случайных точек. Эти точки разбросаны по поверхности. И их z-значение нанесено на цветную полосу. Чтобы не иметь все значения в прямой линии, для позиционирования в цветовой шкале используется рандомизированная x-координата.

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()

example plot

...