Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing position of vertical (z) axis of 3D plot (Matplotlib)?

I'm doing some 3D surface plots using Matplotlib in Python and have noticed an annoying phenomenon. Depending on how I set the viewpoint (camera location), the vertical (z) axis moves between the left and right side. Here are two examples: Example 1, Axis left, Example 2, Axis right. The first example has ax.view_init(25,-135) while the second has ax.view_init(25,-45).

I would like to keep the viewpoints the same (best way to view the data). Is there any way to force the axis to one side or the other?

like image 391
Blink Avatar asked Feb 23 '13 15:02

Blink


People also ask

How do you change the axis of a plot in Matplotlib?

MatPlotLib with Python To change the range of X and Y axes, we can use xlim() and ylim() methods.

How do I move axis in Matplotlib?

MatPlotLib with Python To shift the Y-axis ticks from left to right, use ax. yaxis. tick_right() where ax is axis created using add_subplot(xyz) method.

How do I change the axis position in Python?

You can use the get_position and set_position methods of the axes. You might also want to take a look at GridSpec if you haven't already.

How do I change the Y-axis interval in Matplotlib?

The ylim() function is used to set or to get the y-axis limits or we can say y-axis range. By default, matplotlib automatically chooses the range of y-axis limits to plot the data on the graph area. But if we want to change that range of the current axes then we can use the ylim() function.


1 Answers

I needed something similar: drawing the zaxis on both sides. Thanks to the answer by @crayzeewulf I came to following workaround (for left, righ, or both sides):

enter image description here

First plot your 3d as you need, then before you call show() wrap the Axes3D with a Wrapper class that simply overrides the draw() method.

The Wrapper Class calls simply sets the visibility of some features to False, it draws itself and finally draws the zaxis with modified PLANES. This Wrapper Class allows you to draw the zaxis on the left, on the rigth or on both sides.

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()
like image 77
wolfrevo Avatar answered Sep 24 '22 11:09

wolfrevo