如何在python中制作多边形雷达(蜘蛛)图表 [英] How to make a polygon radar (spider) chart in python
问题描述
import matplotlib.pyplot as plt
import numpy as np
labels = ['Siege','Initiation','Crowd_control',' Wave_clear','Objective_damage']
标记= [0、1、2、3、4、5]
str_markers = [ 0, 1, 2, 3, 4, 5]
def make_radar_chart(名称,统计信息,attribute_labels =标签,plot_markers =标记,plot_str_markers = str_markers):
标签= np.array(attribute_labels )
angles = np.linspace(0,2 * np.pi,len(labels),endpoint = False)
stats = np.concatenate((stats,[stats [0] ]))
angles = np.concatenate((angles,[angles [0]])))
fig = plt.figure()
ax = fig.add_subplot(111 ,polar = True)
ax.plot(angles,stats,'o-',linewidth = 2)
ax.fill(angles,stats,alpha = 0.25)
ax.set_thetagrids(角度* 180 / np.pi,标签)
plt.yticks(标记)
ax.set_title(名称)
ax.grid(真)
图savefig( static / images /%s.png%名称)
return plt.s how()
make_radar_chart( Agni,[2,3,4,4,5])#示例
基本上我希望图表是五边形而不是圆形。有人能帮忙吗。我正在使用python matplotlib保存图像,该图像将在以后存储和显示。我希望图表具有第二张图片的形式
编辑:
网格线= ax.yaxis.get_gridlines()
用于网格线中的gl:
gl.get_path()._ interpolation_steps = 5
从下面的答案中添加此部分代码很有帮助。我正在得到这张图表。仍然需要弄清楚如何摆脱最外层的环:
在这里,外脊柱是所需的多边形。但是,内部网格线是圆形的。
因此,悬而未决的问题是如何使网格线与脊椎相同。
这可以通过覆盖绘制来完成
方法并将网格线的路径插值步骤变量设置为 RadarAxes
类的变量数。
网格线= self.yaxis.get_gridlines()
for gl in gridlines:
gl.get_path()._ interpolation_steps = num_vars
完整示例:
将numpy导入为np
从matplotlib.patches导入为plt
的matplotlib.pyplot从matplotlib.pathches导入Circle,RegularPolygon
从matplotlib.projections导入路径
。 polar从matplotlib.projections导入register_projection
从matplotlib.spines导入Spine
从matplotlib.transforms导入Affine2D
defradar_factory(num_vars, frame ='circle'):
使用`num_vars`轴创建雷达图。
此函数创建RadarAxes投影并进行注册。
参数
----------
num_vars:int
雷达图变量的数量。
框:{’圆圈 | 'polygon'}
围绕轴的框架形状。
#计算均匀间隔的轴角
theta = np.linspace(0,2 * np.pi,num_vars,endpoint = False)
类RadarAxes(PolarAxes):
name ='radar'
def __init __(self,* args,** kwargs):
super( ).__ init __(* args,** kwargs)
#旋转绘图,使第一个轴位于
self的顶部。set_theta_zero_location('N')
def fill(自我,* args,closed = True,** kwargs):
覆盖填充,以便默认情况下关闭行
返回super()。fill(closed = closed,* args ,** kwargs)
def plot(self,* args,** kwargs):
覆盖绘图,因此该行默认情况下处于关闭状态
行= super()。plot(* args,** kwargs)
用于行中的行:
self._close_line(line)
def _close_line(self,line):
x,y = line.get_data()
#FIXME:如果x [0]!= x [-1],则x [0],y [0]处的标记会加倍
:
x = np.concatenate((x,[x [ 0]]]))
y = np.concatenate((y,[y [0]]))
line.set_data(x,y)
def set_varlabels(self,标签):
self.set_thetagrids(np.degrees(theta),标签)
def _gen_axes_patch(self):
#轴补丁必须以(0.5,0.5)为中心),并且在轴坐标中的半径为0.5
#。
if frame =='circle':
return Circle((0.5,0.5),0.5)
elif frame =='polygon':
return RegularPolygon((0.5,0.5 ),num_vars,
radius = .5,edgecolor = k)
否则:
提高ValueError('frame'的未知值:%s%frame)
def draw(self,renderer):
绘制。如果框架是多边形,则使framelines为多边形
如果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):
如果frame =='circle':
return super()._ gen_axes_spines()
elif frame =='polygon':
#spine_type必须为'left'/'right'/'top' /底部 /圆圈。
spine = Spine(轴=自我,
spine_type ='circle',
path = Path.unit_regular_polygon(num_vars))
#unit_regular_polygon给出一个以$为中心的半径为1的多边形b $ b#(0,0),但我们希望在轴坐标中以(0.5,
#0.5)为中心的半径为0.5的多边形。
spine.set_transform(Affine2D()。scale(.5).translate(.5,.5)
+ self.transAxes)
return {' Polar':spine}
else:
提高ValueError('frame'的未知值:%s%frame)
register_projection(RadarAxes)
返回theta
数据= [['硫酸盐','硝酸盐','EC','OC1','OC2','OC3','OP','CO','O3 '],
(基本情况,[
[0.88、0.01、0.03、0.03、0.00、0.06、0.01、0.00、0.00],
[0.07、0.95、0.04、0.05, 0.00、0.02、0.01、0.00、0.00],
[0.01、0.02、0.85、0.19、0.05、0.10、0.00、0.00、0.00],
[0.02、0.01、0.07、0.01、0.21, 0.12、0.98、0.00、0.00],
[0.01、0.01、0.02、0.71、0.74、0.70、0.00、0.00、0.00]])]
N = len(data [0 ])
theta =雷达工厂(N,框架=多边形)
条幅标签= data.pop(0)
标题,case_data = data [0]
无花果,ax = plt.subplots(figsize =(6,6),subplot_kw = dict(projection ='radar'))
fig.subplots_adjust(top = 0.85,bottom = 0.05 )
ax.set_rgrids([0.2,0.4,0.6,0.8])
ax.set_title(title,position =(0.5,1.1),ha ='center')$ b $在case_data中d的b
:
line = ax.plot(theta,d)
ax.fill(theta,d,alpha = 0.25)
ax.set_varlabels(spoke_labels)
plt.show()
import matplotlib.pyplot as plt
import numpy as np
labels=['Siege', 'Initiation', 'Crowd_control', 'Wave_clear', 'Objective_damage']
markers = [0, 1, 2, 3, 4, 5]
str_markers = ["0", "1", "2", "3", "4", "5"]
def make_radar_chart(name, stats, attribute_labels = labels, plot_markers = markers, plot_str_markers = str_markers):
labels = np.array(attribute_labels)
angles = np.linspace(0, 2*np.pi, len(labels), endpoint=False)
stats = np.concatenate((stats,[stats[0]]))
angles = np.concatenate((angles,[angles[0]]))
fig= plt.figure()
ax = fig.add_subplot(111, polar=True)
ax.plot(angles, stats, 'o-', linewidth=2)
ax.fill(angles, stats, alpha=0.25)
ax.set_thetagrids(angles * 180/np.pi, labels)
plt.yticks(markers)
ax.set_title(name)
ax.grid(True)
fig.savefig("static/images/%s.png" % name)
return plt.show()
make_radar_chart("Agni", [2,3,4,4,5]) # example
Basically I want the chart to be a pentagon instead of circle. Can anyone help with this. I am using python matplotlib to save an image which will stored and displayed later. I want my chart to have the form of the second picture
EDIT:
gridlines = ax.yaxis.get_gridlines()
for gl in gridlines:
gl.get_path()._interpolation_steps = 5
adding this section of code from answer below helped a lot. I am getting this chart. Still need to figure out how to get rid of the outer most ring:
The radar chart demo shows how to make the a radar chart. The result looks like this:
Here, the outer spine is polygon shaped as desired. However the inner grid lines are circular. So the open question is how to make the gridlines the same shape as the spines.
This can be done by overriding the draw
method and setting the gridlines' path interpolation step variable to the number of variables of the RadarAxes
class.
gridlines = self.yaxis.get_gridlines()
for gl in gridlines:
gl.get_path()._interpolation_steps = num_vars
Complete example:
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(*args, **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=.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
data = [['Sulfate', 'Nitrate', 'EC', 'OC1', 'OC2', 'OC3', 'OP', 'CO', 'O3'],
('Basecase', [
[0.88, 0.01, 0.03, 0.03, 0.00, 0.06, 0.01, 0.00, 0.00],
[0.07, 0.95, 0.04, 0.05, 0.00, 0.02, 0.01, 0.00, 0.00],
[0.01, 0.02, 0.85, 0.19, 0.05, 0.10, 0.00, 0.00, 0.00],
[0.02, 0.01, 0.07, 0.01, 0.21, 0.12, 0.98, 0.00, 0.00],
[0.01, 0.01, 0.02, 0.71, 0.74, 0.70, 0.00, 0.00, 0.00]])]
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=(6, 6), subplot_kw=dict(projection='radar'))
fig.subplots_adjust(top=0.85, bottom=0.05)
ax.set_rgrids([0.2, 0.4, 0.6, 0.8])
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, alpha=0.25)
ax.set_varlabels(spoke_labels)
plt.show()
这篇关于如何在python中制作多边形雷达(蜘蛛)图表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!