在Python中为雷达图添加图例 [英] Adding legend to a radarchart in Python
问题描述
我想为每个已创建的情节创建一个带有图例的雷达图,但是到目前为止,这是不可能的。然后,您可以看到用于创建绘图的代码(感谢开发该绘图的另一个用户)。
I want to create a radarchart with legends for every plot that is created but until now it has been impossible. Then, you can see the code used to create the plot (thanks to another user that developed it).
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns # improves plot aesthetics
import pandas as pd
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)
每个情节都代表着不同的人。我想添加一个图例,显示每个人的名字以及在情节中代表他的颜色。我尝试添加标签,然后添加图例,但没有用。产生的图是这样的:
Every plot represents to different people. I want to add a legend showing the name of everyone and the color that represents him in the plot. I tried to add labels and then the legends but it didn´t work. The plot produced is something like that:
df = pd.DataFrame({
"Spe": pd.Series([89, 83, 70, 60, 30, 49, 28]),
"Str": pd.Series([69, 53, 30, 20, 10, 29, 48]),
"Det": pd.Series([82, 44, 79, 39, 20, 10, 85]),
"Extr": pd.Series([59, 74, 29, 36, 18, 29, 18]),
"Int": pd.Series([63, 11, 20, 36, 97, 58, 91]),
"Est": pd.Series([12, 69, 89, 59, 19, 58, 98]),
"Ape": pd.Series([29, 13, 94, 30, 20, 10, 67]),
"ID": pd.Series(["Carl","Michael","Peter","Louis","Sarah",
"Laura","Nicholas"])
})
dfo = df.drop('ID', 1)
print(dfo)
variables = ("1", "2", "3",
"4", "5", "6", "7")
ranges = [(1,100),(1,100),(1,100),(1,100),(1,100),(1,100),(1,100)]
fig1 = plt.figure(figsize=(8, 8))
radar = ComplexRadar(fig1, variables, ranges)
for i in range(len(dfo.index)-1):
data=dfo.iloc[i,:]
radar.plot(data)
radar.fill(data,alpha=0.2)
sns.plt.show()
感谢您的帮助。
推荐答案
如果有人感兴趣,请使用 ComplexRadar $ c $的代码c>来自此处。
ComplexRadar
类使用许多轴并使所有轴都不可见,因此在此处创建图例的最佳方法是创建一个新轴以将图例放入其中。为此,我们需要绘制的手柄行,因此我们需要更改 ComplexRadar.plot()
方法以返回行。然后,我们需要将这些行收集在列表中(称为 lax
)并将其提供给新的图例。
In case someone is interested, the code of the ComplexRadar
comes from here.
The ComplexRadar
class uses many axes and makes all of them invisible, so the best way to create a legend here, would be to create a new axes to put the legend in. For that we need the handles of the plotted lines, so we need to change the ComplexRadar.plot()
method to return the line. We then need to collect those lines in a list (call it lax
) and supply them to the new legend.
我确实对代码进行了一些更改,以使其能够在python 2.7中运行,并且也使其对我自己更易理解。在这里,应该起作用:
I did make some changes to the code to make it work in python 2.7 and also to make it more comprehensible to myself. Here is, what should work:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
def _scale_data(data, ranges):
"""scales data[1:] to ranges[0],
"""
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]
sdata = [d]
for d, (y1, y2) in zip(data[1:], ranges[1:]):
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)
l = self.ax.plot(self.angle, np.r_[sdata, sdata[0]], *args, **kw)
return l
def fill(self, data, *args, **kw):
sdata = _scale_data(data, self.ranges)
self.ax.fill(self.angle, np.r_[sdata, sdata[0]], *args, **kw)
index = ["Carl","Michael","Peter","Louis","Sarah", "Laura","Nicholas"]
df = pd.DataFrame({
"Spe": pd.Series([89, 83, 70, 60, 30, 49, 28]),
"Str": pd.Series([69, 53, 30, 20, 10, 29, 48]),
"Det": pd.Series([82, 44, 79, 39, 20, 10, 85]),
"Extr": pd.Series([59, 74, 29, 36, 18, 29, 18]),
"Int": pd.Series([63, 11, 20, 36, 97, 58, 91]),
"Est": pd.Series([12, 69, 89, 59, 19, 58, 98]),
"Ape": pd.Series([29, 13, 94, 30, 20, 10, 67]),
})
variables = [k[0] for k in df.iteritems()]
ranges = [(1.,100.),(1.,100.),(1.,100.),(1.,100.),(1.,100.),(1.,100.),(1.,100.)]
fig1 = plt.figure(figsize=(8, 8))
radar = ComplexRadar(fig1, variables, ranges)
lax = []
for i, name in enumerate(index):
data=df.iloc[i].values
l, = radar.plot(data, label=name)
lax.append(l)
radar.fill(data,alpha=0.2)
legendax = fig1.add_axes([0.8,0.8,0.1,.1])
legendax.legend(handles = lax, labels=index, loc=3, bbox_to_anchor=(0,0,1,1), bbox_transform=fig1.transFigure )
legendax.axis('off')
sns.plt.show()
产生以下情节
producing the following plot
这篇关于在Python中为雷达图添加图例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!