2013-02-23 29 views
13

Tôi đang làm một số ô bề mặt 3D bằng cách sử dụng Matplotlib trong Python và đã nhận thấy một hiện tượng khó chịu. Tùy thuộc vào cách tôi đặt điểm quan sát (vị trí máy ảnh), trục dọc (z) di chuyển giữa bên trái và bên phải. Dưới đây là hai ví dụ: Example 1, Axis left, Example 2, Axis right. Ví dụ đầu tiên có ax.view_init (25, -135) trong khi thứ hai có ax.view_init (25, -45).Thay đổi vị trí trục dọc (z) của ô 3D (Matplotlib)?

Tôi muốn giữ các quan điểm giống nhau (cách tốt nhất để xem dữ liệu). Có cách nào để buộc trục sang một bên hay bên kia không?

Cảm ơn!

Trả lời

9

Tôi cần một cái gì đó tương tự: vẽ zaxis ở cả hai bên. Nhờ có câu trả lời bởi @crayzeewulf tôi đến sau workaround (đối với trái, righ, hoặc cả hai bên):

enter image description here

cốt truyện đầu tiên 3d của bạn khi bạn cần, sau đó trước khi bạn gọi show() quấn Axes3D với một Lớp trình bao bọc chỉ đơn giản là ghi đè phương thức draw().

Các cuộc gọi Lớp bao bọc chỉ đơn giản là đặt khả năng hiển thị của một số đối tượng thành False, nó tự vẽ và cuối cùng vẽ zaxis bằng PLANES đã sửa đổi. Lớp Wrapper này cho phép bạn vẽ zaxis ở bên trái, trên rigth hoặc cả hai bên.

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

Bạn có thể cập nhật ví dụ bằng một bề mặt thực tế không? Tôi gặp khó khăn khi làm việc này. – pyCthon

+1

Đây là những gì tôi nhận được khi tôi thêm một âm mưu sau khi bạn đặt 'fig' http://imgur.com/VJLTTTH – pyCthon

+1

@pyCthon: xem bản cập nhật của ví dụ. Tôi đã thêm một chức năng đơn giản để vẽ một bề mặt có mã mượn từ http://matplotlib.org/examples/mplot3d/surface3d_demo.html. – wolfrevo

5

Như được nêu trong một nhận xét dưới đây bởi OP, phương pháp được đề xuất bên dưới không cung cấp câu trả lời đầy đủ cho câu hỏi gốc.

Như đã đề cập trong this lưu ý, có rất nhiều giá trị được mã hóa cứng trong axis3d khiến bạn khó tùy chỉnh hành vi của nó. Vì vậy, tôi không nghĩ rằng có một cách tốt để làm điều này trong API hiện tại. Bạn có thể "hack" nó bằng cách sửa đổi _PLANES tham số của zaxis như hình dưới đây:

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) 

Bây giờ trục z sẽ luôn luôn được ở phía bên trái của hình không có vấn đề làm thế nào bạn xoay hình (miễn theo hướng dương-z hướng lên). Trục x và trục y sẽ tiếp tục lật. Bạn có thể chơi với _PLANES và có thể có được hành vi mong muốn cho tất cả các trục nhưng điều này có khả năng xảy ra trong các phiên bản tương lai của matplotlib.

+0

Cảm ơn bạn rất nhiều crayzeewulf. Đó là một chút lạ, tôi đã có thể làm cho nó hoạt động, tuy nhiên, nó không hoạt động như mong đợi. Khi tôi chạy tập lệnh mà không sửa đổi, trục z ở bên trái. Khi tôi thực hiện sửa đổi của bạn, trục z ở bên trái. Tôi đã thay đổi thứ tự của ax.zaxis._PLANES = (tmp [0], tmp [1], tmp [2], tmp [3], tmp [4], tmp [5]) và nó di chuyển trục sang bên phải bên (những gì tôi muốn). Có vẻ như tôi chỉ cần đặt lại các giá trị giống nhau của ax.zaxis._PLANES nhưng nó đạt được các kết quả khác nhau. Dù sao, cảm ơn một lần nữa, đây là * chính xác * những gì tôi muốn, tôi đánh giá cao nó. – Blink

+0

Woops, tôi đã nhầm. Để thay đổi trục tôi đã sử dụng ax.zaxis._PLANES = (tmp [1], tmp [2], tmp [3], tmp [4], tmp [5], tmp [0]). Điều này đã làm việc; tuy nhiên, tôi chỉ nhận ra rằng nó cũng thay đổi đường ngang/dọc trên mặt phẳng. Bạn có thể thấy [ở đây] (http://i.imagebanana.com/img/vpcs6af2/Selection_005.png) rằng các mặt phẳng trục quay không có đường ngang nhưng các mặt trước thì có. Có trang web nào mô tả cách ._PLANES được xác định không? Tôi đã cố gắng đưa khoảng 50 kết hợp khác nhau vào nó để tìm ra nhưng tôi đã không thể có được kết quả tôi muốn (trục thẳng đứng ở phía bên phải và dòng horz trên lưng) – Blink

+1

Theo dõi bình luận cuối cùng của tôi.Tôi vừa hoàn thành một thử nghiệm vũ lực chạy qua tất cả các hoán vị [0,1,2,3,4,5] cho tmp_planes, tổng cộng 720 sắp xếp khác nhau. ** Không có ** trong số đó dẫn đến con số thích hợp. Tôi đoán tôi có thể bị mắc kẹt với vấn đề này. – Blink

Các vấn đề liên quan