Reputation: 99
I want to draw some circular axes to plot the artwork for an old-fashioned circular slide rule. In almost every example, polar plots have an angular axis of degrees or radians. I found one example of changing the labels to be like a clock (1 - 12), but I couldn’t see how to extend that technique to logarithmic scales.
I can draw the desired axis in a linear manner, as I see examples of making a logarithmic radial axis. But I can’t find a way to apply log scales to the angular theta axis.
A somewhat related issue, how can you use matplotlib
to draw a single axis (e.g., no data, axis only)? This could be helpful for making nomographs, for example. In my use case, if I can’t plot the circular log scale directly, I could perhaps post-process a linear log scale into a circle — maybe.
Here is an old circular slide rule as an example. I’d like to make scales such as C or D (one complete log cycle in 360 degrees), A (two cycles) and K (three cycles).
Upvotes: 1
Views: 477
Reputation: 99
Based on @ljbkusters answer, I crafted a single-cycle, circular log-base-10 scale. This will serve as a basis for more detailed plots for the final slide rule artwork.
import numpy as np
import matplotlib.pyplot as plt
ax = plt.subplot(111, polar=True)
# Make the labels go clockwise
ax.set_theta_direction(-1)
# Place 0 at the top
ax.set_theta_offset(np.pi/2.0)
# Polar plots don't have tick marks,
# cannot draw outside the max radius set by ylim
# Remove the frame, and y-axis,
# * draw our own axis circle
# * draw our own tick marks (below)
ax.set_ylim(0,100)
ax.grid(False)
ax.set_frame_on(False)
ax.axes.get_yaxis().set_visible(False)
angles = np.linspace(0.0, 2.0*np.pi, 100)
ax.plot( angles, 100*[95], color='black', lw=1.2 )
# Major
lim_min = 1
lim_max = 10
N_LABLES = 10
XTICKS = [2.0 * np.pi * np.log10(x) for x in np.linspace(lim_min, lim_max, N_LABLES-1, endpoint=False)]
ax.set_xticks(XTICKS)
# Set the circumference labels
ax.set_xticklabels(range(1, N_LABLES))
# Draw major tick marks
tick = [93,100]
for t in XTICKS:
ax.plot([t,t], tick, lw=1.0, color='black')
# Minor
lim_min = 1
lim_max = 10
N_LABLES = 100
XTICKS = [2.0 * np.pi * np.log10(x) for x in np.linspace(lim_min, lim_max, N_LABLES-1, endpoint=False)]
ax.set_xticks(XTICKS)
# Draw minor tick marks
tick = [95,98]
for t in XTICKS:
ax.plot([t,t], tick, lw=0.5, color='blue')
plt.show()
Upvotes: 2
Reputation: 197
Try this
import numpy as np
import matplotlib.pyplot as plt
ax = plt.subplot(111, polar=True)
lim_min = 1 # ln(1) = 0
lim_max = np.e**(2*np.pi) # ln(e**(2*pi)) = 2*pi (np.log = ln)
N_LABLES = 24
XTICKS = [np.log(x) for x in np.linspace(lim_min, lim_max, N_LABLES, endpoint=False)]
# Set the circumference labels
ax.set_xticks(XTICKS)
ax.set_xticklabels(range(N_LABLES))
# Make the labels go clockwise
ax.set_theta_direction(-1)
# Place 0 at the top
ax.set_theta_offset(np.pi/2.0)
plt.show()
You can play with the exact scaling from 0 to 2pi to get the plot the way you want it. Figure produced:
Upvotes: 3