可视化计算——数组计算与曲线绘图(下)

我待大计如初恋 大计虐我千万遍

可视化计算——数组计算与曲线绘图(下)

①绘图进阶——单数据柱状图绘制

在日常生活中我们可以获得各种各样的数据,将这些数据填入excel表格就可以利用WPS内置功能画出柱状图,将不太直观的数字转化成可观的图形分析.然而这一过程是如何通过代码实现的呢?

现在我在网上找到了一组数据(如下图,来源非官方),是关于英雄联盟各服务区活跃玩家人数,场次以及参加排位人数的统计(我大LOL永世长存!!(//▲//)).

现在我想把前10个区的总玩家人数做成一张柱状图,首先要提取出数据.这里的数据比较少,所以可以直接手打,如果遇到数据比较多的可以写读取文件数据的代码.

import matplotlib.pyplot as plt
from numpy import *
x='01,02,03,04,05,06,07,08,09,10' #这里以字符串的方式记下来,实际上很多得到的数据都是字符串的形式提取的
y='5548860,3757630,3666841,3462700,3399483,3338007,3213474,2984495,2741270,2679300'
xlabel=x.split(',') #将得到的字符串数据切片得到一个字符串列表
y=[int(e)for e in y.split(',')] #将列表里的字符串强行改变为整数类型
x=range(1,len(xlabel)+1) #使下标与xlabel中的每个数对应
plt.xticks(x,xlabel) #设置x轴的标签文本
plt.axis([0,len(xlabel)+1,2500000,6000000]) #设置坐标轴范围
plt.bar(range(1,len(xlabel)+1),y) #绘制x,y柱状图
plt.show() #展示

效果如下:

关于这段代码需要理解和拓展的点有几个方面:
①split函数
x.split(',')表示将一串字符串x以','为点切开分割成为另一个字符串列表
例如,x='2000年 2001年 2002年',用x.split('年')切开得到x=['2000','2001','2002']
②xticks函数
plt.xticks(x,xlabel,color='b',ratation=40)
其中第一项是坐标轴上的值,第二项是相应标签,第三项是标签的颜色,第四项是倾斜角度(为了避免文字重叠,需要倾斜一定角度)
③bar函数
bar(x,y,width,color='RGB')
其中第一项为横坐标,第二项为纵坐标,第三项为柱的宽度,第四项为柱状图颜色
★④4个与横坐标有关的参数:
四个参数所在的地方:plt.xticks(▲1,▲2);plt.axis([▲3]);plt.bar(▲4,y)
其中,▲1指的是x轴上的具体坐标点,▲2指的是标签列表,▲3指的是整个横坐标范围,▲4指的是柱状图对应的坐标点.在上面例子中:
▲1即x=range(1,len(xlabel)+1)=[1,2,3,4,5,6,7,8,9,10]
▲2即xlabel=['01','02','03','04','05','06','07','08','09','10']
这样即可让标签与x轴上坐标点一一对应
▲3即坐标轴范围[0,11]往往范围比x列表要左右扩大一个单位以让柱状图显示完整
▲4即[1,2,3,4,5,6,7,8,9]这里设置应该与x列表相同,以保证每个柱状图对应相应横坐标,也就对齐了标签,而这里的序号和y列表也是一一对应的(与y列表序号无关,y的第一项与x第一项永远对应)
⑤关于柱状图颜色
在bar函数里用color=''输入颜色对应的RGB值

RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是运用最广的颜色系统之一
——百度百科

在获取我们想要的颜色的RGB值时,我们可以简单地运用各种软件(例如WPS,PS等)自带的吸管,指到某个颜色就会自动告诉你这个颜色的RGB值:

可以看到RGB值由三个部分组成,分别是R值,G值和B值,其间用逗号隔开.但是计算机并不能直接识别RGB值,还需要将数值转化成十六进制的数,这个时候就要用到十六进制系统:
当数字在0-9时用数字表示,当数字在10-15时用a,b,c,d,e,f分别表示10,11,12,13,14,15
转换代码如下(暂且不研究如何转换的):

def rgb2hex(rgbcolor):
    r, g, b = rgbcolor
    return hex((r * 2**16) + (g * 2**8) + b)
# 以空格间隔的RGB三个数字
x = input()
# 根据空格间隔切分输入串,并转为三个数字
x = (int(e) for e in x.split(' '))
# 转换为十六进制格式
print(rgb2hex(x))

例如上图中获得RGB三个值为69 69 93,将这三个值输入,通过上述代码得到一个十六进制的数0x45455d,然后就可以用bar(x,y,color='#45455d')画出相应的颜色
⑥关于汉字字体显示
想要将x轴标签变成中文并且切换字体,就需要利用matplotlib.pylab里的mpl来显示汉字符号,具体操作如下:
from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']

其中SimHei指的是黑体的英文,我在网上查找到了部分不同字体的英文名以及unicode编码如下:

这样就可以将x里的数字修改为文字,并且显示在x轴标签上啦
⑦关于柱状图上方数据显示
我们需要用到的是这两行代码:

for a,b in zip(x,y):
    plt.text(a,b,b,ha='center',va='bottom',fontsize=7)

其中,zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。

plt.text是添加标签,里面内容为plt.text(x, y, string, weight="bold", color="b"),x表示横坐标值,y表示纵坐标值,string是标签内容,weight是注释文本粗细,color是文本颜色, ha='center', va= 'bottom'代表horizontalalignment(水平对齐)、 verticalalignment(垂直对齐)的方式,fontsize则是文字大小
⑧图像翻转
另外,有的时候,图像可能会因为一些原因反过来排列,这样就需要reverse()函数,具体操作为:y.reverse()

现在根据以上拓展修改代码如下:

from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['KaiTi']
import matplotlib.pyplot as plt
from numpy import *
x='艾欧尼亚,德玛西亚,黑色玫瑰,比尔吉沃特,祖安,战争学院,诺克萨斯,班德尔城,弗雷尔卓德,无畏先锋' #这里以字符串的方式记下来,实际上很多得到的数据都是字符串的形式提取的
y='5548860,3757630,3666841,3462700,3399483,3338007,3213474,2984495,2741270,2679300'
y=[int(e)for e in y.split(',')] #将列表里的字符串强行改变为整数类型
xlabel=x.split(',')
x=range(1,len(xlabel)+1) #使下标与xlabel中的每个数对应
for a,b in zip(x,y):
    plt.text(a,b,b,ha='center',va='bottom',fontsize=7)
plt.xticks(x,xlabel,rotation=40) #设置x轴的标签文本
plt.axis([0,len(xlabel)+1,2500000,6000000]) #设置坐标轴范围
plt.bar(range(1,len(xlabel)+1),y,color='#45455d') #绘制x,y柱状图
plt.ylabel('总玩家人数')
plt.xlabel('前10服务区名

就可以得到我们想要的效果:

(下面部分因为汉字太长了显示不出来,可以调小倾斜角度)

②绘图进阶——多数据柱状图绘制

当我绘制好“总玩家人数”的柱状图后,就想把“总比赛场次也加入进来”,但是直接添加一段类似的bar代码会导致两个柱状图重叠!

现在我们就需要将两个柱状图错位,错位的原理就是利用柱状图对应的横坐标,将其中一组数据对应的坐标改为奇数,另一组对应的坐标改为偶数:

from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['KaiTi']
import matplotlib.pyplot as plt
from numpy import *
x='艾欧尼亚,德玛西亚,黑色玫瑰,比尔吉沃特,祖安,战争学院,诺克萨斯,班德尔城,弗雷尔卓德,无畏先锋' 
y1='5548860,3757630,3666841,3462700,3399483,3338007,3213474,2984495,2741270,2679300'
y2='17946640,8691211,7706943,8543282,15704959,12590273,15014668,15435599,7334502,6751726'
y1=[int(e)for e in y1.split(',')]
y2=[int(e)for e in y2.split(',')]
xlabel=x.split(',')
x=arange(1,len(xlabel)+1) #因为要对数据向量化计算,所以改为生成数组而非列表
for a,b in zip(2*x,y1):   #在偶数横坐标处生成第一组上标
    plt.text(a,b,b,ha='center',va='bottom',fontsize=7)
for p,q in zip(2*x-1,y2): #在奇数横坐标处生成第二组上标
    plt.text(p,q,q,ha='center',va='bottom',fontsize=7)
plt.xticks(2*x,xlabel,rotation=40) #横坐标标签对应在偶数位置
plt.axis([0,2*len(x)+1,2500000,20000000]) #将数轴范围扩大2倍
plt.bar(2*x,y1,color='#87cefa') #第一组图画在偶数位置
plt.bar(2*x-1,y2,color='#ff7f50') #第二组图画在奇数位置
plt.ylabel('总玩家人数&总比赛场次')
plt.xlabel('前10服务区名称')
plt.show() 

但是我发现输出的柱状图相邻间隔相同,没有区分出两个不同服务区,这个时候我们需要用到width调整柱状图宽度:

from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['KaiTi']
import matplotlib.pyplot as plt
from numpy import *
x='艾欧尼亚,德玛西亚,黑色玫瑰,比尔吉沃特,祖安,战争学院,诺克萨斯,班德尔城,弗雷尔卓德,无畏先锋'
y1='5548860,3757630,3666841,3462700,3399483,3338007,3213474,2984495,2741270,2679300'
y2='17946640,8691211,7706943,8543282,15704959,12590273,15014668,15435599,7334502,6751726'
labels = [u'总玩家人数', u'总比赛场次']
y1=[int(e)for e in y1.split(',')] 
y2=[int(e)for e in y2.split(',')]
xlabel=x.split(',')
x=arange(1,len(xlabel)+1) 
w=0.5 #将柱状图宽度值设为0.5
for a,b in zip(2*x-1+w,y1): #x轴横坐标均与下方bar里面的横坐标相同
    plt.text(a,b,b,ha='center',va='bottom',fontsize=7)
for p,q in zip(2*x-1,y2):
    plt.text(p,q,q,ha='center',va='bottom',fontsize=7)
plt.xticks(2*x-1,xlabel,rotation=40) 
plt.axis([0,2*len(x)+1,2500000,20000000]) 
plt.bar(2*x-1+w,y1,width=0.5,color='#87cefa') #以2*x-1为标准,在其基础上加上宽度值,表示在上个柱状图后紧邻地画下一个柱状图
plt.bar(2*x-1,y2,width=0.5,color='#ff7f50')  
plt.ylabel('总玩家人数&总比赛场次')
plt.xlabel('前10服务区名称')
plt.legend(labels,loc='upper center')
plt.show()

这样我们就可以输出双数据柱状图了:

但是我仍不满足,想加入第三个数据“参数排位人数”.难道我也是一样创建一个y3继续重复之前的操作吗?有没有更简单的一套代码可以运用到三个以及更多的数据上?

以下我们运用for循环实现对多组数据的绘制:

from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['KaiTi']
import matplotlib.pyplot as plt
from numpy import *
n=3   #设置数据组数为n=3组
y=['']*n   #创建n个列表
x='艾欧尼亚,德玛西亚,黑色玫瑰,比尔吉沃特,祖安,战争学院,诺克萨斯,班德尔城,弗雷尔卓德,无畏先锋'
y[0]='5548860,3757630,3666841,3462700,3399483,3338007,3213474,2984495,2741270,2679300'
y[1]='17946640,8691211,7706943,8543282,15704959,12590273,15014668,15435599,7334502,6751726'
y[2]='1557607,1405400,1218687,1272583,1170444,1193278,1160301,1133985,947901,844207'
xlabel=x.split(',')
x=arange(1,len(xlabel)+1) 
plt.xticks(n*x-(n-1),xlabel,rotation=40)  
plt.axis([0,n*len(x)+1,800000,20000000]) 
w=0.5 
color=['#87cefa','#ff7f50','#45455d']   #创建柱状图颜色列表
for i in range(n):
    y[i]=[int(e)for e in y[i].split(',')] 
    plt.bar(n*x-(n-1)+i*w,y[i],width=w,color=color[i])   #起始点为n*x-(n-1)之后下标每+1就加上一个w
    for a,b in zip(n*x-(n-1)+i*w,y[i]):
        plt.text(a,b,b,ha='center',va='bottom',fontsize=7)
plt.ylabel('总玩家人数&总比赛场次&参数排位人数')
plt.xlabel('前10服务区名称')
labels = [u'总玩家人数', u'总比赛场次',u'参数排位人数']
plt.legend(labels,loc='upper center')
plt.show()

这样我们就可以得到三组及三组以上的柱状图了!(效果如下↓)

②绘图进阶——饼状图绘制

现在我们考虑将总玩家人数制作成为一个饼状图.

from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['KaiTi'] #让中文可以显示
import matplotlib.pyplot as plt
x='艾欧尼亚,德玛西亚,黑色玫瑰,比尔吉沃特,祖安,战争学院,诺克萨斯,班德尔城,弗雷尔卓德,无畏先锋'
xlabel=x.split(',')
y='5548860,3757630,3666841,3462700,3399483,3338007,3213474,2984495,2741270,2679300'
sizes=y.split(',')
color=['red','orange','yellow','green','purple','blue','black','#45455d','#87cefa','#ff7f50']  #不同饼的颜色
explode=[0,0,0,0,0.2,0,0,0,0,0]    #偏移量,0代表没有偏移,大于0则饼图向外偏移
plt.pie(sizes,explode=explode,colors=color,labels=xlabel,shadow=True,autopct='%1.1f%%',startangle=90)
#sizes是数据的列表,explode是偏移量列表,colors是颜色列表,labels是标签列表
#shadow=True表示打开阴影,autopct='%1.1f%%'表示显示以小数点后一位显示每块饼所占的百分比,startangle表示旋转的角度
plt.axis('equal')  #用于显示一个长宽相等的饼图
plt.show()

效果如下:

假如我们想制作两副饼图,一幅是总玩家人数,一幅是总比赛场次,并且将结果打印在一张画布上,则我们需要用到figure函数.

from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['KaiTi']
import matplotlib.pyplot as plt
plt.figure(figsize=[14,5])      #设置一张宽14高5的画布
x='艾欧尼亚,德玛西亚,黑色玫瑰,比尔吉沃特,祖安,战争学院,诺克萨斯,班德尔城,弗雷尔卓德,无畏先锋'
xlabel=x.split(',')
y1='5548860,3757630,3666841,3462700,3399483,3338007,3213474,2984495,2741270,2679300'
y2='17946640,8691211,7706943,8543282,15704959,12590273,15014668,15435599,7334502,6751726'
y1=y1.split(',')
y2=y2.split(',')
m1='总玩家人数'
m2='总比赛场次'
color=['red','orange','yellow','green','purple','blue','black','#45455d','#87cefa','#ff7f50']
explode=[0,0,0,0,0.2,0,0,0,0,0]
plt.subplot(121)         #绘图区域被分为1行2列,并且下面绘制第1幅图
plt.pie(y1,explode=explode,colors=color,labels=xlabel,shadow=True,autopct='%1.1f%%',startangle=90)
plt.title(m1)            #打上饼图标题
plt.subplot(122)         #下面绘制第2幅图
plt.pie(y2,explode=explode,colors=color,labels=xlabel,shadow=True,autopct='%1.1f%%',startangle=90)
plt.title(m2)
plt.axis('equal')
plt.show()

我们可以得到如下效果:

目前就学到了柱状图和饼状图的绘制,其实有更多的图形可以用python绘制,甚至三维的立体图形也不在话下,在博客园里有很多大佬在这方面都有博客可以学习.

“可视化计算——数组计算与曲线绘图”笔记并没有完结,敬请期待下次更博!(//▲//)

posted @ 2020-11-26 17:27  谦与签寻  阅读(195)  评论(0编辑  收藏  举报