数据可视化(2):五种基本图形

上一次通过一个简单例子学习了图形的基本绘制方法,这次我们通过农企(AMD)的数据来学习五种基本图形的绘制

工具准备

  • AMD股票数据(Nov 21,2015 - Nov 21,2016),下载
  • S&P500同期指数,下载
  • AMD最近四个季度的财报
  • S&P500 同时段(AMD)的指数
  • Numpy
  • Matplotlib
  • Python3.x

(数据来源:Yahoo Finance)

首先我们引入工具

1
2
import numpy as np
import matplotlib as plt

接着使用loadtxt导入文件,我们的文件看上去是这个样子的


……

numpy可以很快地将现有的csv类型的数据导入

1
date,high,low=np.loadtxt('Nov21-1yr.csv',delimiter = ',',converters ={0:bytespdate2num('%Y-%m-%d')},skiprows =1,usecols=(0,2,3),unpack=True)
  • 导入文件名 Nov21-1yr.csv
  • delimiter 分隔符为’,’
  • converters 如果有日期需要使用bytespdate2num解析内容,0代表第一列
  • skiprows =1 跳过第一行
  • usecols(0,2,3) 使用1,3,4行,值得注意的是,如果我们只要获取一行,要用元组表示:usecols(x,)
  • unpack 将提取的数据分别放在三个列表里

散点图

简介

用两组数据构成多个坐标点,考察坐标点的分布,判断两变量之间是否存在某种关联或总结坐标点的分布模式。散点图将序列显示为一组点。值由点在图表中的位置表示。类别由图表中的不同标记表示。散点图通常用于比较跨类别的聚合数据。(百度百科)

使用scatter函数,array1(x轴),array2(y轴)为两组数据

1
plt.scatter(array1,array2,[parameters,...])

实例

首先我们获得AMD最近一年的最高价格,最低价格,日期

1
date,high,low=np.loadtxt('Nov21-1yr.csv',delimiter = ',',converters ={0:bytespdate2num('%Y-%m-%d')},skiprows =1,usecols=(0,2,3),unpack=True)

获得每日的价格波动范围,通过numpy读取的数据拥有array的格式,可以对两个同样大小的列表直接进行加减

diff = high -low 

接着我们使用scatter函数作散点图

1
plt.scatter(date,diff,alpha = 0.4)

这里的alpha是透明度。添加了透明度属性后,颜色会变淡,而重合的点的颜色会加深,使散点图更加直观

>>> plt.show()

折线图

简介

折线图是排列在工作表的列或行中的数据可以绘制到折线图中。折线图可以显示随时间(根据常用比例设置)而变化的连续数据,因此非常适用于显示在相等时间间隔下数据的趋势。在折线图中,类别数据沿水平轴均匀分布,所有值数据沿垂直轴均匀分布。(百度百科)

使用plot函数,array1(x轴),array2(y轴)为两组数据

1
plt.plot(array1,array2,[parameters,...])

如果需要表示日期,使用plot_date

1
plt.plot_date(date_array1,array2,[parameters,...])

实例1:AMD股票走势

我们这里使用农企一年的股票走势来举例,首先我们先获取收盘价和日期

1
date,close=np.loadtxt('Nov21-1yr.csv',delimiter = ',',converters = {0:bytespdate2num('%Y-%m-%d')},skiprows =1,usecols=(0,4),unpack=True)

接着我们用获得的数据来绘制折线图。正常情况下我们应该使用plot函数。但是由于我们涉及日期,为了更好地展现我们的图标。我们使用plot_date函数

1
plt.plot_date(date,close,linestyle='-',markersize =2.5,color='#147FB1',label='AMD')
  • linestyle: 这里规定折线线段的种类。使用plot_date时,默认为圆点(类似散点图),所以我们使用’-‘代表线段
  • markersize:这是图中每一个圆点的大小,当markersize和线段粗细相同时无法显示

>>> plt.show()

实例2:S&P500走势

