Last active
May 2, 2024 12:07
-
-
Save kylerbrown/29ce940165b22b8f25f4 to your computer and use it in GitHub Desktop.
Code for a complex radar plot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import matplotlib.pyplot as plt | |
import seaborn as sns # improves plot aesthetics | |
def _invert(x, limits): | |
"""inverts a value x on a scale from | |
limits[0] to limits[1]""" | |
return limits[1] - (x - limits[0]) | |
def _scale_data(data, ranges): | |
"""scales data[1:] to ranges[0], | |
inverts if the scale is reversed""" | |
for d, (y1, y2) in zip(data[1:], ranges[1:]): | |
assert (y1 <= d <= y2) or (y2 <= d <= y1) | |
x1, x2 = ranges[0] | |
d = data[0] | |
if x1 > x2: | |
d = _invert(d, (x1, x2)) | |
x1, x2 = x2, x1 | |
sdata = [d] | |
for d, (y1, y2) in zip(data[1:], ranges[1:]): | |
if y1 > y2: | |
d = _invert(d, (y1, y2)) | |
y1, y2 = y2, y1 | |
sdata.append((d-y1) / (y2-y1) | |
* (x2 - x1) + x1) | |
return sdata | |
class ComplexRadar(): | |
def __init__(self, fig, variables, ranges, | |
n_ordinate_levels=6): | |
angles = np.arange(0, 360, 360./len(variables)) | |
axes = [fig.add_axes([0.1,0.1,0.9,0.9],polar=True, | |
label = "axes{}".format(i)) | |
for i in range(len(variables))] | |
l, text = axes[0].set_thetagrids(angles, | |
labels=variables) | |
[txt.set_rotation(angle-90) for txt, angle | |
in zip(text, angles)] | |
for ax in axes[1:]: | |
ax.patch.set_visible(False) | |
ax.grid("off") | |
ax.xaxis.set_visible(False) | |
for i, ax in enumerate(axes): | |
grid = np.linspace(*ranges[i], | |
num=n_ordinate_levels) | |
gridlabel = ["{}".format(round(x,2)) | |
for x in grid] | |
if ranges[i][0] > ranges[i][1]: | |
grid = grid[::-1] # hack to invert grid | |
# gridlabels aren't reversed | |
gridlabel[0] = "" # clean up origin | |
ax.set_rgrids(grid, labels=gridlabel, | |
angle=angles[i]) | |
#ax.spines["polar"].set_visible(False) | |
ax.set_ylim(*ranges[i]) | |
# variables for plotting | |
self.angle = np.deg2rad(np.r_[angles, angles[0]]) | |
self.ranges = ranges | |
self.ax = axes[0] | |
def plot(self, data, *args, **kw): | |
sdata = _scale_data(data, self.ranges) | |
self.ax.plot(self.angle, np.r_[sdata, sdata[0]], *args, **kw) | |
def fill(self, data, *args, **kw): | |
sdata = _scale_data(data, self.ranges) | |
self.ax.fill(self.angle, np.r_[sdata, sdata[0]], *args, **kw) | |
if __name__ == "__main__": | |
# example data | |
variables = ("Normal Scale", "Inverted Scale", "Inverted 2", | |
"Normal Scale 2", "Normal 3", "Normal 4 %", "Inverted 3 %") | |
data = (1.76, 1.1, 1.2, | |
4.4, 3.4, 86.8, 20) | |
ranges = [(0.1, 2.3), (1.5, 0.3), (1.3, 0.5), | |
(1.7, 4.5), (1.5, 3.7), (70, 87), (100, 10)] | |
# plotting | |
fig1 = plt.figure(figsize=(6, 6)) | |
radar = ComplexRadar(fig1, variables, ranges) | |
radar.plot(data) | |
radar.fill(data, alpha=0.2) | |
plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@amarruedo797 I had the same problem and for me, removing the lines 50 and 51 did the trick. I'm not 100% sure why that is the case, but I'm guessing newer matplotlib versions recognize when the ticks are reversed and do it automatically for the grid as well, so we're rereversing them with that line.