Python数据可视化
Seaborn是一个很好用的python数据可视化包。汇总一下之前做数据可视化时的一些注意事项和技巧。
Seaborn为什么有的数据可视化给人感觉起来很好看很舒服,其实涉及到Seaborn的一些细节操作问题,这里收集了我所关注到的注意事项。文章结构如下:Seaborn依赖的数据结构MatplotlibHeatplotJointplotViolinplot组合图(plt.plot+sns.heatplot)(1) 组合图的框架(2) 子图配置——heatplot(3) 子图配置——ax.plot(4) 其他1. Seaborn依赖的数据结构在使用Seaborn之前,需要强调和注意的是Seaborn依赖的数据结构。pandas的dataframe可以很方便地兼容Seaborn的数据输入。下面简单介绍从csv文件导入dataframe数据以及一些相关的处理:import pandas as pddataframe = pd.read_csv(filedir, usecols=[colsname]) # read data from csv filedataframe.drop() dataframe.iloc[]这里需要说明的是,对于dataframe数据,习惯上提前给列命名,方便之后Seaborn的使用,当然也可以在Seaborn中重新命名。2. MatplotlibMatplotlib可以很好的兼容Seaborn,可以通过Matplotlib对图片尺寸进行修改、ticklable及title等编辑、保存图片以及多个Seaborn子图的排列方式和尺寸进行编辑,同时,也可以实现Seaborn和Matplotlib共同作图。(1) 图片尺寸# 方法一import matplotlib.pyplot as pltf, ax = plt.subplots(figsize=(11, 9))# 方法二import pylabpylab.rcParams['figure.figsize'] = (12.0,7.0) # 显示大小(2) 图片标注及字体大小import matplotlib.pyplot as pltplt.xticks(fontsize=13)plt.yticks(fontsize=13)plt.xlim([0,4000])plt.legend(['line1,'line2','line3'],fontsize=17)plt.xlabel('x',fontsize=17)plt.ylabel('y',fontsize=17)plt.title('title', fontsize=20)(3) 保存图片plt.savefig(filename+".png",format='png', bbox_inches='tight', transparent=True)3. Heatplotcmap = sns.diverging_palette(220, 10, as_cmap=True)rc = {'font.size': 15, 'xtick.labelsize': 15, 'ytick.labelsize': 15}sns.set(rc=rc)# Draw the heatmap with the mask and correct aspect ratioheatplt = sns.heatmap(corr, mask=mask, cmap=cmap, vmax=.3, center=0, square=True, linewidths=.5, cbar_kws={"shrink": .5}, annot=True, fmt=".2f")
Heatmap.png其中,cmap可以定制heatmap的颜色,seaborn的heatmap当中的fmt参数可以修改显示数字的位数,例如".2f"表示float类型保留小数点后两位。4. Jointplotsns.jointplot(x=x, y=y, kind="hex",color='r')
Jointplot.png5. Violinplotvio = sns.violinplot(data=Error, orient="v",linewidth=0.6)for i in range(4): plt.vlines(1.5+2*(i), -0.35, 0.35, colors = "c", linestyles = "dashed")
Violinplot6. 组合图很多时候在描述一个问题时需要对不同的图进行组合以达到表现的目的,例如将plt的曲线图和seaborn的heatplot组合起来,并且横轴相对应,标注要清楚可见。
组合图结构这个时候需要根据以下步骤有条不紊地对图进行设置。(1) 组合图的框架首先确认你的图片当中包含几块,例如如果包含两块,那么分别的尺寸以及比例是怎样的。fig = plt.figure(figsize=(xSize, ySize))gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1])比如,如上代码是做了一个两行一列的结构,并且纵向比例是3:1,整个图片的大小是(xSize, ySize)。ax0 = plt.subplot(gs[0])ax1 = plt.subplot(gs[1])而subplot使用了gs为参数,确定了子图的句柄,可以通过对ax0或者ax1进行操作,以达到不同位置显示不同的图像的目的。(2) 子图配置——heatplot在子图当中,我们首先对heatplot进行操作,heatplt = sns.heatmap(data, linewidths=0, ax=ax1, cmap="YlGnBu", annot=False, yticklabels=['data'], xticklabels=xtick, cbar=False)注意点-1:因为考虑到需要将heatplot的横轴与plt的曲线图横轴对齐,所以关闭图例显示,当然也可以将图例与横轴平行放置,但是为了美观,这里我关掉了cbar的显示。注意点-2:对于横轴较为密集的情况下,例如是一个很长的时间段,需要对横轴进行间隔标注显示,这样给人看起来很清楚,不会因为密密麻麻挤在一起导致看不清的问题。所以使用如下的配置:import matplotlib.ticker as tickerax1.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))tick_spacing是可以修改的参数,顾名思义,是标注间隔的意思,这里需要注意,tick_spacing需要和给定的标注序列统一,举个例子,比如现在需要给横轴标注1到100,共100个数字,但是由于太过密集,需要用到tick_spacing参数进行稀疏标注,那么在给heatplot的xticklabels传递参数时,就必须根据tick_spacing对序列进行系数处理,亲测如下代码无误:(仅限配置heatplot)SliceStart = 0SliceEnd = len(data)tick_spacing = 10xtick=range(SliceStart - tick_spacing, SliceEnd, tick_spacing)需要注意的是必须减去tick_spacing,否则标注会错位。(3) 子图配置——ax.plot这里是曲线图部分,不做过多描述,有一点需要注意的就是,因为两个子图共用一个横坐标,所以第一行的图(也就是plot)的横坐标标注可以隐藏不显示,通过如下代码实现:plt.tick_params( axis='x', # changes apply to the x-axis which='both', # both major and minor ticks are affected bottom=False, # ticks along the bottom edge are off top=False, # ticks along the top edge are off labelbottom=False) # labels along the bottom edge are off(4) 其他为了确保两个图的横坐标对齐,每个子图配置结束后添加一行。plt.xlim([0, LenData])(5) 代码from matplotlib import gridspecimport numpy as npimport seaborn as snsimport matplotlib.pyplot as pltimport matplotlib.ticker as tickerimport pandas as pdimport numpyfrom pandas import Seriesdef drawHeat_plot(line, data, xSize, ySize, xtick, tick_spacing, cols='sin', filename='HeatPlot', title='Demo', yticklabel=['Value']): textFS = 80 titleFS = 100 LenData = len(line) rc = {'font.size': textFS, 'xtick.labelsize': textFS, 'ytick.labelsize': textFS, } sns.set(rc=rc) size = np.shape(data) fig = plt.figure(figsize=(xSize, ySize)) gs = gridspec.GridSpec(2, 1, height_ratios=[2, 1]) ax1 = plt.subplot(gs[1]) heatplt = sns.heatmap(data, linewidths=0, ax=ax1, cmap="YlGnBu", annot=False, xticklabels=xtick, cbar=False, yticklabels=yticklabel) plt.xticks(fontsize=textFS) plt.yticks(fontsize=textFS) ax1.set_ylabel('Value', fontsize=textFS) ax1.set_xlabel('Time step', fontsize=textFS) plt.xlim([0, LenData]) ax1.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing)) ax0 = plt.subplot(gs[0]) ax0.plot(line, linewidth=3) ax0.set_ylabel('Value', fontsize=textFS) plt.tick_params( axis='x', # changes apply to the x-axis which='both', # both major and minor ticks are affected bottom=False, # ticks along the bottom edge are off top=False, # ticks along the top edge are off labelbottom=False) # labels along the bottom edge are off ax0.set_title(title, fontsize=titleFS) ax0.grid(linestyle='--', linewidth='0.5', color='black') plt.legend([cols + ' Data'], fontsize=textFS) plt.xlim([0, LenData]) fig = heatplt.get_figure() fig.savefig(filename + ".png", format='png', bbox_inches='tight', transparent=True)Demo数据及参数:line = np.sin([3.14*i/20 for i in range(0,100)])data = np.sin([3.14*i/20 for i in range(0,100)])line = np.reshape(line,[100,])data = np.reshape(data,[1,100])xSize = 150ySize = 30SliceStart = 0SliceEnd = 100TickSpace = 10运行代码:drawHeat_plot(line, data, xSize, ySize, range(SliceStart - TickSpace, SliceEnd, TickSpace), tick_spacing=TickSpace, cols='sin', filename='HeatPlot', title='Demo')运行结果:
Demo总结:数据可视化是一门学问,如何在一张有限的图上清楚有效地展示图片想要说明的信息。一方面,根据想要突出数据的哪方面的信息,选择合适类型的图型;另一方面,给读图的人一种清楚明了的感觉,需要对可视化图的细节——例如排布、字体、字体大小、图例、颜色等等各个方面进行调节。这样,做出figure才既能表达作图者想要表达的信息,也能让读图者清楚清爽地领会数据呈现出来的信息。之后笔者接触到其他类型的可视化以及相关注意事项时会继续在这篇文章中书写。如有意见和建议请各位提出~