Search code examples
pythonmatplotlibmatplotlib-animation

Interact with a Python plot using keys instead of dragging


Using Matplotlib I made a 3D simulation of some moving objects. Currently, it is defaulted in a way such that if I drag my cursor across the screen I can move the plot around and see the objects in different perspectives. I was wondering if there is a way to change this such that instead of dragging, I can use the arrow keys on my keyboard to move the plot around in 3D?


Solution

  • You can use key events to detect a key press and react accordingly.

    The viewpoint of the 3D plot is given by ax.elev and ax.azim so it's just a matter of modifying those properties.

    That being said, you will have to be careful not to clash with existing keyboard shortcuts (or redefine those if they interfere with the keys you were thinking of using).

    Here is an example that shows how to use the Shift-> and Shift<- keys to turn the plot around

    from matplotlib import cbook
    from matplotlib import cm
    from matplotlib.colors import LightSource
    import matplotlib.pyplot as plt
    import numpy as np
    
    dem = cbook.get_sample_data('jacksboro_fault_dem.npz', np_load=True)
    z = dem['elevation']
    nrows, ncols = z.shape
    x = np.linspace(dem['xmin'], dem['xmax'], ncols)
    y = np.linspace(dem['ymin'], dem['ymax'], nrows)
    x, y = np.meshgrid(x, y)
    
    region = np.s_[5:50, 5:50]
    x, y, z = x[region], y[region], z[region]
    
    fig, ax = plt.subplots(subplot_kw=dict(projection='3d'))
    
    ls = LightSource(270, 45)
    # To use a custom hillshading mode, override the built-in shading and pass
    # in the rgb colors of the shaded surface calculated from "shade".
    rgb = ls.shade(z, cmap=cm.gist_earth, vert_exag=0.1, blend_mode='soft')
    surf = ax.plot_surface(x, y, z, rstride=1, cstride=1, facecolors=rgb,
                           linewidth=0, antialiased=False, shade=False)
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_zticks([])
    
    
    def on_press(event):
        print(event.key)
        if event.key == 'shift+right':
            ax.azim+=10
        if event.key == 'shift+left':
            ax.azim-=10
        fig.canvas.draw_idle()
    
    fig.canvas.mpl_connect('key_press_event', on_press)