ax.plot_surface перезаписывает последующий ax.scatter - PullRequest
0 голосов
/ 12 июля 2020

Я пытаюсь построить изображение поверхности, которое пересекает облако точек. Вот что я надеюсь получить в качестве результата: enter image description here Here is what I am getting: enter image description here As you can see, the surface seems to overwrite the scatter plot. I have tried dividing the scatter plot in two around the plane, like so:

break_idx = np.searchsorted(ts, img_ts)

ax.scatter(xs[0:break_idx], ts[0:break_idx], ys[0:break_idx], zdir='z',
   c=colors[0:break_idx], facecolors=colors[0:break_idx])

ax.plot_surface(y, img_ts, x, rstride=5, cstride=5, facecolors=img, alpha=1)

ax.scatter(xs[break_idx:-1], ts[break_idx:-1], ys[break_idx:-1], zdir='z',
   c=colors[break_idx:-1], facecolors=colors[break_idx:-1])

However this has not worked for me. Any ideas what might be going on?

+++ EDIT +++

Thanks to @JohanC for his suggestions, unfortunately it resulted in the same issue, visualized here in GIF format:

enter image description here

Judging by my results and the comments, this is just a bug/limitation of matplotlibs 3D plotting abilities. Ohwell, time to learn to use mayavi...

A working minimal example using mayavi can be found здесь , хотя причина его нахождения в stackoverflow заключается в том, что я сталкиваюсь с аналогичными проблемами.

1 Ответ

2 голосов
/ 12 июля 2020

Может быть, ваши массивы ts, xs, ys и colors плохо отсортированы при увеличении ts? Кроме того, np.searchsorted возвращает массив, поэтому вы не можете напрямую использовать его результат как [0:break_idx]. Вероятно, вы могли бы взять первый элемент возвращенного массива: break_idx = np.searchsorted(ts, img_ts)[0].

Как указано в комментариях, matplotlib не поддерживает полное 3D, а Mayavi - одна из обычных рекомендаций если вам нужно красивое 3D-сокрытие.

Тем не менее, в вашем примере, если вы не перемещаете точку обзора за плоскость, вы можете сначала нарисовать точки позади плоскости, затем плоскость, а затем точки в фронт. Это то, что пытается сделать код в вопросе.

Чтобы выбрать точки перед плоскостью, более простое решение - просто создать список индексов: front_indices = ts < img_ts. Если это дает неправильный результат, просто замените < на >. Используйте [front_indices], чтобы выбрать значения только спереди, и [~front_indices], чтобы выбрать значения на другой стороне плоскости.

front_indices = ts < img_ts  # supposing ts is a numpy array, and img_ts is one special value

ax.scatter(xs[~front_indices], ts[~front_indices], ys[~front_indices], zdir='z',
   c=colors[~front_indices])

ax.plot_surface(y, img_ts, x, rstride=5, cstride=5, facecolors=img, alpha=1)

ax.scatter(xs[front_indices], ts[front_indices], ys[front_indices], zdir='z',
   c=colors[front_indices])

Вот более полный пример:

import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from mpl_toolkits.mplot3d import Axes3D
import mpl_toolkits.mplot3d.art3d as art3d
import numpy as np

N = 10000
xs = np.random.uniform(4, 6, N)
ys = np.random.uniform(4, 6, N)
ts = np.random.uniform(1, 9, N)
colors = np.random.uniform(0, 1, N)
img_ts = 5

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

front_indices = ts < img_ts

ax.scatter(xs[~front_indices], ts[~front_indices], ys[~front_indices], zdir='z',
           c=colors[~front_indices], cmap='seismic', s=1)

# Draw a circle on the y=5 'wall'
p = Circle((5, 5), 4)
ax.add_patch(p)
art3d.pathpatch_2d_to_3d(p, z=img_ts, zdir="y")

ax.scatter(xs[front_indices], ts[front_indices], ys[front_indices], zdir='z',
           c=colors[front_indices], cmap='seismic', s=1)

ax.set_xlim(0, 10)
ax.set_ylim(0, 10)
ax.set_zlim(0, 10)
ax.set_xlabel('x')
ax.set_ylabel('t')
ax.set_zlabel('y')

ax.view_init(elev=15, azim=33)
plt.show()

пример сюжета

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...