How to use set_theta_offset and set_theta_direction on rotated tick labels on polar plot

Viewed 22

I want to align theta tick labels on a circle while also controlling start position and label order clockwise. Based on those two answers by ImportanceOfBeingErnest and Anmol Durgapal I was able to come up with this code, but that fails when I change the order and/or start with January north:

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(6, 6))
ax1 = fig.add_subplot(projection="polar")

labels = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
angles = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330]
theta_ticks = np.linspace(0.,330.,12)

plt.thetagrids(angles=angles, labels=labels)

for label, angle in zip(ax1.get_xticklabels(), theta_ticks):
    x, y = label.get_position()
    lab = ax1.text(x, y, label.get_text(), transform=label.get_transform(), ha=label.get_ha(), va=label.get_va())
    lab.set_rotation(angle-90)

ax1.set_xticklabels([])

plt.show()

resulting plot

When I now add

ax1.set_theta_offset(np.pi / 2)
ax1.set_theta_direction(-1)

i get this: misaligned labels

Any ideas on how I can achieve this result?

manually edited list example

This was achieved by editing the labels in reverse order and starting at April:

labels = ["April", "March", "February", "January", "December", "November", "October", "September", "August", "July", "June", "May"]

While that works it ruins the actual data I want to plot that relies on the theta_direction and offset.

1 Answers

While I could not find a solution to the specific question - that's how to use coordinate calculation to align the labels - I went a different way and separated data and labels into different axes. Being new to this I can't tell if that is a valid way of doing things, but it works.

Below is the minimal working example with these changes and toy data incorporated. Notice the end of the spiral lines up with January after being reversed and rotated independently of the labels. On the off-chance that anyone ever reads this, feel free to comment on anything that looks wrong.

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(6, 6))

# ax1 containing labels
ax1 = fig.add_subplot(label='labels', projection="polar")

labels = ["January","February","March","April","May","June","July","August","September","October","November","December"]

labels.reverse()
labels = labels[8:] + labels[:8]

angles = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330]
theta_ticks = np.linspace(0, 330, 12)

plt.thetagrids(
    angles=angles,
    labels=labels,
    fmt=None,
)  # theta grid with month labels

for label, angle in zip(ax1.get_xticklabels(), theta_ticks):
    x, y = label.get_position()
    lab = ax1.text(x, y, label.get_text(), transform=label.get_transform(), ha=label.get_ha(), va=label.get_va())
    lab.set_rotation(angle - 90)

ax1.set_xticklabels([])

# ax2 containing data rotated and reversed
ax2 = fig.add_subplot(label='data', projection="polar")
ax2.set_xticklabels([])

# toy data
r = np.arange(0, 2, 0.01)
theta = 2 * np.pi * np.arange(0, 2, 0.01)

ax2.plot(theta, r)

ax2.set_axis_off()  # hide all decorations
ax2.set_theta_offset(np.pi / 2)  # start month labels north
ax2.set_theta_direction(-1)  # set month labels in clockwise order

plt.show()
Related