Maik
Maik

Reputation: 33

How to change ticklabels within figure created with axisartist

I tried to change the ticklabels in my creted figure. But I don't get it.

Ok, my code (se below) is from someone else, I modified it. I don't understand all of it. So I tried a few things. My goal ist to change the labels on the r-axis to something else. I have to rescale it, beacuse this kind of code is the best result for the half polar plot, but it is currently somehow limited. If I could change the lables of the r-axis it will be perfect for me.

In the documentation of axisartist they write that it should work like normal mpl (ax.set_xticks([1,2,3])).

What I'm doing wrong?

from __future__ import division
from __future__ import print_function

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.transforms import Affine2D
from matplotlib.projections import PolarAxes
from mpl_toolkits.axisartist import angle_helper
from mpl_toolkits.axisartist.grid_finder import MaxNLocator
from mpl_toolkits.axisartist.floating_axes import GridHelperCurveLinear, FloatingSubplot

def fractional_polar_axes(f, thlim=(0, 180), rlim=(0, 1), step=(30, 0.2),
                      thlabel='theta', rlabel='r', ticklabels=True, theta_offset=0):
"""Return polar axes that adhere to desired theta (in deg) and r limits. steps for theta
and r are really just hints for the locators."""
th0, th1 = thlim # deg
r0, r1 = rlim
thstep, rstep = step

