2013-02-23 2 views
13

Я делаю некоторые 3D-графики, используя Matplotlib в Python, и заметил раздражающее явление. В зависимости от того, как я устанавливаю точку обзора (местоположение камеры), вертикальная ось (z) перемещается между левой и правой сторонами. Вот два примера: Example 1, Axis left, Example 2, Axis right. Первый пример имеет ax.view_init (25, -135), а второй - ax.view_init (25, -45).Изменение положения вертикальной (z) оси 3D-графика (Matplotlib)?

Я хотел бы оставить точки обзора одинаковыми (лучший способ просмотра данных). Есть ли способ заставить ось в одну сторону или другую?

Спасибо!

ответ

9

Мне было нужно нечто похожее: рисование zaxis с обеих сторон. Благодаря ответ по @crayzeewulf я пришел к следующим обходному пути (для левой стороны, RIGH, или обе стороны):

enter image description here

Первого участка вашего 3d, как вам нужно, то перед вызовом show() обернуть Axes3D с микросхемой Класс Wrapper, который просто переопределяет метод draw().

Классы класса Wrapper просто устанавливают видимость некоторых функций в False, он рисует сам и, наконец, рисует zaxis с модифицированными PLANES. Этот класс Wrapper позволяет рисовать zaxis слева, на уровне или с обеих сторон.

import matplotlib 
matplotlib.use('QT4Agg') 
import matplotlib.pyplot as plt 
from mpl_toolkits.mplot3d import axes3d 

class MyAxes3D(axes3d.Axes3D): 

    def __init__(self, baseObject, sides_to_draw): 
     self.__class__ = type(baseObject.__class__.__name__, 
           (self.__class__, baseObject.__class__), 
           {}) 
     self.__dict__ = baseObject.__dict__ 
     self.sides_to_draw = list(sides_to_draw) 
     self.mouse_init() 

    def set_some_features_visibility(self, visible): 
     for t in self.w_zaxis.get_ticklines() + self.w_zaxis.get_ticklabels(): 
      t.set_visible(visible) 
     self.w_zaxis.line.set_visible(visible) 
     self.w_zaxis.pane.set_visible(visible) 
     self.w_zaxis.label.set_visible(visible) 

    def draw(self, renderer): 
     # set visibility of some features False 
     self.set_some_features_visibility(False) 
     # draw the axes 
     super(MyAxes3D, self).draw(renderer) 
     # set visibility of some features True. 
     # This could be adapted to set your features to desired visibility, 
     # e.g. storing the previous values and restoring the values 
     self.set_some_features_visibility(True) 

     zaxis = self.zaxis 
     draw_grid_old = zaxis.axes._draw_grid 
     # disable draw grid 
     zaxis.axes._draw_grid = False 

     tmp_planes = zaxis._PLANES 

     if 'l' in self.sides_to_draw : 
      # draw zaxis on the left side 
      zaxis._PLANES = (tmp_planes[2], tmp_planes[3], 
          tmp_planes[0], tmp_planes[1], 
          tmp_planes[4], tmp_planes[5]) 
      zaxis.draw(renderer) 
     if 'r' in self.sides_to_draw : 
      # draw zaxis on the right side 
      zaxis._PLANES = (tmp_planes[3], tmp_planes[2], 
          tmp_planes[1], tmp_planes[0], 
          tmp_planes[4], tmp_planes[5]) 
      zaxis.draw(renderer) 

     zaxis._PLANES = tmp_planes 

     # disable draw grid 
     zaxis.axes._draw_grid = draw_grid_old 

def example_surface(ax): 
    """ draw an example surface. code borrowed from http://matplotlib.org/examples/mplot3d/surface3d_demo.html """ 
    from matplotlib import cm 
    import numpy as np 
    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, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False) 