动手试试用同样的办法来绘制S&P500最近一年(Nov 21,2015 - Nov 21,2016)的走势

比较S&P500与AMD

如果我们直接进行S&P500和农企的比较,会发现农企是一条贴近X轴的线(AMD是个位数,S&P是4位数)。所以在我们需要将S&P500的值缩小比例,具体方法是先求出每日的变化率,然后使用同一起点(AMD第一天的收盘价),根据变化率来模拟走势

这里我们需要两个S&P500的变量:spopen,spclose;和两个之前AMD的变量close,date

首先我们求出每日的变化率,得到一年的变化率列表

1
2
#(收盘价-开盘价)/开盘价
spchanges = np.divide(spclose-spopen,spopen)

接着是一个缩小比例的函数,假设第一天的收盘价(指数)作为第二天的开盘价(指数),接收一个起点价格和从该点开始一年的变动

1
2
3
4
5
6
def sp500_scale_down(start_point,changes):
stdsp = []
for each in changes:
start_point = start_point*(1+each)
stdsp.append(start_point)
return np.array(stdsp)

看看我们如何调用这个函数

1
stdsp = sp500_scale_down(close[-1]/(1+spchanges[-1]),spchanges[::-1])

这时我们获得了一个缩小版的S&P500指数列表stdsp。注意我们这个列表的内容都是从后往前的,即close[0]代表的是Nov 21,2016这一天而不是最靠前的Nov 21,2015.所以我们的第一天其实是列表的最后一个,即close[-1],spchanges同理。 而[::-1]表示反转列表,将其变回正常顺序。

绘制农企和S&P500的走势

1
2
plt.plot_date(date,close,linestyle='-',markersize =2.5,color='#147FB1',label='AMD')
plt.plot_date(date,stdsp[::-1],linestyle='-',markersize =2.5,color='#14B158',label='S&P500')

为什么我们的stdsp要在这里反转呢?因为我们之前提到过我们提取的数据是从后往前的,可是,我们画出来的数据方向不是反的,这说明plot_date函数接收一个“反”着的列表,而我们的stdsp列表是从前往后推的,我们需要将其反转

绘制图例

1
plt.legend(loc = 'upper left')

>>> plt.show()

条形图

简介

排列在工作表的列或行中的数据可以绘制到条形图中。条形图显示各个项目之间的比较情况。(百度百科)

绘制条形图,我们需要bar函数(纵向)或barh函数(横向),x_array代表分布在x轴的点,y_array代表高度

1
plt.bar(left=x_array,height=y_array,[parameters,...])

条形图实例:AMD4个季度营业额

首先我们获取农企最近四个季度的营业额,我们可以到AMD的官网,SEC里EDGAR的10Q或者其他第三方网站(Yahoo Finance)中找到

1
2
#单位:'M(百万)'
revenue = [958,832,1207,1307]

接着生成四个条形图的位置列表

1
2
3
4
#数量4个
N = 4
#生成x轴坐标列表[0,1.5,3.0,4.5]
x = np.arange(N)*1.5

使用bar函数来绘制条形图

1
plt.bar(left=x,height=revenue,color ='#51ADD8',width=0.5,align='center')
  • left 表示条形图在x轴的位置,以条形图左下角的点为坐标点
  • width 表示条形图的宽度
  • height 表示条形图高度
  • align=’center’ 文字居中

接着使用日期来标记,分别是四个季度出财报(10-Q)的日期,并定位

1
2
3
x_date=['12/26/2015','3/26/2016','6/25/2016','9/24/2016']
x_namepos =np.arange(4)*1.5
plt.xticks(x_namepos,x_date)

>>> plt.show()

条形图(横向)实例

前面我们知道了一个标准的条形图该如何绘制,有的时候我们会想要使用横向的条形图该怎么办,和bar差不多,matplotlib在这里提供了barh函数

