看本文前,请看matlplotlib使用教程 https://blog.csdn.net/kun1280437633/article/details/80370622,有基础请忽略
一、简单垂直条形图
案例一:直辖市GDP水平
中国的四个直辖市分别为北京市、上海市、天津市和重庆市,其2017年上半年的GDP分别为12406.8亿、13908.57亿、9386.87亿、9143.64亿。对于这样一组数据,我们该如何使用条形图来展示各自的GDP水平呢?
# 导入绘图模块
import matplotlib.pyplot as plt
# 构建数据
GDP = [12406.8,13908.57,9386.87,9143.64]
# 中文乱码的处理
plt.rcParams['font.sans-serif'] =['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 绘图
plt.bar(range(4), GDP, align = 'center',color='steelblue', alpha = 0.8)
# 添加轴标签
plt.ylabel('GDP')
# 添加标题
plt.title('四个直辖市GDP大比拼')
# 添加刻度标签
plt.xticks(range(4),['北京市','上海市','天津市','重庆市'])
# 设置Y轴的刻度范围
plt.ylim([5000,15000])
# 为每个条形图添加数值标签
for x,y in enumerate(GDP):
plt.text(x,y+100,'%s' %round(y,1),ha='center')
# 显示图形
plt.show()
代码解读
由于matplotlib对中文的支持并不是很友好,所以需要提前对绘图进行字体的设置,即通过rcParams来设置字体,这里将字体设置为微软雅黑,同时为了避免坐标轴不能正常的显示负号,也需要进行设置;
bar函数指定了条形图的x轴、y轴值,设置x轴刻度标签为水平居中,条形图的填充色color为铁蓝色,同时设置透明度alpha为0.8;
添加y轴标签、标题、x轴刻度标签值,为了让条形图显示各柱体之间的差异,将y轴范围设置在5000~15000;
通过循环的方式,添加条形图的数值标签;
案例二:同一本书不同平台最低价比较
很多人在买一本书的时候,都比较喜欢货比三家,例如《python数据分析实战》在亚马逊、当当网、中国图书网、京东和天猫的最低价格分别为39.5、39.9、45.4、38.9、33.34。针对这个数据,我们也可以通过条形图来完成,这里使用水平条形图来显示:
# 导入绘图模块
import matplotlib.pyplot as plt
# 构建数据
price = [39.5,39.9,45.4,38.9,33.34]
# 中文乱码的处理
plt.rcParams['font.sans-serif'] =['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 绘图
plt.barh(range(5), price, align = 'center',color='steelblue', alpha = 0.8)
# 添加轴标签
plt.xlabel('价格')
# 添加标题
plt.title('不同平台书的最低价比较')
# 添加刻度标签
plt.yticks(range(5),['亚马逊','当当网','中国图书网','京东','天猫'])
# 设置Y轴的刻度范围
plt.xlim([32,47])
# 为每个条形图添加数值标签
for x,y in enumerate(price):
plt.text(y+0.1,x,'%s' %y,va='center')
# 显示图形
plt.show()
代码解读
水平条形图的绘制与垂直条形图的绘制步骤一致,只是调用了barh函数来完成。需要注意的是,条形图的数值标签设置有一些不一样,需要将标签垂直居中显示,使用va参数即可。
以上讲的简单垂直和水平条形图是基于一种离散变量的情况,针对两种离散变量的条形图我们可以使用水平交错条形图和堆叠条形图,下面我们就来看看这两种条形图是如何绘制的。
案例三:胡润财富榜:亿万资产超高净值家庭数
利用水平交错条形图对比2016年和2017年亿万资产超高净值家庭数(top5),其数据如下:
# 导入绘图模块
import matplotlib.pyplot as pltimport numpy as np
# 构建数据Y2016 = [15600,12700,11300,4270,3620]
Y2017 = [17400,14800,12000,5200,4020]
labels = ['北京','上海','香港','深圳','广州']
bar_width = 0.45
# 中文乱码的处理
plt.rcParams['font.sans-serif'] =['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 绘图
plt.bar(np.arange(5), Y2016, label = '2016', color = 'steelblue', alpha = 0.8, width = bar_width)
plt.bar(np.arange(5)+bar_width, Y2017, label = '2017', color = 'indianred', alpha = 0.8, width = bar_width)
# 添加轴标签
plt.xlabel('Top5城市')
plt.ylabel('家庭数量')
# 添加标题
plt.title('亿万财富家庭数Top5城市分布')
# 添加刻度标签
plt.xticks(np.arange(5)+bar_width,labels)
# 设置Y轴的刻度范围
plt.ylim([2500, 19000])
# 为每个条形图添加数值标签
for x2016,y2016 in enumerate(Y2016):
plt.text(x2016, y2016+100, '%s' %y2016)
for x2017,y2017 in enumerate(Y2017):
plt.text(x2017+bar_width, y2017+100, '%s' %y2017)
# 显示图例
plt.legend()
# 显示图形
plt.show()
代码解读
水平交错条形图绘制的思想很简单,就是在第一个条形图绘制好的基础上,往左移一定的距离,再去绘制第二个条形图,所以在代码中会出现两个bar函数;
图例的绘制需要在bar函数中添加label参数;color和alpha参数分别代表条形图的填充色和透明度;
给条形图添加数值标签,同样需要使用两次for循环的方式实现;
垂直堆叠条形图的绘制思想与水平交错条形图一样,只不过一个是向上偏移,一个是往左偏移,具体我们以案例说明。
案例四:2017年物流运输量情况分布
# 导入模块
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 导入数据
data = pd.read_excel('C:\\Users\\Administrator\\Desktop\\货运.xls')
# 绘图
plt.bar(np.arange(8), data.loc[0,:][1:], color = 'red', alpha = 0.8, label = '铁路', align = 'center')
plt.bar(np.arange(8), data.loc[1,:][1:], bottom = data.loc[0,:][1:], color = 'green', alpha = 0.8, label = '公路', align = 'center')
plt.bar(np.arange(8), data.loc[2,:][1:], bottom = data.loc[0,:][1:]+data.loc[1,:][1:], color = 'm', alpha = 0.8, label = '水运', align = 'center')
plt.bar(np.arange(8), data.loc[3,:][1:], bottom = data.loc[0,:][1:]+data.loc[1,:][1:]+data.loc[2,:][1:], color = 'black', alpha = 0.8, label = '民航', align = 'center')
# 添加轴标签
plt.xlabel('月份')
plt.ylabel('货物量(万吨)')
# 添加标题
plt.title('2017年各月份物流运输量')
# 添加刻度标签
plt.xticks(np.arange(8),data.columns[1:])
# 设置Y轴的刻度范围
plt.ylim([0,500000])
# 为每个条形图添加数值标签
for x_t,y_t in enumerate(data.loc[0,:][1:]):
plt.text(x_t,y_t/2,'%sW' %(round(y_t/10000,2)),ha='center', color = 'white')
for x_g,y_g in enumerate(data.loc[0,:][1:]+data.loc[1,:][1:]):
plt.text(x_g,y_g/2,'%sW' %(round(y_g/10000,2)),ha='center', color = 'white')
for x_s,y_s in enumerate(data.loc[0,:][1:]+data.loc[1,:][1:]+data.loc[2,:][1:]):
plt.text(x_s,y_s-20000,'%sW' %(round(y_s/10000,2)),ha='center', color = 'white')
# 显示图例
plt.legend(loc='upper center', ncol=4)
# 显示图形
plt.show()
代码解读
垂直条形图的绘制不仅仅需要提供x,y轴的数值,还需要提供bottom参数,其目的就是在某个条形图顶端的基础上,绘制其他条形图,以此类推可以绘制多个堆叠条形图;
图例的位置选择在了正上方,且设置列数为4,表面图例以一排的形式展现;
堆叠条形图的数值标签,任然是按照y轴方向堆叠的思想,贴上数值标签值;
由于航空运输的货物量非常少,导致图中几乎无法显示;
我们用条形图来展示离散变量的分布呈现,在常见的统计图像中,还有一种图像可以表示离散变量各水平占比情况,这就是我们要讲解的饼图。饼图的绘制可以使用matplotlib库中的pie函数,首先我们来看看这个函数的参数说明。
plt.pie(x, explode=None, labels=None, colors=None,
autopct=None, pctdistance=0.6, shadow=False,
labeldistance=1.1, startangle=None,
radius=None, counterclock=True, wedgeprops=None,
textprops=None, center=(0, 0), frame=False)
x:指定绘图的数据;
explode:指定饼图某些部分的突出显示,即呈现爆炸式;
labels:为饼图添加标签说明,类似于图例说明;
colors:指定饼图的填充色;
autopct:自动添加百分比显示,可以采用格式化的方法显示;
pctdistance:设置百分比标签与圆心的距离;
shadow:是否添加饼图的阴影效果;
labeldistance:设置各扇形标签(图例)与圆心的距离;
startangle:设置饼图的初始摆放角度;
radius:设置饼图的半径大小;
counterclock:是否让饼图按逆时针顺序呈现;
wedgeprops:设置饼图内外边界的属性,如边界线的粗细、颜色等;
textprops:设置饼图中文本的属性,如字体大小、颜色等;
center:指定饼图的中心点位置,默认为原点
frame:是否要显示饼图背后的图框,如果设置为True的话,需要同时控制图框x轴、y轴的范围和饼图的中心位置;
案例:芝麻信用失信用户分析
关于pie函数的参数我们讲了这么多,光讲不练假把式,我们接下来通过案例,来绘制一个个性化的饼图。关于绘图数据,我们借用芝麻信用近300万失信人群的样本统计数据,该数据显示,从受教育水平上来看,中专占比25.15%,大专占比37.24%,本科占比33.36%,硕士占比3.68%,剩余的其他学历占比0.57%。对于这样一组数据,我们该如何使用饼图来呈现呢?
# 导入第三方模块
import matplotlib.pyplot as plt
# 设置绘图的主题风格(不妨使用R中的ggplot分隔)
plt.style.use('ggplot')
# 构造数据
edu = [0.2515,0.3724,0.3336,0.0368,0.0057]
labels = ['中专','大专','本科','硕士','其他']
explode = [0,0.1,0,0,0] # 用于突出显示大专学历人群
colors=['#9999ff','#ff9999','#7777aa','#2442aa','#dd5555'] # 自定义颜色
# 中文乱码和坐标轴负号的处理
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 将横、纵坐标轴标准化处理,保证饼图是一个正圆,否则为椭圆
plt.axes(aspect='equal')
# 控制x轴和y轴的范围
plt.xlim(0,4)
plt.ylim(0,4)
# 绘制饼图
plt.pie(x = edu, # 绘图数据
explode=explode, # 突出显示大专人群
labels=labels, # 添加教育水平标签
colors=colors, # 设置饼图的自定义填充色
autopct='%.1f%%', # 设置百分比的格式,这里保留一位小数
pctdistance=0.8, # 设置百分比标签与圆心的距离
labeldistance = 1.15, # 设置教育水平标签与圆心的距离
startangle = 180, # 设置饼图的初始角度
radius = 1.5, # 设置饼图的半径
counterclock = False, # 是否逆时针,这里设置为顺时针方向
wedgeprops = {'linewidth': 1.5, 'edgecolor':'green'},# 设置饼图内外边界的属性值
textprops = {'fontsize':12, 'color':'k'}, # 设置文本标签的属性值
center = (1.8,1.8), # 设置饼图的原点
frame = 1 )# 是否显示饼图的图框,这里设置显示
# 删除x轴和y轴的刻度
plt.xticks(())
plt.yticks(())
# 添加图标题
plt.title('芝麻信用失信用户教育水平分布')
# 显示图形
plt.show()
针对离散变量我们可以使用常见的条形图和饼图完成数据的可视化工作,那么,针对数值型变量,我们也有很多可视化的方法,例如箱线图、直方图、折线图、面积图、散点图等等。这一期,我们就先来介绍一下数值型变量的箱线图绘制。箱线图一般用来展现数据的分布(如上下四分位值、中位数等),同时,也可以用箱线图来反映数据的异常情况。
绘图之前,我们先来讲解一下matplotlib包中boxplot函数的参数含义及使用方法:
plt.boxplot(x, notch=None, sym=None, vert=None,
whis=None, positions=None, widths=None,
patch_artist=None, meanline=None, showmeans=None,
showcaps=None, showbox=None, showfliers=None,
boxprops=None, labels=None, flierprops=None,
medianprops=None, meanprops=None,
capprops=None, whiskerprops=None)
x:指定要绘制箱线图的数据;
notch:是否是凹口的形式展现箱线图,默认非凹口;
sym:指定异常点的形状,默认为+号显示;
vert:是否需要将箱线图垂直摆放,默认垂直摆放;
whis:指定上下须与上下四分位的距离,默认为1.5倍的四分位差;
positions:指定箱线图的位置,默认为[0,1,2…];
widths:指定箱线图的宽度,默认为0.5;
patch_artist:是否填充箱体的颜色;
meanline:是否用线的形式表示均值,默认用点来表示;
showmeans:是否显示均值,默认不显示;
showcaps:是否显示箱线图顶端和末端的两条线,默认显示;
showbox:是否显示箱线图的箱体,默认显示;
showfliers:是否显示异常值,默认显示;
boxprops:设置箱体的属性,如边框色,填充色等;
labels:为箱线图添加标签,类似于图例的作用;
filerprops:设置异常值的属性,如异常点的形状、大小、填充色等;
medianprops:设置中位数的属性,如线的类型、粗细等;
meanprops:设置均值的属性,如点的大小、颜色等;
capprops:设置箱线图顶端和末端线条的属性,如颜色、粗细等;
whiskerprops:设置须的属性,如颜色、粗细、线的类型等;
案例:titanic:不同等级仓位的年龄箱线图
整体乘客的年龄箱线图
# 导入第三方模块
import pandas as pd
import matplotlib.pyplot as plt
# 读取Titanic数据集
titanic = pd.read_csv('titanic_train.csv')
# 检查年龄是否有缺失
any(titanic.Age.isnull())
# 不妨删除含有缺失年龄的观察
titanic.dropna(subset=['Age'], inplace=True)
# 设置图形的显示风格
plt.style.use('ggplot')
# 设置中文和负号正常显示
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
# 绘图:整体乘客的年龄箱线图
plt.boxplot(x = titanic.Age, # 指定绘图数据
patch_artist=True, # 要求用自定义颜色填充盒形图,默认白色填充
showmeans=True, # 以点的形式显示均值
boxprops = {'color':'black','facecolor':'#9999ff'}, # 设置箱体属性,填充色和边框色
flierprops = {'marker':'o','markerfacecolor':'red','color':'black'}, # 设置异常值属性,点的形状、填充色和边框色
meanprops = {'marker':'D','markerfacecolor':'indianred'}, # 设置均值点的属性,点的形状、填充色
medianprops = {'linestyle':'--','color':'orange'}) # 设置中位数线的属性,线的类型和颜色
# 设置y轴的范围
plt.ylim(0,85)
# 去除箱线图的上边框与右边框的刻度标签
plt.tick_params(top='off', right='off')
# 显示图形
plt.show()
对于所有乘客而言,从图中容易发现,乘客的平均年龄在30岁,有四分之一的人低于20岁,另有四分之一的人超过38岁,换句话说,有一半的人,年龄落在20~38岁之间;从均值(红色的菱形)略高于中位数(黄色虚线)来看,说明年龄是有偏的,并且是右偏;同时,我们也会发现一些红色的异常值,这些异常值的年龄均在64岁以上。
不同等级仓的年龄箱线图
# 按舱级排序,为了后面正常显示分组盒形图的顺序
titanic.sort_values(by = 'Pclass', inplace=True)
# 通过for循环将不同仓位的年龄人群分别存储到列表Age变量中
Age = []
Levels = titanic.Pclass.unique()
for Pclass in Levels:
Age.append(titanic.loc[titanic.Pclass==Pclass,'Age'])
# 绘图
plt.boxplot(x = Age,
patch_artist=True,
labels = ['一等舱','二等舱','三等舱'], # 添加具体的标签名称
showmeans=True,
boxprops = {'color':'black','facecolor':'#9999ff'},
flierprops = {'marker':'o','markerfacecolor':'red','color':'black'},
meanprops = {'marker':'D','markerfacecolor':'indianred'},
medianprops = {'linestyle':'--','color':'orange'})
# 显示图形
plt.show()
如果对人群的年龄按不同的舱位来看,我们会发现一个明显的趋势,就是舱位等级越高的乘客,他们的年龄越高,三种舱位的平均年龄为38、30和25,说明年龄越是偏大一点,他们的经济能力会越强一些,所买的舱位等级可能就会越高一些。同时,在二等舱和三等舱内,乘客的年龄上存在一些异常用户。
我们仔细的讲解了如何绘制数值型变量的箱线图,展现数据的分布,我们还可以使用直方图来说明,同过图形的长相,就可以快速的判断数据是否近似服从正态分布。之所以我们很关心数据的分布,是因为在统计学中,很多假设条件都会包括正态分布,故使用直方图来定性的判定数据的分布情况,尤其显得重要。这期我们就来介绍Python中如何绘制一个直方图。
绘图之前,我们先来讲解一下matplotlib包中hist函数的参数含义及使用方法:
plt.hist(x, bins=10, range=None, normed=False,
weights=None, cumulative=False, bottom=None,
histtype='bar', align='mid', orientation='vertical',
rwidth=None, log=False, color=None,
label=None, stacked=False)
x:指定要绘制直方图的数据;
bins:指定直方图条形的个数;
range:指定直方图数据的上下界,默认包含绘图数据的最大值和最小值;
normed:是否将直方图的频数转换成频率;
weights:该参数可为每一个数据点设置权重;
cumulative:是否需要计算累计频数或频率;
bottom:可以为直方图的每个条形添加基准线,默认为0;
histtype:指定直方图的类型,默认为bar,除此还有’barstacked’, ‘step’, ‘stepfilled’;
align:设置条形边界值的对其方式,默认为mid,除此还有’left’和’right’;
orientation:设置直方图的摆放方向,默认为垂直方向;
rwidth:设置直方图条形宽度的百分比;
log:是否需要对绘图数据进行log变换;
color:设置直方图的填充色;
label:设置直方图的标签,可通过legend展示其图例;
stacked:当有多个数据时,是否需要将直方图呈堆叠摆放,默认水平摆放;
案例:titanic数据集
整体乘客的年龄直方图
# 导入第三方包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
# 中文和负号的正常显示
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 读取Titanic数据集
titanic = pd.read_csv('titanic_train.csv')
# 检查年龄是否有缺失any(titanic.Age.isnull())
# 不妨删除含有缺失年龄的观察
titanic.dropna(subset=['Age'], inplace=True)
# 设置图形的显示风格
plt.style.use('ggplot')
# 绘图:乘客年龄的频数直方图
plt.hist(titanic.Age, # 绘图数据
bins = 20, # 指定直方图的条形数为20个
color = 'steelblue', # 指定填充色
edgecolor = 'k', # 指定直方图的边界色
label = '直方图' )# 为直方图呈现标签
# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')
# 显示图例
plt.legend()
# 显示图形
plt.show()
上图绘制的是年龄的频数直方图,从整体的分布来看,有点像正态分布,两边低中间高的倒钟形状。除此,我们还可以绘制累计频率直方图,并且设置5岁为组距,如下代码可以表示成:
# 绘图:乘客年龄的累计频率直方图
plt.hist(titanic.Age, # 绘图数据
bins = np.arange(titanic.Age.min(),titanic.Age.max(),5), # 指定直方图的组距
normed = True, # 设置为频率直方图
cumulative = True, # 积累直方图
color = 'steelblue', # 指定填充色
edgecolor = 'k', # 指定直方图的边界色
label = '直方图' )# 为直方图呈现标签
# 设置坐标轴标签和标题
plt.title('乘客年龄的频率累计直方图')
plt.xlabel('年龄')
plt.ylabel('累计频率')
# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')
# 显示图例
plt.legend(loc = 'best')
# 显示图形
plt.show()
通过累计频率直方图就可以快速的发现什么年龄段的人数占了多少比重,例如35岁以下的乘客占了7成,这种图的解读有点像帕累托图。为了测试数据集是否近似服从正态分布,需要在直方图的基础上再绘制两条线,一条表示理论的正态分布曲线,另一条为核密度曲线,目的就是比较两条曲线的吻合度,越吻合就说明数据越近似于正态分布。接下来我们就在直方图的基础上再添加两条曲线:
# 正太分布图
plt.hist(titanic.Age, # 绘图数据
bins = np.arange(titanic.Age.min(),titanic.Age.max(),5), # 指定直方图的组距
normed = True, # 设置为频率直方图
color = 'steelblue', # 指定填充色
edgecolor = 'k') # 指定直方图的边界色
# 设置坐标轴标签和标题
plt.title('乘客年龄直方图')
plt.xlabel('年龄')
plt.ylabel('频率')
# 生成正态曲线的数据
x1 = np.linspace(titanic.Age.min(), titanic.Age.max(), 1000)
normal = mlab.normpdf(x1, titanic.Age.mean(), titanic.Age.std())
# 绘制正态分布曲线
line1, = plt.plot(x1,normal,'r-', linewidth = 2)
# 生成核密度曲线的数据
kde = mlab.GaussianKDE(titanic.Age)
x2 = np.linspace(titanic.Age.min(), titanic.Age.max(), 1000)
# 绘制
line2, = plt.plot(x2,kde(x2),'g-', linewidth = 2)
# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')
# 显示图例
plt.legend([line1, line2],['正态分布曲线','核密度曲线'],loc='best')
# 显示图形
plt.show()
从直方图的展现来看,乘客的年龄分布与理论正态分布曲线存在一些差异,说明不服从正态分布,而且从图中也能看见,年龄呈现右偏的特征。
上面绘制的直方图都是基于所有乘客的年龄,如果想对比男女乘客的年龄直方图的话,我们可以通过两个hist将不同性别的直方图绘制到一张图内,具体代码如下:
# 提取不同性别的年龄数据
age_female = titanic.Age[titanic.Sex == 'female']
age_male = titanic.Age[titanic.Sex == 'male']
# 设置直方图的组距
bins = np.arange(titanic.Age.min(), titanic.Age.max(), 2)
# 男性乘客年龄直方图
plt.hist(age_male, bins = bins, label = '男性', color = 'steelblue', alpha = 0.7)
# 女性乘客年龄直方图plt.hist(age_female, bins = bins, label = '女性', alpha = 0.6)
# 设置坐标轴标签和标题
plt.title('乘客年龄直方图')
plt.xlabel('年龄')
plt.ylabel('人数')
# 去除图形顶部边界和右边界的刻度
plt.tick_params(top='off', right='off')
# 显示图例
plt.legend()
# 显示图形
plt.show()
图中结果反映了,不同年龄组内几乎都是男性乘客比女性乘客要多;同时,也说明男女性别的年龄组分布几乎一致。
讲解一下关于折线图的绘制,折线图一般是用来表示某个数值变量随着时间的推移而形成的趋势,这种图还是比较常见的,如经济走势图、销售波动图、PV监控图等。在Python的matplotlib模块中,我们可以调用plot函数就能实现折线图的绘制了,先来看看这个函数的一些参数含义。
matplotlib模块中plot函数语法及参数含义:
plt.hist(x,y,linestyle,
linewidth,color,marker,
markersize,markeredgecolor,
markerfactcolor,label,alpha)
x:指定折线图的x轴数据;
y:指定折线图的y轴数据;
linestyle:指定折线的类型,可以是实线、虚线、点虚线、点点线等,默认文实线;
linewidth:指定折线的宽度
marker:可以为折线图添加点,该参数是设置点的形状;
markersize:设置点的大小;
markeredgecolor:设置点的边框色;
markerfactcolor:设置点的填充色;
label:为折线图添加标签,类似于图例的作用;
案例:每天进步一点点2015公众号文章阅读人数
# 导入模块
import pandas as pd
import matplotlib.pyplot as plt
# 设置绘图风格
plt.style.use('ggplot')
# 设置中文编码和负号的正常显示
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
# 读取需要绘图的数据
article_reading = pd.read_excel('wechart.xlsx')
# 取出8月份至9月28日的数据
sub_data = article_reading.loc[article_reading.date >= '2017-08-01' ,:]
# 设置图框的大小
fig = plt.figure(figsize=(10,6))
# 绘图
plt.plot(sub_data.date, # x轴数据
sub_data.article_reading_cnts, # y轴数据
linestyle = '-', # 折线类型
linewidth = 2, # 折线宽度
color = 'steelblue', # 折线颜色
marker = 'o', # 点的形状
markersize = 6, # 点的大小
markeredgecolor='black', # 点的边框色
markerfacecolor='brown') # 点的填充色
# 添加标题和坐标轴标签
plt.title('公众号每天阅读人数趋势图')
plt.xlabel('日期')
plt.ylabel('人数')
# 剔除图框上边界和右边界的刻度
plt.tick_params(top = 'off', right = 'off')
# 为了避免x轴日期刻度标签的重叠,设置x轴刻度自动展现,并且45度倾斜
fig.autofmt_xdate(rotation = 45)
# 显示图形
plt.show()
由于x轴是日期型数据,当数据量一多的时候,就会导致刻度标签的重叠或拥挤,为了防止重叠的产生,我们需要让日期型的x轴刻度标签自动展现,从而避免重叠的现象。下面两幅图是对比自动刻度标签的前后变化:
可能你并不满足这样的刻度标签展现形式,你想以个性化的展现方式,如“YYYY-MM-DD”的显示方式,同时又想以固定的几天作为间隔,这样的设置又该如何实现?其实非常的简单,只需要在上面代码的基础上添加几行代码就可以轻松搞定。
# 导入模块
import matplotlib as mpl
# 设置图框的大小
fig = plt.figure(figsize=(10,6))
# 绘图
plt.plot(sub_data.date, # x轴数据
sub_data.article_reading_cnts, # y轴数据
linestyle = '-', # 折线类型
linewidth = 2, # 折线宽度
color = 'steelblue', # 折线颜色
marker = 'o', # 点的形状
markersize = 6, # 点的大小
markeredgecolor='black', # 点的边框色
markerfacecolor='steelblue') # 点的填充色
# 添加标题和坐标轴标签
plt.title('公众号每天阅读人数趋势图')
plt.xlabel('日期')
plt.ylabel('人数')
# 剔除图框上边界和右边界的刻度
plt.tick_params(top = 'off', right = 'off')
# 获取图的坐标信息
ax = plt.gca()
# 设置日期的显示格式
date_format = mpl.dates.DateFormatter("%Y-%m-%d")
ax.xaxis.set_major_formatter(date_format)
# 设置x轴显示多少个日期刻度
#xlocator = mpl.ticker.LinearLocator(10)
# 设置x轴每个刻度的间隔天数
xlocator = mpl.ticker.MultipleLocator(5)
ax.xaxis.set_major_locator(xlocator)
# 为了避免x轴日期刻度标签的重叠,设置x轴刻度自动展现,并且45度倾斜
fig.autofmt_xdate(rotation = 45)
# 显示图形
plt.show()
如果你需要在一张图形中画上两条折线图,也很简单,只需要在代码中写入两次plot函数即可,其他都不需要改动了。具体可以参考下面的代码逻辑:
# 设置图框的大小
fig = plt.figure(figsize=(10,6))
# 绘图--阅读人数趋势
plt.plot(sub_data.date, # x轴数据
sub_data.article_reading_cnts, # y轴数据
linestyle = '-', # 折线类型
linewidth = 2, # 折线宽度
color = 'steelblue', # 折线颜色
marker = 'o', # 点的形状
markersize = 6, # 点的大小
markeredgecolor='black', # 点的边框色
markerfacecolor='steelblue', # 点的填充色
label = '阅读人数') # 添加标签
# 绘图--阅读人次趋势
plt.plot(sub_data.date, # x轴数据
sub_data.article_reading_times, # y轴数据
linestyle = '-', # 折线类型
linewidth = 2, # 折线宽度
color = '#ff9999', # 折线颜色
marker = 'o', # 点的形状
markersize = 6, # 点的大小
markeredgecolor='black', # 点的边框色
markerfacecolor='#ff9999', # 点的填充色
label = '阅读人次') # 添加标签
# 添加标题和坐标轴标签
plt.title('公众号每天阅读人数和人次趋势图')
plt.xlabel('日期')
plt.ylabel('人数')
# 剔除图框上边界和右边界的刻度
plt.tick_params(top = 'off', right = 'off')
# 获取图的坐标信息
ax = plt.gca()
# 设置日期的显示格式
date_format = mpl.dates.DateFormatter('%m-%d')
ax.xaxis.set_major_formatter(date_format)
# 设置x轴显示多少个日期刻度
#xlocator = mpl.ticker.LinearLocator(10)
# 设置x轴每个刻度的间隔天数
xlocator = mpl.ticker.MultipleLocator(3)
ax.xaxis.set_major_locator(xlocator)
# 为了避免x轴日期刻度标签的重叠,设置x轴刻度自动展现,并且45度倾斜
fig.autofmt_xdate(rotation = 45)
# 显示图例
plt.legend()
# 显示图形
plt.show()
两条折线图很完美的展现在一张图中,公众号的阅读人数与人次趋势完全一致,而且具有一定的周期性,即过几天就会有一个大幅上升的波动,这个主要是由于双休日的时候,时间比较空闲,就可以更新并推送文章了。
我们通过折线图可以快速的发现时间序列的趋势图,当然他不仅仅只能用在时间序列中,也可以和其他图形配合使用,正如本期要介绍的,可以将折线图绘制到散点图中。散点图可以反映两个变量间的相关关系,即如果存在相关关系的话,它们之间是正向的线性关系还是反向的线性关系?甚至于是非线性关系?在绘制散点图之前,我们任然老规矩,先来介绍一下matplotlib包中的scatter函数用法及参数含义。
matplotlib模块中scatter函数语法及参数含义:
plt.scatter(x, y, s=20,
c=None, marker='o',
cmap=None, norm=None,
vmin=None, vmax=None,
alpha=None, linewidths=None,
edgecolors=None)
x:指定散点图的x轴数据;
y:指定散点图的y轴数据;
s:指定散点图点的大小,默认为20,通过传入新的变量,实现气泡图的绘制;
c:指定散点图点的颜色,默认为蓝色;
marker:指定散点图点的形状,默认为圆形;
cmap:指定色图,只有当c参数是一个浮点型的数组的时候才起作用;
norm:设置数据亮度,标准化到0~1之间,使用该参数仍需要c为浮点型的数组;
vmin、vmax:亮度设置,与norm类似,如果使用了norm则该参数无效;
alpha:设置散点的透明度;
linewidths:设置散点边界线的宽度;
edgecolors:设置散点边界线的颜色;
案例:汽车速度与刹车距离的关系
# 导入模块
import pandas as pd
import matplotlib.pyplot as plt
# 设置绘图风格
plt.style.use('ggplot')
# 设置中文编码和负号的正常显示
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
# 读入数据cars = pd.read_csv('cars.csv')
# 绘图
plt.scatter(cars.speed, # x轴数据为汽车速度
cars.dist, # y轴数据为汽车的刹车距离
s = 30, # 设置点的大小
c = 'steelblue', # 设置点的颜色
marker = 's', # 设置点的形状
alpha = 0.9, # 设置点的透明度
linewidths = 0.3, # 设置散点边界的粗细
edgecolors = 'red' # 设置散点边界的颜色
)
# 添加轴标签和标题plt.title('汽车速度与刹车距离的关系')
plt.xlabel('汽车速度')
plt.ylabel('刹车距离')
# 去除图边框的顶部刻度和右边刻度
plt.tick_params(top = 'off', right = 'off')
# 显示图形plt.show()
这样一张简单的散点图就呈现出来了,很明显的发现,汽车的刹车速度与刹车距离存在正相关关系,即随着速度的增加,刹车距离也在增加。其实这个常识不用绘图都能够发现,关键是通过这个简单的案例,让大家学会如何通过python绘制一个散点图。如果你需要画的散点图,是根据不同的类别进行绘制,如按不同的性别,将散点图区分开来等。这样的散点图该如何绘制呢?
案例:iris数据集
# 读取数据
iris = pd.read_csv('iris.csv')
# 自定义颜色
colors = ['steelblue', '#9999ff', '#ff9999']
# 三种不同的花品种S
pecies = iris.Species.unique()
# 通过循环的方式,完成分组散点图的绘制
for i in range(len(Species)):
plt.scatter(iris.loc[iris.Species == Species[i], 'Petal.Length'],
iris.loc[iris.Species == Species[i], 'Petal.Width'],
s = 35, c = colors[i], label = Species[i])
# 添加轴标签和标题
plt.title('花瓣长度与宽度的关系')
plt.xlabel('花瓣长度')
plt.ylabel('花瓣宽度')
# 去除图边框的顶部刻度和右边刻度
plt.tick_params(top = 'off', right = 'off')
# 添加图例
plt.legend(loc = 'upper left')
# 显示图形
plt.show()
绘制这样的分组散点图是不是也非常的简单呀,而且关于图的属性,可以想怎么设置就怎么设置。从图中可以发现,三种花的花瓣长度与宽度之间都存在正向的关系,只不过品种setasa的体型比较小,数据点比较聚集。
案例:大区销售数据
# 导入第三方包
import numpy as np
# 读取数据
sales = pd.read_excel('sales.xlsx')
# 绘制气泡图
plt.scatter(sales.finish_ratio,
sales.profit_ratio,
c = 'steelblue',
s = sales.tot_target/30,
edgecolor = 'black')
# 改变轴刻度的显示方式(百分比形式)
plt.xticks(np.arange(0,1,0.1), [str(i*100)+'%' for i in np.arange(0,1,0.1)])
plt.yticks(np.arange(0,1,0.1), [str(i*100)+'%' for i in np.arange(0,1,0.1)])
# 设置x轴和y轴的数值范围
plt.xlim(0.2, 0.7)
plt.ylim(0.25, 0.85)
# 添加轴标签和标题
plt.title('完成率与利润率的关系')
plt.xlabel('完成率')
plt.ylabel('利润率')
# 去除图边框的顶部刻度和右边刻度
plt.tick_params(top = 'off', right = 'off')
# 显示图形
plt.show()
这样一个气泡图,也非常容易的展现出来了,图中的圆越大,代表总任务量就越大。一般来说气泡图可以展现3维或4维数据,利润本图就展现了3维数据,如果再加上颜色表示不同的大区,就可以反映4维数据。
在绝大多数情况下,我们会看见散点图和线性回归线绘制在一起,一方面可以反映变量间的相关关系,另一反面,也可以定量的找到一根直线来反映这个相关趋势。接下来,我们就来实现一下散点图+回归线的绘制,这里回归线的绘制数据需要加载sklearn这个机器学习的模块,通过这个模块来生成一个线性模型。关于sklearn模块的知识分享,后期我也会以系列的形式呈现。
汽车速度与刹车距离的关系
从我们的第一案例就认识到了汽车的刹车速度与刹车距离之间存在正相关的关系,如果需要定量的模型来反映这个关系,就可以利用线性回归模型来刻画即可,接下来我们就来实现一下这个散点图与回归图的结合:
# 导入第三方模块
from sklearn.linear_model import LinearRegression
# 散点图
plt.scatter(cars.speed, # x轴数据为汽车速度
cars.dist, # y轴数据为汽车的刹车距离
s = 30, # 设置点的大小
c = 'black', # 设置点的颜色
marker = 'o', # 设置点的形状
alpha = 0.9, # 设置点的透明度
linewidths = 0.3, # 设置散点边界的粗细
label = '观测点'
)
# 建模
reg = LinearRegression().fit(cars.speed.reshape(-1,1), cars.dist)
# 回归预测值
pred = reg.predict(cars.speed.reshape(-1,1))
# 绘制回归线
plt.plot(cars.speed, pred, linewidth = 2, label = '回归线')
# 添加轴标签和标题
plt.title('汽车速度与刹车距离的关系')
plt.xlabel('汽车速度')
plt.ylabel('刹车距离')
# 去除图边框的顶部刻度和右边刻度
plt.tick_params(top = 'off', right = 'off')
# 显示图例
plt.legend(loc = 'upper left')
# 显示图形
plt.show()
如何借用Python绘制雷达图(或蛛网图),雷达图可以很好刻画出某些指标的横向或纵向的对比关系,例如近三年营业额、客单价、新客招募等指标的同比情况对比,完全就可以通过雷达图让数据一目了然。很不幸的是,matplotlib模块中并没有特制雷达图的封装函数,我们只能换一只思路来实现了。
# 导入第三方模块
import numpy as np
import matplotlib.pyplot as plt
# 中文和负号的正常显示
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
# 使用ggplot的绘图风格
plt.style.use('ggplot')
# 构造数据
values = [3.2,2.1,3.5,2.8,3]
feature = ['个人能力','QC知识','解决问题能力','服务质量意识','团队精神']
N = len(values)
# 设置雷达图的角度,用于平分切开一个圆面
angles=np.linspace(0, 2*np.pi, N, endpoint=False)
# 为了使雷达图一圈封闭起来,需要下面的步骤
values=np.concatenate((values,[values[0]]))
angles=np.concatenate((angles,[angles[0]]))
# 绘图
fig=plt.figure()
# 这里一定要设置为极坐标格式
ax = fig.add_subplot(111, polar=True)
# 绘制折线图
ax.plot(angles, values, 'o-', linewidth=2)
# 填充颜色
ax.fill(angles, values, alpha=0.25)
# 添加每个特征的标签
ax.set_thetagrids(angles * 180/np.pi, feature)
# 设置雷达图的范围
ax.set_ylim(0,5)
# 添加标题
plt.title('活动前后员工状态表现')
# 添加网格线
ax.grid(True)
# 显示图形
plt.show()
非常简单吧,一张雷达图就这么造出来了。其思想也非常简单,即先把常见的二维坐标变换成极坐标,然后在极坐标的基础上绘制折线图,如果需要填充颜色的话就是要fill方法。一般而言这样的雷达图没有什么意义,因为我们用雷达图通常是要实现多个对象的对比,所以,该如何绘制多条线的雷达图呢?可以参考下面的代码:
# 导入第三方模块
import numpy as np
import matplotlib.pyplot as plt
# 中文和负号的正常显示
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
# 使用ggplot的绘图风格
plt.style.use('ggplot')
# 构造数据
values = [3.2,2.1,3.5,2.8,3]
values2 = [4,4.1,4.5,4,4.1]
feature = ['个人能力','QC知识','解决问题能力','服务质量意识','团队精神']
N = len(values)
# 设置雷达图的角度,用于平分切开一个圆面
angles=np.linspace(0, 2*np.pi, N, endpoint=False)
# 为了使雷达图一圈封闭起来,需要下面的步骤
values=np.concatenate((values,[values[0]]))
values2=np.concatenate((values2,[values2[0]]))
angles=np.concatenate((angles,[angles[0]]))
# 绘图
fig=plt.figure()
ax = fig.add_subplot(111, polar=True)
# 绘制折线图
ax.plot(angles, values, 'o-', linewidth=2, label = '活动前')
# 填充颜色
ax.fill(angles, values, alpha=0.25)
# 绘制第二条折线图
ax.plot(angles, values2, 'o-', linewidth=2, label = '活动后')
ax.fill(angles, values2, alpha=0.25)
# 添加每个特征的标签
ax.set_thetagrids(angles * 180/np.pi, feature)
# 设置雷达图的范围
ax.set_ylim(0,5)
# 添加标题
plt.title('活动前后员工状态表现')
# 添加网格线
ax.grid(True)
# 设置图例
plt.legend(loc = 'best')
# 显示图形
plt.show()
发现了吧,如果要绘制多个对象的雷达图,只需多执行几个绘制折线图的语句即可。总体来说,这张图绘制的还算可以,但总是觉得有点拥挤,不自在。其实在matplotlib官网中,也提供了绘制雷达图的API,只不过代码量非常大,感兴趣的话,可以前去查看(http://matplotlib.org/gallery/api/radar_chart.html#sphx-glr-gallery-api-radar-chart-py)。
虽然matplotlib模块没有封装好的雷达图命令,但pygal模块则提供了更加简单的雷达图函数,我们也尝试着借助这个模块实现雷达图的绘制。
# 导入第三方模块
import pygal
# 调用Radar这个类,并设置雷达图的填充,及数据范围
radar_chart = pygal.Radar(fill = True, range=(0,5))
# 添加雷达图的标题
radar_chart.title = '活动前后员工状态表现'
# 添加雷达图各顶点的含义
radar_chart.x_labels = ['个人能力','QC知识','解决问题能力','服务质量意识','团队精神']
# 绘制两条雷达图区域
radar_chart.add('活动前', [3.2,2.1,3.5,2.8,3])
radar_chart.add('活动后', [4,4.1,4.5,4,4.1])
# 保存图像
radar_chart.render_to_file('radar_chart.svg')
一般来说,折线图表达的思想是研究某个时间序列的趋势。往往一条折线图可以根据某个分组变量进行拆分,比如今年的销售额可以拆分成各个事业线的贡献;流量可以拆分为各个渠道;物流总量可以拆分为公路运输、铁路运输、海运和空运。按照这个思路可以将一条折线图拆分成多条折线图,直观的发现各个折线图的趋势,但遗憾的是不能得知总量的趋势。为了解决这个问题,我们可以借助matplotlib中的stackplot函数绘制面积图来直观表达分组趋势和总量趋势。
stackplot(x,*args,**kargs)
x指定面积图的x轴数据
*args为可变参数,可以接受任意多的y轴数据,即各个拆分的数据对象
**kargs为关键字参数,可以通过传递其他参数来修饰面积图,如标签、颜色
可用的关键字参数:
labels:以列表的形式传递每一块面积图包含的标签,通过图例展现
colors:设置不同的颜色填充面积图
以我国2017年的物流运输量为例,来对比绘制折线图和面积图。这里将物流运输量拆分成公路运输、铁路运输和水路运输,绘图的对比代码见下方所示:
# ========== Python3 + Jupyter ========== #
# 导入第三方模块
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置图形的显示风格
plt.style.use('ggplot')
# 设置中文和负号正常显示
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
# 读取数据
transport = pd.read_excel('transport.xls')
# 窥探数据框的前5行
transport.head()
# 折线图的x变量值,即Jan(一月份)到Aug(八月份)8个值
N = np.arange(transport.shape[1]-1)
# 绘制拆分的折线图
labels = transport.Index
channel = transport.columns[1:]
for i in range(transport.shape[0]):
plt.plot(N, # x坐标
transport.loc[i,'Jan':'Aug'], # y坐标
label = labels[i], # 添加标签
marker = 'o', # 给折线图添加圆形点
linewidth = 2 # 设置线的宽度
)
# 添加标题和坐标轴标签
plt.title('2017年各运输渠道的运输量')
plt.ylabel('运输量(万吨)')
# 修改x轴的刻度标签
plt.xticks(N,channel)
# 剔除图框上边界和右边界的刻度
plt.tick_params(top = 'off', right = 'off')
# 显示图例(即显示label的效果)
plt.legend(loc = 'best')
# 显示图形
plt.show()
这就是绘制分组的折线图思想,虽然折线图能够反映各个渠道的运输量随月份的波动趋势,但无法观察到1月份到8月份的各自总量。接下来我们看看面积图的展现。
x = N
# 将铁路运输、公路运输和水路运输各月的值提取出来,存储到y1~y3
# 千万千万记得,提取出数据框的一列时,需要将序列的数据类型进行强制转换,否则会报错
y1 = transport.loc[0,'Jan':'Aug'].astype('int')
y2 = transport.loc[1,'Jan':'Aug'].astype('int')
y3 = transport.loc[2,'Jan':'Aug'].astype('int')
# 定义各区块面积的含义
colors = ['#ff9999','#9999ff','#cc1234']
# 绘制面积图
plt.stackplot(x, # x轴
y1,y2,y3, # 可变参数,接受多个y
labels = labels, # 定义各区块面积的含义
colors = colors # 设置各区块的填充色
)
# 添加标题和坐标轴标签
plt.title('2017年各运输渠道的运输量')
plt.ylabel('累积运输量(万吨)')
# 修改x轴的刻度
plt.xticks(N,channel)
# 剔除图框上边界和右边界的刻度
plt.tick_params(top = 'off', right = 'off')
# 显示图例(即显示labels的效果)
plt.legend(loc = 'upper left')
# 显示图形
plt.show()
一个stackplot函数就能解决问题,而且具有很强的定制化。从上面的面积图就可以清晰的发现两个方面的信息,一个是各渠道运输量的趋势,另一个是则可以看见各月份的总量趋势。所以,我们在可视化的过程中要尽可能的为阅读者输出简单而信息量丰富的图形。
如何绘制填充表格热力图的知识点,先给大家看一下效果图。
从效果图里我们可以发现,所谓的填充表格热力图就是将原本为数字表(数组)的单元格以颜色来填充,颜色的深浅表示数值的大小。我想,对于这样的图来说,总比直接看密密麻麻的数值表要轻松的多吧,毕竟颜色感官比数字感官要直接,要具有更强的冲击。除了填充表格热力图,还有更为常见的地图热力图等。那填充表格热力图是如何应用Python来实现的呢?就让我们手把手的进行讲解吧~
在绘图之前,需要说明一下绘图的数据源,案例中的数据是通过爬虫获取的,用的是上海9月份每天的最高气温,即生成两列数据(日期和最高气温)。在有了原始数据的基础上,还需要对数据进行清洗和整理,关于这部分是做任何数据分析或可视化都必经的坎。详细可以通过下面的代码来了解:
步骤一:数据采集
# ========== Python3 + Jupyter ========== #
# 导入所需的第三方包
import datetime
import calendar
import requests
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 采集数据
# 上海2017年9月份历史气温数据
url = 'http://lishi.tianqi.com/shanghai/201709.html'
# 发送爬虫请求
response = requests.get(url).text
# 解析源代码
soup = BeautifulSoup(response, 'html.parser')
# 根据HTML标记语言,查询目标标记下的数据
datas = soup.findAll('div',{'class':'tqtongji2'})[0].findAll('ul')[1:]
# 抓取日期数据
date = [i.findAll('li')[0].text for i in datas]
# 抓取最高温数据
high = [i.findAll('li')[1].text for i in datas]
# 创建数据框
df = pd.DataFrame({'date':date, 'high':high})
# 变量类型
df.dtypes
步骤二:数据整理
# 将date变量转换为日期类型
df.date = pd.to_datetime(df.date)
# 将high变量转换成数值型
df.high = df.high.astype('int')
# 数据处理
# 由日期型数据衍生出weekday
df['weekday'] = df.date.apply(pd.datetime.weekday)
# 由日期型数据计算week_of_month,即当前日期在本月中是第几周
# 由于没有现成的函数,这里自定义一个函数来计算week_of_month
def week_of_month(tgtdate):
# 由日期型参数tgtdate计算该月的天数
days_this_month = calendar.mdays[tgtdate.month] # 通过循环当月的所有天数,找出第二周的第一个日期
for i in range(1, days_this_month + 1):
d = datetime.datetime(tgtdate.year, tgtdate.month, i)
if d.day - d.weekday() > 0:
startdate = d
break
# 返回日期所属月份的第一周
return (tgtdate - startdate).days //7 + 1
df['week_of_month'] = df.date.apply(week_of_month)
df.head()
到此为止,我们就完成了数据的采集和清洗过程,接下来我们就可以借助该数据完成填充热力(日历)图的绘制。
基于matplotlib绘制热力图
其实,我需要绘制的是一个数据表,只不过把表中的每一个单元格用颜色填充起来。而表的结构是:列代表周一到周日,行代表9月份第一周到第五周。很显然,我们刚刚完成的数据并不符合这样的结构,故需要通过pandas模块中的pivot_table函数制作一个透视表,然后才可以绘图。关于热力图,我们可以使用matplotlib模块中的pcolor函数,具体我们可以看下方的绘图语句:
# ==================绘图前的数据整理=====================
# 构建数据表(日历)
target = pd.pivot_table(data = df.iloc[:,1:],values = 'high',
index = 'week_of_month', columns = 'weekday')
target
# 缺失值填充(不填充的话pcolor函数无法绘制)
target.fillna(0,inplace=True)
# 删除表格的索引名称
target.index.name = None
# 对索引排序(为了让“第一周”到“第五周”的刻度从y轴的高到底显示)
target.sort_index(ascending=False, inplace=True)
# ======================开始绘图=========================
# 设置中文和负号正常显示
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
plt.pcolor(target, # 指定绘图数据
cmap=plt.cm.Blues, # 指定填充色
edgecolors = 'white' # 指点单元格之间的边框色
)
# 添加x轴和y轴刻度标签(加0.5是为了让刻度标签居中显示)
plt.xticks(np.arange(7)+0.5,['周一','周二','周三','周四','周五','周六','周日'])
plt.yticks(np.arange(5)+0.5,['第五周','第四周','第三周','第二周','第一周'])
# 消除图框顶部和右部的刻度线
plt.tick_params(top='off', right = 'off')
# 添加标题
plt.title('上海市2017年9月份每日最高气温分布图')
# 显示图形
plt.show()
绘图数据的表结构
热力图展现
OK,一张填充表格热力图就奇迹般的显示了,而且看上去还蛮舒服的。从图框看,9月份的第一天是周五,之后的每一天都有对应的颜色显示。但我在绘图过程中发现几个问题:
1)绘图用的数据,不能包含缺失值,否则填充图是绘制不出来的,所有需要对缺失值做填充处理;
2)最终的图例无法实现,即颜色的深浅,代表了具体的数值范围是什么?
3)不方便将具体的温度值显示在每个单元格内;
为解决上面的三个问题,我们借助于seaborn模块中的heatmap函数重新绘制一下热力图,而且这些问题在heatmap函数看来根本不算问题。
基于seaborn绘制热力图
# 通过透视图函数形成绘图数据
target = pd.pivot_table(data = df.iloc[:,1:],values = 'high',
index = 'week_of_month', columns = 'weekday')
# 绘图
ax = sns.heatmap(target, # 指定绘图数据
cmap=plt.cm.Blues, # 指定填充色
linewidths=.1, # 设置每个单元方块的间隔
annot=True # 显示数值
)
# 添加x轴刻度标签(加0.5是为了让刻度标签居中显示)
plt.xticks(np.arange(7)+0.5,['周一','周二','周三','周四','周五','周六','周日'])
# 可以将刻度标签置于顶部显示
# ax.xaxis.tick_top()
# 添加y轴刻度标签
plt.yticks(np.arange(5)+0.5,['第一周','第二周','第三周','第四周','第五周'])
# 旋转y刻度0度,即水平显示
plt.yticks(rotation = 0)
# 设置标题和坐标轴标签
ax.set_title('上海市2017年9月份每日最高气温分布图')
ax.set_xlabel('')
ax.set_ylabel('')
# 显示图形
plt.show()
完美热力图的绘制太简单了!不需要做任何的特殊处理,只需要将绘图数据扔给heatmap函数即可。想想是不是有点小激动啊~激动过后,还得跟着步骤操作一表哦~
用可视化的方法来表达离散变量的数值情况,不仅仅可以使用条形图、饼图、热力图,我们还可以借助于树地图来完成。树地图的思想就是通过方块的面积来表示,面积越大,其代表的值就越大,反之亦然。今天要跟大家分享的就是如何通过Ptyhon这个工具,完成树地图的绘制。
在Python中,可以借助于squarify包来绘制,即squarify.plot函数。首先,我们来看一下这个函数的语法及参数含义:
squarify.plot(sizes,
norm_x=100,
norm_y=100,
color=None,
label=None,
value=None,
alpha,
**kwargs)
sizes:指定离散变量各水平对应的数值,即反映树地图子块的面积大小;
norm_x:默认将x轴的范围限定在0-100之内;
norm_y:默认将y轴的范围限定在0-100之内;
color:自定义设置树地图子块的填充色;
label:为每个子块指定标签;
value:为每个子块添加数值大小的标签;
alpha:设置填充色的透明度;
**kwargs:关键字参数,与条形图的关键字参数类似,如设置边框色、边框粗细等;
介绍完了绘图所需要的函数,先来抛一个树地图的效果图,该图反映的是2017年8月中央财政收入的主要来源情况:
图中的数据来自《中华人民共和国财政部》官网,具体可以从2017年8月财政收支情况(http://gks.mof.gov.cn/zhengfuxinxi/tongjishuju/201709/t20170911_2695830.html)查看。
# 导入第三方包
import matplotlib.pyplot as plt
import squarify
#中文及负号处理办法
plt.rcParams['font.sans-serif'] = 'Microsoft YaHei'
plt.rcParams['axes.unicode_minus'] = False
# 创建数据
name = ['国内增值税','国内消费税','企业所得税','个人所得税',
'进口增值税、消费税','出口退税','城市维护建设税',
'车辆购置税','印花税','资源税','土地和房税','车船税烟叶税等']
income = [3908,856,801,868,1361,1042,320,291,175,111,414,63]
# 绘图
colors = ['steelblue','#9999ff','red','indianred',
'green','yellow','orange']
plot = squarify.plot(sizes = income, # 指定绘图数据
label = name, # 指定标签
color = colors, # 指定自定义颜色
alpha = 0.6, # 指定透明度
value = income, # 添加数值标签
edgecolor = 'white', # 设置边界框为白色
linewidth =3 # 设置边框宽度为3
)
# 设置标签大小
plt.rc('font', size=8)
# 设置标题大小
plot.set_title('2017年8月中央财政收支情况',fontdict = {'fontsize':15})
# 去除坐标轴
plt.axis('off')
# 去除上边框和右边框刻度
plt.tick_params(top = 'off', right = 'off')
# 显示图形
plt.show()
通过上面的这些绘图语句和美化语句,就可以得到一个形象不错的树地图了。是不是很简单呢,如果你的工作中需要绘制离散变量的可视化,也可以考虑考虑这张图呢~简单明了形象佳!