if __name__ == '__main__': 
    fig = plt.figure(figsize=(15, 5)) 
    ax = fig.add_subplot(131, projection='3d') 
    ax.set_title('z-axis left side') 
    ax = fig.add_axes(MyAxes3D(ax, 'l')) 
    example_surface(ax) # draw an example surface 
    ax = fig.add_subplot(132, projection='3d') 
    ax.set_title('z-axis both sides') 
    ax = fig.add_axes(MyAxes3D(ax, 'lr')) 
    example_surface(ax) # draw an example surface 
    ax = fig.add_subplot(133, projection='3d') 
    ax.set_title('z-axis right side') 
    ax = fig.add_axes(MyAxes3D(ax, 'r')) 
    example_surface(ax) # draw an example surface 
    plt.show() 
+0

Не могли бы вы обновить пример с реальной поверхностью? У меня проблемы с работой. – pyCthon

+1

Вот что я получаю, когда добавляю сюжет после того, как вы установили 'fig' http://imgur.com/VJLTTTH – pyCthon

+1

@pyCthon: см. Мое обновление примера. Я просто добавил функцию рисования поверхности с кодом, заимствованным из http://matplotlib.org/examples/mplot3d/surface3d_demo.html. – wolfrevo

5

Как указано в комментарии ниже ОП, предложенный ниже метод не дал адекватного ответа на исходный вопрос.

Как указано в примечании this, в axis3d есть много жестко заданных значений, которые затрудняют настройку его поведения. Итак, я не думаю, что есть хороший способ сделать это в текущем API. Вы можете «взломать» его, изменяя параметр zaxis_PLANES, как показано ниже:

tmp_planes = ax.zaxis._PLANES 
ax.zaxis._PLANES = (tmp_planes[2], tmp_planes[3], 
        tmp_planes[0], tmp_planes[1], 
        tmp_planes[4], tmp_planes[5]) 
view_1 = (25, -135) 
view_2 = (25, -45) 
init_view = view_2 
ax.view_init(*init_view) 

Теперь ось г всегда будет находиться на левой стороне фигуры, независимо от того, как вы повернете фигуру (до тех пор, когда направление положительного z направляется вверх). Однако ось x и ось y будут продолжать переворачивать. Вы можете играть с _PLANES и, возможно, сможете получить желаемое поведение для всех осей, но это, вероятно, сломается в будущих версиях matplotlib.

+0

Большое спасибо crayzeewulf. Это немного странно, я смог заставить его работать, однако он не ведет себя так, как ожидалось. Когда я запускаю скрипт без вашей модификации, ось z находится слева. Когда я внедрил вашу модификацию, ось z осталась слева. Я изменил порядок ax.zaxis._PLANES = (tmp [0], tmp [1], tmp [2], tmp [3], tmp [4], tmp [5]), и он переместил ось вправо (что я хотел). Кажется, что я просто сбросил те же значения ax.zaxis._PLANES, но добился разных результатов. В любом случае, еще раз спасибо, это точно, что я хотел, я ценю это. – Blink

+0

Вордс, я ошибся. Для изменения оси я использовал ax.zaxis._PLANES = (tmp [1], tmp [2], tmp [3], tmp [4], tmp [5], tmp [0]). Это сработало; однако я просто понял, что он также сдвигает горизонтальные/вертикальные линии на плоскостях. Вы можете увидеть [здесь] (http://i.imagebanana.com/img/vpcs6af2/Selection_005.png), что плоскости задней оси не имеют горизонтальных линий, но передние. Существует ли какой-либо сайт, описывающий, как .PLANES определен? Я попытался использовать в нем около 50 различных комбинаций, но я не смог получить результат, который я хочу (вертикальная ось на правой стороне и горизонтальные строки на обратной стороне) – Blink

+1

Следуя моему последнему комментарию.Я только что завершил проверку грубой силы, протекающую через все перестановки [0,1,2,3,4,5] для tmp_planes, всего 720 различных аранжировок. ** Ни один ** из них не привел к правильной цифре. Наверное, я просто застрял с проблемой. – Blink

Смежные вопросы