tr_rotate = Affine2D().translate(theta_offset, 0)
# scale degrees to radians:
tr_scale = Affine2D().scale(np.pi/180., 1.)
#pa = axes(polar="true") # Create a polar axis
pa = PolarAxes
tr = tr_rotate + tr_scale + pa.PolarTransform()
theta_grid_locator = angle_helper.LocatorDMS((th1-th0)//thstep)
r_grid_locator = MaxNLocator((r1-r0)//rstep)
theta_tick_formatter = angle_helper.FormatterDMS()

grid_helper = GridHelperCurveLinear(tr,
                                    extremes=(th0, th1, r0, r1),
                                    grid_locator1=theta_grid_locator,
                                    grid_locator2=r_grid_locator,
                                    tick_formatter1=theta_tick_formatter,
                                    tick_formatter2=None)

    a = FloatingSubplot(f, 111, grid_helper=grid_helper)
    f.add_subplot(a)
    # adjust x axis (theta):
    a.axis["bottom"].set_visible(False)
    a.axis["top"].set_axis_direction("bottom") # tick direction
    a.axis["top"].toggle(ticklabels=ticklabels, label=bool(thlabel))
    a.axis["top"].major_ticklabels.set_axis_direction("top")
    a.axis["top"].label.set_axis_direction("top")
    a.axis["top"].major_ticklabels.set_pad(10)

    # adjust y axis (r):
    a.axis["left"].set_axis_direction("bottom") # tick direction
    a.axis["right"].set_axis_direction("top") # tick direction
    a.axis["left"].toggle(ticklabels=ticklabels, label=bool(rlabel))

    # add labels:
    a.axis["top"].label.set_text(thlabel)
    a.axis["left"].label.set_text(rlabel)

    # create a parasite axes whose transData is theta, r:
    auxa = a.get_aux_axes(tr)
    # make aux_ax to have a clip path as in a?:
    auxa.patch = a.patch 
    # this has a side effect that the patch is drawn twice, and possibly over some other
    # artists. So, we decrease the zorder a bit to prevent this:
    a.patch.zorder = -2

    # add sector lines for both dimensions:
    thticks = grid_helper.grid_info['lon_info'][0]
    rticks = grid_helper.grid_info['lat_info'][0]
    for th in thticks[1:-1]: # all but the first and last
        auxa.plot([th, th], [r0, r1], ':', c='grey', zorder=-1, lw=0.5)
    for ri, r in enumerate(rticks):
        # plot first r line as axes border in solid black only if it  isn't at r=0
        if ri == 0 and r != 0:
            ls, lw, color = 'solid', 1, 'black'
        else:
            ls, lw, color = 'dashed', 0.5, 'grey'
        # From http://stackoverflow.com/a/19828753/2020363
        auxa.add_artist(plt.Circle([0, 0], radius=r, ls=ls, lw=lw, color=color, fill=False,
                    transform=auxa.transData._b, zorder=-1))

    return auxa


if __name__ == '__main__':
    f1 = plt.figure(facecolor='white', figsize=(16/2.54, 12/2.54), dpi=600)
    a1 = fractional_polar_axes(f1, thlim=(-90, 90),step=(10, 0.2),theta_offset=90)
    # example spiral plot:
    thstep = 10
    th = np.arange(-90, 90+thstep, thstep) # deg
    rstep = 1/(len(th)-1)
    r = np.arange(0, 1+rstep, rstep)
    a1.plot(th, r, 'b')
    # try to change one label for testing
    labels = [item.get_text() for item in a1.get_xticklabels()]
    labels[1] = '5'
    a1.set_xticklabels(labels)

    f1.show()

The setting in the last lines doesn't affect something. The list of labels contains only 7 empty strings.

Upvotes: 0

Views: 1675

Answers (1)

Amy Teegarden
Amy Teegarden

Reputation: 3972

I'm not certain, but it looks like you're doing something slightly different from what they are talking about in the documentation when they say you can use ax.set_xticks() like normal.

I think that you might need to set the ticklabels at the time the axes are created. When GridHelperCurveLinear is called, one of the keyword arguments is tick_formatter2. That's what you need to use. First, you need to import the formatter. Change

from mpl_toolkits.axisartist.grid_finder import MaxNLocator

to

from mpl_toolkits.axisartist.grid_finder import MaxNLocator, DictFormatter

DictFormatter takes a dictionary on initialization. When the formatter is passed a location, it looks in the dictionary to see if there's a corresponding string. Right now, the locations are [0, .25, .5, .75, 1]. Let's say I want to change those to [5, 10, 15, 20, 25]. I would create a dictionary:

r_locs = [0, .25, .5, .75, 1]
r_labels = ['5', '10', '15', '20', '25']
r_ticks = {loc : label for loc, label in zip(r_locs, r_labels)}

Notice that r_labels is a list of strings. This is important! DictFormatter will throw an error if you try to use ints. Then I add the keyword argument rlabels = None to fractional_polar_axes and change the code inside a bit:

if rlabels:
    rlabels = DictFormatter(rlabels)

grid_helper = GridHelperCurveLinear(tr,
                                    extremes=(th0, th1, r0, r1),
                                    grid_locator1=theta_grid_locator,
                                    grid_locator2=r_grid_locator,
                                    tick_formatter1=theta_tick_formatter,
                                    tick_formatter2=rlabels)

Now I just need to call fractional_polar_axes with the dictionary I made:

a1 = fractional_polar_axes(f1, thlim=(-90, 90),step=(10, 0.2),
    theta_offset=90, rlabels = r_ticks)

And here's the result:

Polar axes graph

Here's the entire code:

from __future__ import division
from __future__ import print_function

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.transforms import Affine2D
from matplotlib.projections import PolarAxes
from mpl_toolkits.axisartist import angle_helper
from mpl_toolkits.axisartist.grid_finder import MaxNLocator, DictFormatter
from mpl_toolkits.axisartist.floating_axes import GridHelperCurveLinear, FloatingSubplot

def fractional_polar_axes(f, thlim=(0, 180), rlim=(0, 1), step=(30, 0.25),
                      thlabel='theta', rlabel='r', ticklabels=True, theta_offset=0, rlabels = None):
    '''Return polar axes that adhere to desired theta (in deg) and r limits. steps for theta
and r are really just hints for the locators.'''
    th0, th1 = thlim # deg
    r0, r1 = rlim
    thstep, rstep = step

    tr_rotate = Affine2D().translate(theta_offset, 0)
    # scale degrees to radians:
    tr_scale = Affine2D().scale(np.pi/180., 1.)
    #pa = axes(polar="true") # Create a polar axis
    pa = PolarAxes
    tr = tr_rotate + tr_scale + pa.PolarTransform()
    theta_grid_locator = angle_helper.LocatorDMS((th1-th0)//thstep)
    r_grid_locator = MaxNLocator((r1-r0)//rstep)
    theta_tick_formatter = angle_helper.FormatterDMS()
    if rlabels:
        rlabels = DictFormatter(rlabels)

    grid_helper = GridHelperCurveLinear(tr,
                                        extremes=(th0, th1, r0, r1),
                                        grid_locator1=theta_grid_locator,
                                        grid_locator2=r_grid_locator,
                                        tick_formatter1=theta_tick_formatter,
                                        tick_formatter2=rlabels)

    a = FloatingSubplot(f, 111, grid_helper=grid_helper)
    f.add_subplot(a)
    # adjust x axis (theta):
    print(a)
    a.axis["bottom"].set_visible(False)
    a.axis["top"].set_axis_direction("bottom") # tick direction
    a.axis["top"].toggle(ticklabels=ticklabels, label=bool(thlabel))
    a.axis["top"].major_ticklabels.set_axis_direction("top")
    a.axis["top"].label.set_axis_direction("top")
    a.axis["top"].major_ticklabels.set_pad(10)

    # adjust y axis (r):
    a.axis["left"].set_axis_direction("bottom") # tick direction
    a.axis["right"].set_axis_direction("top") # tick direction
    a.axis["left"].toggle(ticklabels=True, label=bool(rlabel))
    # add labels:
    a.axis["top"].label.set_text(thlabel)
    a.axis["left"].label.set_text(rlabel)
    # create a parasite axes whose transData is theta, r:
    auxa = a.get_aux_axes(tr)
    print(auxa)
    # make aux_ax to have a clip path as in a?:
    auxa.patch = a.patch 
    # this has a side effect that the patch is drawn twice, and possibly over some other
    # artists. So, we decrease the zorder a bit to prevent this:
    a.patch.zorder = -2

    # add sector lines for both dimensions:
    thticks = grid_helper.grid_info['lon_info'][0]
    rticks = grid_helper.grid_info['lat_info'][0]
    print(grid_helper.grid_info['lat_info'])
    for th in thticks[1:-1]: # all but the first and last
        auxa.plot([th, th], [r0, r1], ':', c='grey', zorder=-1, lw=0.5)
    for ri, r in enumerate(rticks):
        # plot first r line as axes border in solid black only if it  isn't at r=0
        if ri == 0 and r != 0:
            ls, lw, color = 'solid', 1, 'black'
        else:
            ls, lw, color = 'dashed', 0.5, 'grey'
        # From http://stackoverflow.com/a/19828753/2020363
        auxa.add_artist(plt.Circle([0, 0], radius=r, ls=ls, lw=lw, color=color, fill=False,
                    transform=auxa.transData._b, zorder=-1))

    return auxa


if __name__ == '__main__':
    f1 = plt.figure(facecolor='white')
    r_locs = [0, .25, .5, .75, 1]
    r_labels = ['5', '10', '15', '20', '25']
    r_ticks = {loc : label for loc, label in zip(r_locs, r_labels)}
    a1 = fractional_polar_axes(f1, thlim=(-90, 90),step=(10, 0.2),
        theta_offset=90, rlabels = r_ticks)
    # example spiral plot:
    thstep = 10
    th = np.arange(-90, 90+thstep, thstep) # deg
    rstep = 1/(len(th)-1)
    r = np.arange(0, 1+rstep, rstep)
    a1.plot(th, r, 'b')
plt.show()

Upvotes: 3

Related Questions