Search code examples
pythonmatplotlibpolar-coordinates

Polar grid on left hand side of rectangular plot


I am trying to reproduce a plot like this:

So the requirements are actually that the grid (that is to be present just on the left side) behaves just like a grid, that is, if we zoom in and out, it is always there present and not dependent on specific x-y limits for the actual data.

Unfortunately there is no diagonal version of axhline/axvline (open issue here) so I was thinking about using the grid from polar plots.

So for that I have two problems:

  1. This answer shows how to overlay a polar axis on top of a rectangular one, but it does not match the origins and x-y values. How can I do that?

  2. I also tried the suggestion from this answer for having polar plots using ax.set_thetamin/max but I get an AttributeError: 'AxesSubplot' object has no attribute 'set_thetamin' How can I use these functions? This is the code I used to try to add a polar grid to an already existing rectangular plot on ax axis:

    ax_polar = fig.add_axes(ax, polar=True, frameon=False)
    ax_polar.set_thetamin(90)
    ax_polar.set_thetamax(270)
    ax_polar.grid(True)
    

I was hoping I could get some help from you guys. Thanks!


Solution

  • The mpl_toolkits.axisartist has the option to plot a plot similar to the desired one. The following is a slightly modified version of the example from the mpl_toolkits.axisartist tutorial:

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.cbook as cbook
    from mpl_toolkits.axisartist import SubplotHost, ParasiteAxesAuxTrans
    from mpl_toolkits.axisartist.grid_helper_curvelinear import GridHelperCurveLinear
    import mpl_toolkits.axisartist.angle_helper as angle_helper
    from matplotlib.projections import PolarAxes
    from matplotlib.transforms import Affine2D
    
    # PolarAxes.PolarTransform takes radian. However, we want our coordinate
    # system in degree
    tr = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform()
    # polar projection, which involves cycle, and also has limits in
    # its coordinates, needs a special method to find the extremes
    # (min, max of the coordinate within the view).
    
    # 20, 20 : number of sampling points along x, y direction
    extreme_finder = angle_helper.ExtremeFinderCycle(20, 20,
                                                     lon_cycle=360,
                                                     lat_cycle=None,
                                                     lon_minmax=None,
                                                     lat_minmax=(0, np.inf),)
    
    grid_locator1 = angle_helper.LocatorDMS(36)
    tick_formatter1 = angle_helper.FormatterDMS()
    grid_helper = GridHelperCurveLinear(tr,
                                        extreme_finder=extreme_finder,
                                        grid_locator1=grid_locator1,
                                        tick_formatter1=tick_formatter1
                                        )
    
    fig = plt.figure(1, figsize=(7, 4))
    fig.clf()
    ax = SubplotHost(fig, 1, 1, 1, grid_helper=grid_helper)
    
    # make ticklabels of right invisible, and top axis visible.
    ax.axis["right"].major_ticklabels.set_visible(False)
    ax.axis["right"].major_ticks.set_visible(False)
    ax.axis["top"].major_ticklabels.set_visible(True)
    
    # let left axis shows ticklabels for 1st coordinate (angle)
    ax.axis["left"].get_helper().nth_coord_ticks = 0
    # let bottom axis shows ticklabels for 2nd coordinate (radius)
    ax.axis["bottom"].get_helper().nth_coord_ticks = 1
    
    fig.add_subplot(ax)
    
    ## A parasite axes with given transform
    ## This is the axes to plot the data to.
    ax2 = ParasiteAxesAuxTrans(ax, tr)
    ## note that ax2.transData == tr + ax1.transData
    ## Anything you draw in ax2 will match the ticks and grids of ax1.
    ax.parasites.append(ax2)
    intp = cbook.simple_linear_interpolation
    
    ax2.plot(intp(np.array([150, 230]), 50),
             intp(np.array([9., 3]), 50),
             linewidth=2.0)
    
    
    ax.set_aspect(1.)
    ax.set_xlim(-12, 1)
    ax.set_ylim(-5, 5)
    ax.grid(True, zorder=0)
    wp = plt.Rectangle((0,-5),width=1,height=10, facecolor="w", edgecolor="none")
    ax.add_patch(wp)
    ax.axvline(0, color="grey", lw=1)
    plt.show()
    

    enter image description here