玫瑰图简介
玫瑰图全称南丁格尔玫瑰图,是英国护士和统计学家弗罗伦斯·南丁格尔发明的,又名为极区图。
南丁格尔自己常昵称这类图为鸡冠花图(coxcomb),用以表达军医院季节性的死亡率,提供给那些不太能理解传统统计报表的公务人员。
在疫情期间经常看到那种盘旋的像玫瑰一样的、用来展示不同地区的新增等数据的图形,就是玫瑰图。
玫瑰图是一种圆形的直方图,即有饼图的特征,也有直方图的特征。
在Python中,可以使用pyecharts库中绘制饼图的组件Pie实现玫瑰图,本文就循序渐进地介绍一步步将饼图演变成玫瑰图。
绘图准备
pip install pyecharts
本文用十种水果的热量(kcal/100g)值对比来做演示。(数据来源于网络)
# coding=utf-8
import pandas as pd
fruits = {'香蕉': 115, '梨': 79, '椰子': 241, '柿子': 74, '鲜枣': 125,
'榴莲': 147, '石榴': 72, '菠萝蜜': 105, '牛油果': 143, '山楂': 102}
s_fruits = pd.Series(fruits)
print(s_fruits)
香蕉 115
梨 79
椰子 241
柿子 74
鲜枣 125
榴莲 147
石榴 72
菠萝蜜 105
牛油果 143
山楂 102
dtype: int64
绘制饼图
先根据初始数据,绘制一个基本的饼图。
绘制饼图使用pyecharts中的Pie组件,先初始化一个Pie对象,调用add()方法添加绘图用的数据,再链式调用set_series_opts()、set_global_opts()设置饼图的标签、标题、图例等,最后链式调用render()方法将图形渲染到HTML文件中,可以用浏览器打开绘图结果。
from pyecharts.charts import Pie
from pyecharts import options as opts
# 饼图
pie = Pie(init_opts=opts.InitOpts(width='800px', height='600px', bg_color='white'))
pie.add(
'', [list(z) for z in zip([fruit for fruit in s_fruits.index], s_fruits)], center=['50%', '50%']
).set_series_opts(
label_opts=opts.LabelOpts(formatter="{b}: {c}"),
).set_global_opts(
title_opts=opts.TitleOpts(title='水果的热量对比(kcal/100g)', pos_left='300', pos_top='20',
title_textstyle_opts=opts.TextStyleOpts(color='black', font_size=16)),
legend_opts=opts.LegendOpts(is_show=False)
).render('fruits_calorie1.html')

此时绘制了一个普通的饼图,已经可以对比展示数据了。
绘制环形饼图
要将一个饼图设置成环形饼图,在添加数据的add()方法中使用radius参数设置。
radius参数接收一个列表或元组,列表由两个数值或百分比组成,如radius=[‘40%’, ‘60%’],分别表示饼图的内半径和外半径,大部分情况用百分比。
饼图的内半径默认为0,外半径默认为画布高宽中较小的一项的一半,所以饼图默认是从圆心开始的,大小根据画布大小自适应。
# 环形饼图
pie = Pie(init_opts=opts.InitOpts(width='800px', height='600px', bg_color='white'))
pie.add(
'', [list(z) for z in zip([fruit for fruit in s_fruits.index], s_fruits)],
radius=['40%', '60%'], center=['50%', '50%']
).set_series_opts(
label_opts=opts.LabelOpts(formatter="{b}: {c}"),
).set_global_opts(
title_opts=opts.TitleOpts(title='水果的热量对比(kcal/100g)', pos_left='300', pos_top='20',
title_textstyle_opts=opts.TextStyleOpts(color='black', font_size=16)),
legend_opts=opts.LegendOpts(is_show=False)
).render('fruits_calorie2.html')