1
plt.barh(left = 0,bottom=y,height=0.5,color ='#51ADD8',width=revenue,align='center')
  • bottom 表示条形图在y轴的位置,以条形图左上角的点为坐标点
  • width 横过来表示长度
  • height 竖过来表示宽度

>>> plt.show()

条形图对比实例

除了营业额,我们还可以来看一下两个条形图如何在一起对比,这里我们增加了农企的四个季度净利润

1
2
#单位:'M(百万)'
income = [-102,-109,69,-406]

之前我们设定了两个营业额条形图间距为1.5,添加了净额之后我们预期的结构是这样的

1
2
3
4
0.5:营业额1
0.5:净额1
0.5:间距
0.5:营业额2

所以绘制净额

1
plt.bar(left=x+0.5,height=income,color ='#51ADD8',width=0.5,alpha=0.75,align='center',label="Net Income")
  • left 在营业额的坐标点增加0.5(营业额width)

添加日期,图例

1
2
3
4
plt.legend(loc = 'upper left')
x_datepos =np.add(np.arange(4)*1.5,0.25)
x_date=['12/26/2015','3/26/2016','6/25/2016','9/24/2016']
plt.xticks(x_datepos,x_date)

>>> plt.show()

直方图

简介

直方图(Histogram)又称质量分布图。是一种统计报告图,由一系列高度不等的纵向条纹或线段表示数据分布的情况。 一般用横轴表示数据类型,纵轴表示分布情况。(百科词条)

绘制直方图我们使用hist函数,array表示变量集合,bins代表分布数量

1
plt.hist(array,bins=20,[parameters,...])

###实例:AMD股价变化率正态分布

获取股票价格

1
open_price,close_price=np.loadtxt('Nov21-1yr.csv',delimiter = ',',skiprows =1,usecols=(1,4),unpack=True)

获取变化率,使用百分比(乘以100)

1
diff = ((close_price-open_price)/open_price)*100

绘制直方图,分30个连续的区间,并使用正态分布

1
plt.hist(diff,bins=30,color='#EA4545',normed=True)

>>> plt.show()

饼图

扇形统计图是用整个圆表示总数,用圆内各个扇形的大小表示各部分数量占总数的百分数。通过扇形统计图可以很清楚地表示出各部分数量同总数之间的关系。百分数.。 扇形统计图可以清楚地表示各个项目与总数之间的关系。(百科词条)

绘制饼图很简单,我们只需要使用pie函数和一组数据即可完成

1
plt.pie(fracs,[parameters,...])

###实例:AMD资产结构

我们先找到农企2016第三季度的财报(10-Q),可以从公司官网或者SEC(美国证监会)找到,如下图

找到资产下的子分类,作为标签

1
labels = ['Cash','A/R','Inventories','GLOBF','Prepaid','Other Current','Property','Goodwill','Investments','Others']

对应的值为

1
asset_items = [1258,640,772,13,63,78,161,289,60,282]

如果是common size balance sheet的话,我们以资产总和为100%,每个自分类表示为对应的百分比

1
fracs = [round(each/sum(asset_items)*100,1) for each in asset_items]

绘制之前添加一组颜色,这组颜色对应每一个板块的颜色,可以自行选择

1
colors =['#f26e6e','#6e7ef2','#6ed1f2','#f29d6e','#e1f26e','#b7f26e','#a46ef2','#f2ec6e','#6ef2a3','#51a0aa']

将比例设置为1,使最终效果为圆形

1
plt.axes(aspect =1)

绘制

1
plt.pie(fracs,labels = labels,colors = colors,autopct = '%.1f')
  • labels 使用我们预设的标签
  • color 使用我们预设的颜色
  • autopct 将数字标记在上面

>>> plt.show()

哇咧!下面的字叠在一起了,没法看了。该怎么办呢?我们可以使用之前学过的箭头来指向特别窄的扇区,但是还有另一种更简单粗暴的办法。

转个角度

我们添加初始角度

1
plt.pie(fracs,labels = labels,colors = colors,autopct = '%.1f',startangle=100)

是不是好多了呢?

Reference