本文为《Task06 - 场景案例显神通》笔记。
介绍用于不同场景的可视化图表类型:
1)展示趋势变化(Evolution)
2)展示分布关系(Distribution)
3)展示相关关系(Correlation)
4)展示排序信息(Ranking)
5)展示组成关系(Part of a whole)
通过用于呈现时间趋势的变化(时间序列),所以x轴常用来代表时间。
使用折线图使需要注意:
- X轴的数据必须是有序的
- 是否需要截断Y轴,即Y轴是否必须要从0点开始?
- 如果要比较两个或多个不同的变量的变化趋势,不要使用双Y轴图表
- 小心有很多线条的线图(spaghetti chart-意大利面条图),太多的线条会让图表变得混乱、无法阅读;建议使用多子图形式或重点突出某一个种类
用plt绘制时,如果只输入一列数则默认为y的值,而自动生成x。
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 创建数据,分别对应X轴和Y轴,注意X轴要是有序排列的
df=pd.DataFrame({'xdata': range(1,101), 'ydata': np.random.randn(100) })
# 绘图
plt.style.use('seaborn-darkgrid') # 也可以选择其他的风格式样 seaborn-whitegrid
plt.figure(figsize=(15, 10)) # 设置画布大小
# color: 控制线条颜色,red/skyblue/blue 等
# alpha: 控制线条透明度
# linestyle:控制线条式样,'--', '-', '-.', ':' 等
# linewidth:控制线条粗细大小
plt.plot( 'xdata', 'ydata', data=df, color='blue',alpha=0.3, linestyle='-.', linewidth=2, label='linestyle')
plt.legend(loc='upper left', frameon=False) # 设置标签
plt.title('Basic line plot') # 设置标题
plt.show()
当途中又多条线时,我们可以突出某条或几条线。有两种方法:
未突出重点的图:
# 导入包
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 导入数据集并转成方便作图的格式
Dataset = pd.read_csv('data/Drugs.csv')
group = Dataset.groupby(['YYYY','State']).agg('sum').reset_index()
df = group.pivot(index='YYYY', columns='State', values='DrugReports').reset_index()
# 设定式样
plt.style.use('seaborn-darkgrid')
# 创建调色板,色卡用来控制每条线的颜色
palette = plt.get_cmap('Set1')
# 绘图
plt.figure(figsize=(15, 7))
num=0
for column in df.drop('YYYY', axis=1):
num += 1
plt.plot(df['YYYY'], df[column], marker='', color=palette(num), linewidth=2, alpha=0.9, label=column)
plt.legend(loc=2, ncol=2)
plt.title("Multiple line plot", loc='center', fontsize=12, fontweight=0, color='orange')
plt.xlabel("year")
plt.ylabel("DrugReports")
plt.show()
# 导入包
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 导入数据集并转成方便作图的格式
Dataset = pd.read_csv('data/Drugs.csv')
group = Dataset.groupby(['YYYY','State']).agg('sum').reset_index()
df = group.pivot(index='YYYY', columns='State', values='DrugReports').reset_index()
# 设定式样
plt.style.use('seaborn-darkgrid')
# 绘图
plt.figure(figsize=(10, 10), dpi=70)
# 所有的线条都画成灰色
for column in df.drop('YYYY', axis=1):
plt.plot(df['YYYY'], df[column], marker='', color='grey', linewidth=1, alpha=0.4)
# PA的特殊处理,用橘色且加粗
plt.plot(df['YYYY'], df['PA'], marker='', color='orange', linewidth=4, alpha=0.7)
# 设定每条线的label的位置,其他的都为灰色,PA的为橘色
num=0
for i in df.values[7][1:]:
num+=1
name=list(df)[num]
if name != 'PA':
plt.text(2017.02, i, name, horizontalalignment='left', size='small', color='grey')
# 特殊处理PA
plt.text(2017.02, df.PA.tail(1), 'PA', horizontalalignment='left', size='small', color='orange')
# 添加图的标题和XY轴的标签
plt.title("Evolution of PA vs other states", loc='left', fontsize=12, fontweight=0, color='orange')
plt.xlabel("Year")
plt.ylabel("DrugReports")
多子图:
多个子图对比的时候,需要注意,X轴和Y轴的刻度大小需要严格一致,不然会带来误导。
# 导入包
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 导入数据集并转成方便作图的格式
Dataset = pd.read_csv('data/Drugs.csv')
group = Dataset.groupby(['YYYY','State']).agg('sum').reset_index()
df = group.pivot(index='YYYY', columns='State', values='DrugReports').reset_index()
# 初始化画布的设定
plt.style.use('seaborn-darkgrid') # 风格
palette = plt.get_cmap('Set1') # 颜色卡
plt.figure(figsize=(15, 10)) # 画布大小
# 绘制
num=0
for column in df.drop('YYYY', axis=1):
num+=1
# 设定子图在画布的位置
plt.subplot(3,3, num)
# 画线图
plt.plot(df['YYYY'], df[column], marker='', color=palette(num), linewidth=1.9, alpha=0.9, label=column)
# 设定子图的X轴和Y轴的范围,注意,这里所有的子图都是用同一套X轴和Y轴
plt.xlim(2009.3,2017.3)
plt.ylim(0,50000)
# 添加每个子图的标题
plt.title(column, loc='left', fontsize=12, fontweight=0, color=palette(num) )
# 添加整个画布的标题
plt.suptitle("How many DrugReports the 5 states have in past few years?", fontsize=13, fontweight=0, color='black', style='italic', y=0.95)
# 添加整个画布的横纵坐标的名称
plt.text(2014, -9500, 'Year', ha='center', va='center')
plt.text(1998, 60000, 'DrugReports', ha='center', va='center', rotation='vertical')
在折线图下方区域填充颜色,相比于折线图,面积图能更明显地反应数据的变化趋势。
注意事项:
- 是否要截断Y轴,见折线图部分。
- 如果需要对比两个或以上的类别,建议使用堆积面积图;如果一定要在单一面积图上表示,注意填充颜色一定要是透明色的,可以看到所有的线条。
- 注意图形的长宽比,让图形更易读一点。
- 一个好的做法是,将线条和填充的颜色保持统一,填充的颜色设置一些透明度,这些的图形会更美观一点。
在python中,可以用 fill_between
和 stackplot
来实现。
这里更推荐使用 fill_between
,在之后的定制化操作中更方便一点; stackplot
更多的是用在堆积面积图中。
# 导入包
import numpy as np
import matplotlib.pyplot as plt
# 创建数据
x=range(1,15)
y=[1,4,6,7,4,9,3,2,4,1,5,4,8,7]
# 绘图
# facecolor:控制填充颜色,red/skyblue/blue 等
# alpha: 控制填充透明度
# hatch: 控制阴影式样{'/', '\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
plt.fill_between( x, y, facecolor="skyblue", alpha=0.4, hatch='/')
plt.show()
# 在填充的基础上,添加一条折线,图形更加清晰
plt.fill_between( x, y, facecolor="skyblue", alpha=0.2)
plt.plot(x, y, color="skyblue", alpha=0.6, linewidth=1.5) # 线的更多设置可以参考 line plot文档
plt.show()
特点如下:
- 不同于多折线图的线条可能相互交叉,堆积面积图不会出现不同分类的数据点被遮盖、被隐藏的状况。每个类别都是都是堆积在下面类别面积图之上的。
- 堆积面积图与标准面积图不同,某一分类的值并非与纵坐标完全对应,而是通过折线之间的相对高度来表达。
- 堆积面积图不仅可以展示各类的发展趋势(面积图和折线图都能表示这个), 可以表达总体的发展趋势和个种类间的关系,比如重要程度,大致占比等。
stackplot
函数绘制的方式有二:
一个X和多个Y:
# 导入包
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 导入数据集并转成方便作图的格式
Dataset = pd.read_csv('data/Drugs.csv')
group = Dataset.groupby(['YYYY','State']).agg('sum').reset_index()
df = group.pivot(index='YYYY', columns='State', values='DrugReports').reset_index()
plt.style.use('seaborn-darkgrid') # 风格
plt.figure(figsize=(10, 6)) # 画布大小
plt.stackplot(df['YYYY'],df['KY'],df['OH'],df['PA'],df['VA'],df['WV'], labels=df.iloc[:, 1:6].columns)
plt.legend(loc='upper left')
plt.show()
# library
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-darkgrid') # 风格
plt.figure(figsize=(10, 6)) # 画布大小
# 方式一, y由三个序列组成
x=range(1,6)
y=[ [1,4,6,8,9], [2,2,7,10,12], [2,8,5,10,6] ]
# 绘图
plt.stackplot(x,y, labels=['A','B','C'])
plt.legend(loc='upper left')
plt.show()
小提琴图是用来展示多组数据的分布状态以及概率密度,它显示了一个(或多个)分类变量多个属性上的定量数据的分布,从而可以比较这些分布。
seaborn.violinplot 参数data
可接受的数据类型:
dataDataFrame, array, or list of arrays, optional
参数x,y,hue
的作用:
x,y是用作横纵坐标的属性,hue是在x,y取某组值(属性x,属性y)时要观察其数据分布和概率密度的属性。当hue属性有不同的值时,在同一(属性x,属性y)情况下会展现出多个小提琴图。
下小节的箱形图同理。
注意事项:
- 不适合展示只有很少组别的数据
- 按照中位数排序能让数据看起来更直观
import seaborn as sns
df = pd.read_csv('data/iris.csv')
#根据分类变量分组绘制一个纵向的小提琴图:
sns.violinplot( x=df['species'],y=df["sepal_length"],inner='quartile' )#x代表不同的类别特征,y代表连续特征,inner代表在小提琴图中显示四分位数线
tips = pd.read_csv('data/tips.csv')
#根据2个分类变量嵌套分组绘制一个小提琴图
ax = sns.violinplot(x="day", y="total_bill", hue="smoker",data=tips, palette="muted")
在上图中,可以看到,根据hue代表的属性’smoker’‘的取值’‘No’和’Yes’,在每组(属性x,属性y)下展现了两个小提琴图。
箱形图(或盒须图)以一种利于变量
之间比较或不同分类变量层次
之间比较的方式来展示定量数据的分布。矩形框显示数据集的上下四分位数
,而矩形框中延伸出的线段(触须)则用于显示其余数据的分布位置,剩下超过上下四分位间距
的数据点则被视为“异常值”
。
作用:
同一数轴上,几批数据的箱形图并行排列,几批数据的中位数、尾长、异常值、分布区间等形状信息便一目了然。在一批数据中,哪几个数据点出类拔萃,哪些数据点表现不及一般,这些数据点放在同类其它群体中处于什么位置,可以通过数据箱形图的形状看出。
箱型图可以直接使用 seaborn.boxplot
方法来实现:
import seaborn as sns
sns.set(style="whitegrid")
tips = pd.read_csv('data/tips.csv')
#根据分类变量分组绘制一个纵向的箱型图
ax = sns.boxplot(x="day", y="total_bill", data=tips)
# 根据2个分类变量嵌套分组绘制一个箱型图
ax = sns.boxplot(x="day", y="total_bill", hue="smoker",data=tips, palette="Set2")
# 使用 swarmplot() 展示箱型图顶部的数据点
ax = sns.boxplot(x="day", y="total_bill", data=tips)
ax = sns.swarmplot(x="day", y="total_bill", data=tips, color=".25")
直方图只
能接收数值类型
的变量
数据,该变量被切割成几个箱子,每个箱子的高度代表处于分箱中的数量。
注意事项
- 使用过程中要注意分箱数量的选择
- 不要用直方图展示超过5个变量的分布情况
- 避免使用彩色
可以使用seaborn.histplot
方法绘制直方图。
重要参数stat
,element
:
stat
: {“count”, “frequency”, “density”, “probability”}
Aggregate statistic to compute in each bin.
count
shows the number of observationsfrequency
shows the number of observations divided by the bin widthdensity
normalizes counts so that the area of the histogram is 1probability
normalizes counts so that the sum of the bar heights is 1
element
: {“bars”, “step”, “poly”}
Visual representation of the histogram statistic. Only relevant with univariate data.
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston
boston=load_boston()
y = boston['target']
f, axs = plt.subplots(7,1,figsize=(10,10))
# 计算标准直方图
sns.histplot(y,stat='count',ax=axs[0])
# 计算频率直方图
sns.histplot(y,stat='frequency',ax=axs[1])
# 计算密度
sns.histplot(y,stat='density',ax=axs[2])
# 归一化的直方图
sns.histplot(y,stat='probability',ax=axs[3])
# 在直方图上同时画出密度曲线
sns.histplot(y,stat='probability',kde=True,ax=axs[4])
# 取消填充
sns.histplot(y,stat='probability', fill=False,ax=axs[5])
# 取消直方图的分割线
sns.histplot(y,stat='probability',element="step", fill=False,ax=axs[6])
plt.tight_layout()
密度图和直方图很类似,同样用来展示数值型变量
的分布情况。
注意事项
- 注意密度函数的带宽
- 不要用直方图展示超过5个变量的分布情况
- 避免使用彩色
可以使用 seaborn.deplot
方法绘制直方图;
#kdeplot()中的bw参数控制着估计值与真实数据之间的贴近程度
#它与我们的KDE图的宽度相关。它提供了默认的规则来确定一个取值
x = np.random.normal(size=100)
sns.kdeplot(x, label="bw: default")
sns.kdeplot(x, bw_method=0.2, label="bw: 0.2")
sns.kdeplot(x, bw_method=2, label="bw: 2")
plt.legend();
mean, cov = [0, 1], [(1, .5), (.5, 1)]
data = np.random.multivariate_normal(mean, cov, 200)
df = pd.DataFrame(data, columns=["x", "y"])
#核密度估计也适用于二元的情况。在seaborn中,这种图会以等高线的方式展示出来,我们可以用jointplot(kind="kde")来绘制
sns.jointplot(x="x", y="y", data=df, kind="kde")
散点图常用于查看数值型变量之间的相关性,同时可以利用不同颜色来区分样本所属的类别。
注意事项
绘制散点图时要避免Overplotting,意思是由于散点数量过多导致图中的样例点过度重合。
- 可以通过抽样来作图
- 可以用热力图代替
- 调节样本点的size
可以直接用 matplotlib.scatter
方法绘制散点图:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
df = pd.read_csv('data\diamonds.csv').sample(1000)
# 绘制标准散点图
plt.scatter(df.carat, df.price, s=0.2)
# 用颜色区别不同类别的散点
sns.lmplot(x='carat', y='price', data=df, hue='cut', fit_reg=False)
通常用于数值变量的总体信息,可以通过颜色深浅明显地看出哪些数据更多。
通常和pandas一起使用。
注意事项
- 考虑到长尾分布等情况,经常需要对数据做标准化的预处理
- 经常需要对数据先进行分箱再绘图,对于类别变量而言,可以进行类别的合并;同时对于数值变量而言,既可以包含分位数分箱,也可以包含等间隔分箱
可以直接使用seaborn.heatmap
方法绘制热力图,用seaborn.jointplot
绘制蜂窝热力图:
# 类别变量的统计
res = pd.crosstab(df.cut, df.clarity)
sns.heatmap(res, cmap='Greens', annot=True)
# 类别变量和数值变量分箱统计
res = pd.crosstab(pd.qcut(df.price, 5), df.clarity)
sns.heatmap(res, cmap='Greens', annot=True)
# 数值变量之间的密度图
sns.jointplot(x=df["price"], y=df["carat"], kind='hex')
在上述密度图作图时,由于原来的特征是长尾分布的,所以导致密度图的偏向性很高,此时可以考虑使用对数变换、分位数截断和标准差截断。
下图可以看到,对数变换后数据近似于正态分布:
# 使用对数变换
sns.jointplot(x=np.log(df["price"]), y=np.log(df["carat"]), kind='hex')
# 使用标准差截断
s1, s2 = df.price, df.carat
s1 = s1.mask((s1>(s1.median()+1*s1.std()))|(s1<(s1.median()-s1.std())))
s2 = s2.mask((s2>(s2.median()+1*s2.std()))|(s2<(s2.median()-s2.std())))
sns.jointplot(x=s1, y=s2, kind='hex')
# 使用分位数截断
s1, s2 = df.price, df.carat
s1 = s1.mask((s1>(s1.quantile(0.5)))|(s1<(s1.quantile(0.05))))
s2 = s2.mask((s2>(s2.quantile(0.5)))|(s2<(s2.quantile(0.05))))
sns.jointplot(x=s1, y=s2, kind='hex')
气泡图适用于超过二维特征
的可视化,一般可以用气泡的颜色
和大小
来表示第三
维、第四
维的特征,可以认为气泡图是散点图的衍生。
注意事项
- 使用气泡面积而不是气泡的直径作为数值指标对比
- 和散点图类似,气泡图同样要注意overplotting的问题
可以使用 matplotlib.scatter
方法绘制气泡图,同时用颜色
和尺寸
参数控制第三
,第四
维度:
new_feature1 = np.random.randint(0, 10, 10) # 用气泡大小显示该feature大小
new_feature2 = np.random.randint(0, 10, 10) # 用气泡深浅显示该feature大小
plt.scatter(df.carat.sample(10), df.price.sample(10), s=new_feature1*100, c=new_feature2, cmap="Blues", alpha=0.8, edgecolors="grey", linewidth=2)
plt.scatter(df.cut.sample(10), df.price.sample(10), s=new_feature1*100, c=new_feature2, cmap="Blues", alpha=0.8, edgecolors="grey", linewidth=2)
柱状图用来展示一个类别变量和一个数值变量之间的关系,每个柱子代表一个类别,柱子的长度代表这个类别的数值。通常来说,柱状图是展示此类信息最有效的方式之一。
注意,
直方图
展示的是某个变量取值是在某个范围的数量。例如:[1,1,2,3,5,6]在[1,5)的取值有4个,分别是1 1 2 3 。
注意事项
- 不要和直方图混淆
- 类别标签较长时,可以采用横向柱状图
- 给柱子排序通常更有利于展示信息
可以直接用 matplotlib.bar
方法绘制柱状图:
# 计算分类别的平均属性值
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
pokemon = pd.read_csv('data/pokemon.csv')
data=pokemon.groupby('Type 1')['Total'].mean().sort_values(ascending=False).reset_index()
# 绘制柱状图
bars = data['Type 1']
pos = np.arange(len(bars))
plt.bar(pos, data['Total'])
plt.xticks(pos, bars,rotation=270)
plt.show()
较少使用。
可以使用极坐标系和多边形填充的方式绘制雷达图,具体用法如下:
from math import pi
# 绘制背景,选择2只口袋妖怪,比较六维属性值
data = pokemon.loc[[0,4]]
categories=['HP','Attack','Defense','Sp. Atk','Sp. Def','Speed']
N=6
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
ax = plt.subplot(111, polar=True)
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
plt.xticks(angles[:-1], categories)
ax.set_rlabel_position(0)
plt.yticks([20,40,60,80], ["20","40","60","80"], color="grey", size=7)
plt.ylim(0,80)
# 分别添加两个变量的雷达曲线
values= data.loc[0, ['HP','Attack','Defense','Sp. Atk','Sp. Def','Speed','HP']]
ax.plot(angles, values, linewidth=1, linestyle='solid', label=data.loc[0,'Name'])
ax.fill(angles, values, 'b', alpha=0.1)
values= data.loc[4, ['HP','Attack','Defense','Sp. Atk','Sp. Def','Speed','HP']]
ax.plot(angles, values, linewidth=1, linestyle='solid', label=data.loc[4,'Name'])
ax.fill(angles, values, 'r', alpha=0.1)
# 图例
plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
用来比较样本在一组数值型变量上的特征,它是雷达图的另一种表现形式,在可视化中更推荐被使用。
注意事项
- 不适合用于组别过多的情况
- 可以在X轴对数据排序,避免曲线之间的交叉
可以通过 pandas.plotting.parallel_coordinates
方法绘制平行坐标图:
from pandas.plotting import parallel_coordinates
import seaborn as sns
import matplotlib.pyplot as plt
data =pd.read_csv('data/iris.csv')
# Make the plot
parallel_coordinates(data, 'species', colormap=plt.get_cmap("Set2"))
plt.show()
从上图可以看到x轴上变量共用一个y坐标轴,此时因sepal_length、sepal_width、petal_length以及petal_width这四个变量的值得范围相近,利用这种方式作出的共用y轴的平行坐标图有着很好的可视化效果;但假如sepal_length、sepal_width、petal_length以及petal_width这些变量的值的范围相差较大
时,这种共用y轴的平行坐标图就不再适用,此时我们需要的是y轴独立
的平行坐标图。下面介绍的另一种方法实现的就是y轴独立的平行坐标图。
df = sns.load_dataset('iris')
df['species_id'] = df['species'].map({'setosa':1,'versicolor':2,'virginica':3}) #用于颜色映射
py.offline.iplot({
"data": [go.Parcoords(
line = dict(color = df['species_id'],
colorscale = [[0,'#D7C16B'],[0.5,'#23D8C3'],[1,'#F3F10F']]),
dimensions = list([
dict(range = [2,8],
constraintrange = [4,8],
label = 'Sepal Length', values = df['sepal_length']),
dict(range = [1,6],
label = 'Sepal Width', values = df['sepal_width']),
dict(range = [0,8],
label = 'Petal Length', values = df['petal_length']),
dict(range = [0,4],
label = 'Petal Width', values = df['petal_width'])
])
)],
"layout": go.Layout(title='Iris parallel coordinates plot')
})
棒棒糖图本质上是柱状图的另一种表现形式,区别是把柱子用线和点来代替,但是从视觉上表现效果更好。
注意事项
- 排序会使得显示效果更好
- 如果因为某种原因不能保持排序状态,那么宁愿选择柱状图
可以使用 pyplot.hlines
方法来展示棒棒糖图:
# 计算分类别的平均属性值
data=pokemon.groupby('Type 1')['Total'].mean().reset_index()
# 绘制棒棒糖图
data = data.sort_values(by='Total')
my_range=range(1,len(data.index)+1)
plt.hlines(y=my_range, xmin=0, xmax=data['Total'], color='skyblue')
plt.plot(data['Total'], my_range, "o")
plt.yticks(my_range, data['Type 1'])
plt.title("A vertical lolipop plot", loc='left')
plt.xlabel('Average value of Total')
plt.ylabel('Type')
圆形柱状图相比于柱状图更吸引眼球,但同时也更难识别出柱子尺寸的差别,因此只有当你有大量类别需要展示,并且有一些明显突出的类别时才会使用。
注意事项
- 内圈的比例不能太小,一般须超过外圈的三分之一
- 通常只有当你有很多类别并且要突出某几个类别的时候才会用(>40)
# 计算分类别的平均属性值
data=pokemon.groupby('Type 1')['Total'].mean().reset_index()
# 绘制圆形柱状图
N = len(data)
bottom = 250
value = data['Total']
theta = np.linspace(0.0, 2 * pi, N, endpoint=False)
width = (2*pi) / N-0.02
plt.figure(figsize = (16, 10))
ax = plt.subplot(111, polar=True)
bars = ax.bar(theta, value, width=width, bottom=bottom)
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ticks =data['Type 1']
for theta,tick,value in zip(theta,ticks,value):
ax.text(theta+0.03, value+380,tick)
plt.axis('off')
plt.show()
饼图在图像上是一个被分成若干部分的圆,用于反映每个部分对于整体所占的比重。
注意事项
- 如果使用百分数,确保它加起来是100%
- 不要使用3d和图例,使得图的阅读性更差
饼图可以直接用 pyplot.pie
函数绘制,也可以调用pandas库的绘图接口 dataframe.plot
,具体用法如下:
#绘制Pie chart
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots() # 1*1画布
size = 0.3
vals = np.array([[60., 32.], [37., 40.], [29., 10.]]) # 3*2 array
cmap = plt.get_cmap("tab20c") # Get a colormap instance, matplotlib.cm
outer_colors = cmap(np.arange(3)*4) # cmap([0,4,8]), len(cmap.colors) -> 20
inner_colors = cmap(np.array([1,2,5,6,9,10]))
# 第一个环
ax.pie(vals.sum(axis=1)) # wedge object 控制圆环的宽度
plt.show()
import pandas as pd
# --- dataset 1: just 4 values for 4 groups:
df = pd.DataFrame([8,8,1,2], index=['a', 'b', 'c', 'd'], columns=['x'])
# make the plot
df.plot(kind='pie', subplots=True, figsize=(8, 8))
甜甜圈图和饼图极为类似,都是用来反映几个对象的组成比例,因而也有着相似的注意事项
注意事项
- 如果使用百分数,确保它加起来是100%
- 不要使用3d和图例,使得图的阅读性更差
在绘图时可以通过在饼图的中心画一个和底色相同的同心圆方式来绘制,具体用法如下:
import matplotlib.pyplot as plt
# 创建数据
names='groupA', 'groupB', 'groupC', 'groupD',
size=[12,11,3,30]
# 在中心画一个白色的圆
my_circle=plt.Circle( (0,0), 0.7, color='white')
# 画外围的饼图
plt.pie(size, labels=names, colors=['red','green','blue','skyblue'])
p=plt.gcf()
p.gca().add_artist(my_circle)
plt.show()
import matplotlib.pyplot as plt
# Make data: I have 3 groups and 7 subgroups
group_names=['groupA', 'groupB', 'groupC']
group_size=[12,11,30]
subgroup_names=['A.1', 'A.2', 'A.3', 'B.1', 'B.2', 'C.1', 'C.2', 'C.3', 'C.4', 'C.5']
subgroup_size=[4,3,5,6,5,10,5,5,4,6]
# Create colors
a, b, c=[plt.cm.Blues, plt.cm.Reds, plt.cm.Greens]
# First Ring (outside)
fig, ax = plt.subplots()
ax.axis('equal')
mypie, _ = ax.pie(group_size, radius=1.3, labels=group_names, colors=[a(0.6), b(0.6), c(0.6)] )
plt.setp( mypie, width=0.3, edgecolor='white')
# Second Ring (Inside)
mypie2, _ = ax.pie(subgroup_size, radius=1.3-0.3, labels=subgroup_names, labeldistance=0.7, colors=[a(0.5), a(0.4), a(0.3), b(0.5), b(0.4), c(0.6), c(0.5), c(0.4), c(0.3), c(0.2)])
plt.setp( mypie2, width=0.4, edgecolor='white')
plt.margins(0,0)
plt.show()
文氏图用于表示不同集合的有限集合之间所有可能的逻辑关系,每个集合用一个圆表示,圆的大小反映了该组的重要性,组与组之间通常会有交叠,交叠的部分体现了不同组之间的交叉数据。
不建议绘制超过3个集合的venn图。
文氏图可以利用matplotlib_venn包中的venn2和venn3方法绘制两个集合或三个集合的之间的逻辑关系。文氏图的数据类型可以是set或tuple
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
from matplotlib_venn import venn3
venn3(subsets=[set([3, 2, 1,4,5,6]),set([2,3,4]),set([1,2,3,4,5])], set_labels=('A', 'B','C'),set_colors = ('lightpink','pink','pink'))
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
from matplotlib_venn import venn3
venn2(subsets=(3, 2,4,1), set_labels=('A', 'B'),set_colors = ('r','g'))
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
from matplotlib_venn import venn3
venn3(subsets=(1,2,3,4,5,6,0), set_labels=('A', 'B','C'),set_colors = ('r','g','b'))
通过矩形的面积反映其取值大小,使用配色方案,可以表示多个维度:组、子组。
注意事项
- 不要在层次结构中注释超过3个级别,这会使图形不可读。
- 优先考虑层次结构的最高层次
可以使用 squarify
包绘制树图,squarify的底层代码也是基于matplotlib实现的:
#绘制treemap
import matplotlib.pyplot as plt
import squarify # pip install squarify (algorithm for treemap)
# Change color
squarify.plot(sizes=[13,22,10,5], label=["group A", "group B", "group C", "group D"], color=["red","green","blue", "grey"], alpha=.4 )
plt.axis('off')
plt.show()
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import squarify # pip install squarify (algorithm for treemap)</pre>
# Create a dataset:
my_values=[i**3 for i in range(1,100)]
# create a color palette, mapped to these values
cmap = matplotlib.cm.Blues
mini=min(my_values)
maxi=max(my_values)
norm = matplotlib.colors.Normalize(vmin=mini, vmax=maxi) # 归一化
colors = [cmap(norm(value)) for value in my_values] # matplotlib.cm.Blues接受0~1的参数,所以需要归一化
# Change color
squarify.plot(sizes=my_values, alpha=.8, color=colors )
plt.axis('off')
plt.show()
from matplotlib.pyplot import MultipleLocator
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
data = pd.read_csv('Drugs.csv')
df = pd.DataFrame(data)
# 以'YYYY'和'State'对'DrugReports'进行统计
reports = df.groupby(['YYYY', 'State'])['DrugReports'].sum().unstack('State') # 以‘State’列为目标消除堆叠
max_y = reports.max().max() #子图中纵坐标最大值
min_y = reports.min().min() #子图中纵坐标最小值
max_x = reports.idxmax().max()#子图中横坐标最大值
min_x = reports.idxmin().min()#子图中横坐标最小值
# 获取'State'的值['KY', 'OH', 'PA', 'VA', 'WV']
value_State = reports.columns
# 画图
# 标题颜色样式
colors = plt.get_cmap('tab10')
plt.figure(figsize=(20,10))
x_major_location = MultipleLocator(100) #将横坐标宽度设为10
y_major_location = MultipleLocator(1000) #将纵坐标宽度设为10
for i, value in enumerate(value_State):
x = reports.index
y = reports[value]
plt.subplot(2,3,i+1) # 记得是i+1,因为子图的下标是从1开始的。
plt.plot(x,y,color=colors(i))
plt.fill_between(x,y,facecolor='skyblue',alpha=0.4)
plt.title(value,loc='right',color=colors(i))
# 修改每个子图的刻度宽度
axis = plt.gca() # 获取当前axis
ax.xaxis.set_major_locator(x_major_location)
ax.yaxis.set_major_locator(y_major_location )
# 设置每个子图的刻度总范围
plt.xlim(min_x,max_x)
plt.ylim(min_y,max_y)
plt.grid()
# 给figure加横纵轴的名称,范围在[0,1]之间
plt.figtext(0.5, 0.05, 'Year', fontsize=15)
plt.figtext(0.05, 0.5, 'DrugReports', va='center', rotation='vertical',fontsize=15)
# figure的标题
plt.suptitle('DrugReport of each state every year', fontsize=20)
plt.show()