设置radius参数后饼图变成了环形饼图。当然,玫瑰图并不一定是“空心”的,不用先修改成环形饼图也可以。
绘制玫瑰图
在饼图的基础上,在add()方法中添加rosetype="radius"参数,就可以绘制出玫瑰图。
rosetype参数用于设置是否展示成南丁格尔玫瑰图,默认None(不展示成玫瑰图)。
rosetype有’radius’和’area’两种模式:
radius模式:用扇形圆心角展现数据的百分比,通过半径展现数据大小。
area模式:所有扇形圆心角相同,仅通过半径展现数据大小。
# 玫瑰图
pie = Pie(init_opts=opts.InitOpts(width='800px', height='600px', bg_color='white'))
pie.add(
'', [list(z) for z in zip([fruit for fruit in s_fruits.index], s_fruits)],
radius=['10%', '70%'], center=['50%', '50%'], rosetype="radius"
).set_series_opts(
label_opts=opts.LabelOpts(formatter="{b}: {c}")
).set_global_opts(
title_opts=opts.TitleOpts(title='水果的热量对比(kcal/100g)', pos_left='300', pos_top='20',
title_textstyle_opts=opts.TextStyleOpts(color='black', font_size=16)),
legend_opts=opts.LegendOpts(is_show=False)
).render('fruits_calorie3.html')

本文使用’radius’模式,用扇形圆心角展现数据的百分比,具有饼图的特征,通过半径展现数据大小,具有直方图的特征。
优化玫瑰图
玫瑰图已经完成了,在展示时可以进行一些优化。
先对数据进行排序。
使用pandas中的sort_values()方法先将数据排序,再绘制玫瑰图,这样图像的半径依次变大,对比效果更直观。
调整radius的范围。
根据数据的变化调整radius参数中的内半径和外半径值,改变图形的展示范围,使图像更协调美观。
设置扇形颜色渐变。
链式调用set_colors()方法来设置玫瑰图的颜色,为了使不同的扇形颜色依次渐变,可以通过设置RGB(red,green,blue)值的变化来实现,如下方代码控制不同数据的R值和B值,将颜色调为红蓝渐变。具体代码如下。
# 玫瑰图美化
s_fruits = s_fruits.sort_values()
pie = Pie(init_opts=opts.InitOpts(width='800px', height='600px', bg_color='white'))
pie.add(
'', [list(z) for z in zip([fruit for fruit in s_fruits.index], s_fruits)],
radius=['10%', '70%'], center=['50%', '50%'], rosetype="radius"
).set_series_opts(
label_opts=opts.LabelOpts(formatter="{b}: {c}"),
).set_global_opts(
title_opts=opts.TitleOpts(title='水果的热量对比(kcal/100g)', pos_left='300', pos_top='20',
title_textstyle_opts=opts.TextStyleOpts(color='black', font_size=16)),
legend_opts=opts.LegendOpts(is_show=False)
).set_colors(
['rgb({r},0,{b})'.format(r=255-20*(len(s_fruits)-x+1), b=255-15*x) for x in range(len(s_fruits))]
).render('fruits_calorie4.html')

