python - 如何在 Python Matplotlib 中为我的雷达图点添加标签
问题描述
原谅这个看似简单的问题。
我有一个我在 Power BI 中使用的雷达图,它会在我过滤数据时拉入数据点并进行更改。我无法解决的一个问题是如何将数字添加到图表点。我从这里的另一篇文章中获得了大部分代码,但我似乎无法弄清楚如何添加这些数据点。
如果我要找的东西没有意义,请查看图片示例。
当前图表:
所需图表:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, RegularPolygon
from matplotlib.path import Path
from matplotlib.projections.polar import PolarAxes
from matplotlib.projections import register_projection
from matplotlib.spines import Spine
from matplotlib.transforms import Affine2D
def radar_factory(num_vars, frame='circle'):
"""Create a radar chart with `num_vars` axes.
This function creates a RadarAxes projection and registers it.
Parameters
----------
num_vars : int
Number of variables for radar chart.
frame : {'circle' | 'polygon'}
Shape of frame surrounding axes.
"""
# calculate evenly-spaced axis angles
theta = np.linspace(0, 2*np.pi, num_vars, endpoint=False)
class RadarAxes(PolarAxes):
name = 'radar'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# rotate plot such that the first axis is at the top
self.set_theta_zero_location('N')
def fill(self, *args, closed=True, **kwargs):
"""Override fill so that line is closed by default"""
return super().fill(closed=closed, *args, **kwargs)
def plot(self, *args, **kwargs):
"""Override plot so that line is closed by default"""
lines = super().plot(19, **kwargs)
for line in lines:
self._close_line(line)
def _close_line(self, line):
x, y = line.get_data()
# FIXME: markers at x[0], y[0] get doubled-up
if x[0] != x[-1]:
x = np.concatenate((x, [x[0]]))
y = np.concatenate((y, [y[0]]))
line.set_data(x, y)
def set_varlabels(self, labels):
self.set_thetagrids(np.degrees(theta), labels)
def _gen_axes_patch(self):
# The Axes patch must be centered at (0.5, 0.5) and of radius 0.5
# in axes coordinates.
if frame == 'circle':
return Circle((0.5, 0.5), 0.5)
elif frame == 'polygon':
return RegularPolygon((0.5, 0.5), num_vars,
radius=0.5, edgecolor="k")
else:
raise ValueError("unknown value for 'frame': %s" % frame)
def draw(self, renderer):
""" Draw. If frame is polygon, make gridlines polygon-shaped """
if frame == 'polygon':
gridlines = self.yaxis.get_gridlines()
for gl in gridlines:
gl.get_path()._interpolation_steps = num_vars
super().draw(renderer)
def _gen_axes_spines(self):
if frame == 'circle':
return super()._gen_axes_spines()
elif frame == 'polygon':
# spine_type must be 'left'/'right'/'top'/'bottom'/'circle'.
spine = Spine(axes=self,
spine_type='circle',
path=Path.unit_regular_polygon(num_vars))
# unit_regular_polygon gives a polygon of radius 1 centered at
# (0, 0) but we want a polygon of radius 0.5 centered at (0.5,
# 0.5) in axes coordinates.
spine.set_transform(Affine2D().scale(.5).translate(.5, .5)
+ self.transAxes)
return {'polar': spine}
else:
raise ValueError("unknown value for 'frame': %s" % frame)
register_projection(RadarAxes)
return theta
disease_avg = round(dataset["disease_avg"].mean())
stress_vvg = round(dataset["Stress_Avg"].mean())
Nutrition_Avg = round(dataset["Nutrition_Avg"].mean())
Movement_avg = round(dataset["Movement_avg"].mean())
fitness_avg = round(dataset["fitness_avg"].mean())
data = [['Disease Risk', 'Stress', 'Nutrition', 'Movement Quality', 'Fitness'],
('Basecase', [[disease_avg, stress_vvg , Nutrition_Avg, Movement_avg, fitness_avg]])]
#('Basecase', [[dataset["disease_avg"].mean(), dataset["Stress_Avg"].mean() , dataset["Nutrition_Avg"].mean(),dataset["Movement_avg"].mean(), dataset["fitness_avg"].mean()]])]
cat = ['Disease Risk', 'Stress', 'Nutrition', 'Movement Quality', 'Fitness']
values = [dataset["disease_avg"].mean(), dataset["Stress_Avg"].mean(), dataset["Nutrition_Avg"].mean(), dataset["Movement_avg"].mean(), dataset["fitness_avg"].mean()]
N = len(data[0])
theta = radar_factory(N, frame='polygon')
spoke_labels = data.pop(0)
title, case_data = data[0]
fig, ax = plt.subplots(figsize=(4, 4), subplot_kw=dict(projection='radar'))
fig.subplots_adjust(wspace=0.25, hspace=0.20, top=0.85, bottom=0.05)
ax.set_rgrids([5, 10, 15, 20])
#ax.set_title(title, position=(0.5, 1.1), ha='center')
for d in case_data:
line = ax.plot(theta, d)
ax.fill(theta, d,color='#8bbe3f', alpha=0.35)
ax.set_varlabels(spoke_labels)
plt.show()
解决方案
您可以在绘制填充多边形的循环期间添加文本标签。遍历多边形的点,ax.text(ti, di+1, 'text', ...
在 position 放置一个文本(ti, di+1)
。使用di+1
使文本比多边形稍微向外。由于水平和垂直居中,所有标签的位置相似。
可选地,可以标记点本身,例如通过调用scatter
。
像这样:
for d in case_data:
line = ax.plot(theta, d)
ax.fill(theta, d, color='#8bbe3f', alpha=0.35)
for ti, di in zip(theta, d):
ax.text(ti, di+1, di, color='dodgerblue', ha='center', va='center')
ax.scatter(theta, d, color='crimson', s=10)
推荐阅读
- flutter - 颤振:生成的插件注册错误
- java - 两个字符串类型的局部变量相同的内容是否相等?
- javascript - 如何在 React 中为上传到数组的不正确数据触发警报消息
- android - 如何在 android webview PWA 中读取/写入本地和会话存储?
- php - Dompdf Tutor LMS“找不到图像或类型未知”
- windows - 默认 1MB 堆栈中缺少 KB
- docker - docker和runc有什么关系?
- jasmine - 从 mocha chai 迁移到 Jasmine
- javascript - 在 setData 之后,xKey 标签在 Morris.js 上消失
- javascript - 无法使用函数内的函数更新数据变量