-
-
Save kylerbrown/29ce940165b22b8f25f4 to your computer and use it in GitHub Desktop.
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() |
@amarruedo797 I didn't find a solution yet, I just moved the labels outwards a bit so they didn't overlap for now:
for txt, angle in zip(text, angles):
# txt.set_rotation(angle-90) # TODO: doesn't work
txt.set_position((-0.1,-0.1)) # move labels outward
@amarruedo797 I didn't find a solution yet, I just moved the labels outwards a bit so they didn't overlap for now:
for txt, angle in zip(text, angles): # txt.set_rotation(angle-90) # TODO: doesn't work txt.set_position((-0.1,-0.1)) # move labels outward
Hi! thanks for your answer,
in my case I can only get a graph when the ranges are not inversed, for example: (0,1), when I have a range : (1,0) the code does not work. I think it migth be an issue with the python and matplotlib versions? @kylerbrown, do you know if this could be the problem? Thanks!
@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.
@w-t-effi Thanks ! That solved my issue of not getting the axes inverted .
Hi!
I have the same problem as @OD1995 , did you find a solution? The code works with non inverted ranges, but it gets stuck when inverting them.
Thanks