经过以上几个步骤的演进,一个不错的玫瑰图完成了。这样一步一步地调整和演进,可以方便大家学习。
如果本文对你有帮助,欢迎点赞、收藏和关注。
参考文档:
[1] pyecharts官方文档:https://pyecharts.org/#/zh-cn/basic_charts
我正在寻找一种简单的方法来绘制大约10个点和矩形,以便能够查看我的算法哪里出了问题。我查看了gnuplot,但似乎绘制矩形特别糟糕。 最佳答案 SVG(MDNTutorial)是一种非常简单的基于文本(XML)的格式,您可以使用Ruby轻松生成它,而无需任何SVG库,并可以在任何现代Web浏览器中查看。这是一个示例:通过字符串插值的SVG点points=(0..5).map{[rand(100)-50,rand(100)-50]}puts#{points.map{|x,y|""}.join("\n")}ENDSVG输出:http:/
我想画一个点,大约1秒后我想画下一个点。这是否可能:我已经试过了:functionsimulate(i){setTimeout(function(){drawPoint(vis,i,i);},1000);}for(vari=1;i不幸的是,这是行不通的。它只是立即绘制整条线。 最佳答案 这是行不通的,因为for循环将立即运行到结束,setTimeouts将被同时调度,所有函数将同时触发。取而代之的是,这样做:vari=1;(functionloop(){if(i++>200)return;setTimeout(function(){
我正在使用GoogleMapsAPIV3在Googlemap中绘制一些自由形式的多边形,而不是标准库附带的标准点击多边形。一切都很好。问题:多边形生成大量可编辑点。如何在需要时简化多边形并创建可编辑点?这里是我的代码:varlatlng=newgoogle.maps.LatLng(46.779231,6.659431);varoptions={center:latlng,zoom:19,mapTypeId:google.maps.MapTypeId.ROADMAP,draggable:false};varmap=newgoogle.maps.Map(document.getElemen
我正在尝试绘制一个分类的多轴排名柱形图。排名第一的应该是最高的列,最低的排名应该是最短的。基本上我希望条形的高度是倒数。非常接近:varplayer_name_array=["AaronRodgers","AndrewLuck","DrewBrees","RussellWilson","PeytonManning","RyanTannehill","TonyRomo","MattRyan","CamNewton","BenRoethlisberger","EliManning","PhilipRivers","ColinKaepernick","TeddyBridgewater","M
我编写了这个无辜的javascript代码,它允许用户创建两个标记并绘制它们之间的路线。它不起作用,相反,它给出了一个奇怪的错误:UncaughtTypeError:Cannotreadproperty'ya'ofundefined有人可以告诉我这里出了什么问题吗://calleduponaclickGEvent.addListener(map,"click",function(overlay,point){if(isCreateHeadPoint){//addtheheadmarkerheadMarker=newGMarker(point,{icon:redIcon,title:'H
我正在使用Fabric.js,我想在Canvas上绘制弧线。我能找到的最接近的形状是Circle形状。当然,这只能让我画一个圆,而不是像跨越45°或180°的弧。有没有办法用Fabric.js来完成这个?如果没有,有没有办法获取底层上下文,然后创建弧并允许fabric管理它?保留Fabric.js提供的选择和缩放功能很重要。 最佳答案 在最新版本的FabricJSforcircle中添加了startAngle和endAngle属性。https://github.com/kangax/fabric.js/pull/1675varcan
我有一个力导向图,每个节点之间都有链接。现在一些节点对有多个相互连接的链接。我找到了这个例子:Drawingmultipleedgesbetweentwonodeswithd3.我觉得这很管用。但是如果你有固定的节点并拖动,路径最终会相互重叠。我整理了这个例子的编辑版本:http://jsfiddle.net/thatOneGuy/7HZcR/502/单击按钮固定节点并四处移动它们以了解我的意思。计算弧度的代码://sortlinksbysource,thentargetlinks.sort(function(a,b){if(a.source>b.source){return1;}el
我目前有一个Recharts组件,我想将其导出为PNG文件。(this.currentChart=chart)}width={this.state.width}height={this.state.height}data={this.testData}margin={{top:5,right:30,left:20,bottom:5}}>;但我不确定图书馆是否直接支持这一点。我有一个想法,涉及使用Canvas和2D渲染上下文让我接近解决方案,如MDN中所述。但是,我不确定将HTML元素(或React组件)呈现为Canvas以实现此解决方案的通用方法。我可能做错了这一切,我将不胜感激!
我是d3.js的新手,不确定要使用哪个d3功能。我需要围绕原点(在一个圆圈中)同心放置一组元素。svg.selectAll('circle').each(function(){d3.select(this).attr('cx',r*Math.cos(theta)).attr('cy',r*Math.sin(theta));theta+=thetaInc;});所以与其像上面的代码那样做一些乏味的事情,d3的简短方法是什么? 最佳答案 执行此操作的d3方法是传入数据并根据数据的索引计算位置,即类似于vartheta=2*Math.PI
我正在使用FabricJS创建用于绘制特定线条和形状的Canvas。其中一条线是带箭头的波浪线,类似这样:我已经成功地创建了一个带有箭头端点的直线版本,但找不到任何关于如何创建波浪线的示例。用户可以根据需要绘制线,因此线中“峰”和“谷”的数量需要相应地调整(像上图这样的短线可能有4个峰,但两倍长度的线会有8个峰,不仅仅是较短线的拉伸(stretch)版本)。这是我用来绘制带有箭头端点的直线的代码。请注意,线的起点是在mousedown上绘制的,终点是在mouseup上绘制的。importLineWithArrowfrom'./LineWithArrow';drawLineWithArr