数据可视化笔记整理02

第二周笔记---「时序数据」和「比例数据」的可视化 [toc]

本周主题:图标选择。 学习目标:

  1. 了解时序数据的特点,熟练掌握不同类型的时序数据分别适合的图表类型;
  2. 了解比例型数据可视化的目的,学会根据数据集的特征去选择合适的图表;
  3. 实践:从给定的4个数据集中挑选两个,自行选择合适图表并进行可视化呈现;

1.大纲

图表的选择上 转载自木东居士

2.时序可视化

时序数据是指任何随着时间而变化的数据,如一天中气温随时间变化。(可用于时间序列分析) 前提,了解时间具有的特征:

  • 有序性:时间都是有序的,事件有先后顺序;
  • 周期性:许多自然或商业现象都有循环规律,如季节等周期性的循环;
  • 结构性:时间的尺度可以按照年,季度,月,周,日,时,分,秒等去切割。

时间数据按是否连续可分为:离散型时间连续型时间

2.1 离散时间的可视化

由于下面的数据没有找到合适的,所以没有自由发挥了.

定义:离散时间:数据来源于具体的时间点或者时间段,而且时间数据的可能取值时有限的。 适用图形:柱状图,堆叠柱状图,散点图。 (1)单一柱状图 适用场景

  • 适合表示离散时间数据的趋势,而且数据条个数一般不超过12条.
  • 适用于但类别数据的时间趋势表示,即系列值单一的数据.

图片展示; 单一柱状图示例

代码展示:

# 单一柱状图
plt.rcParams['font.sans-serif']=['SimHei']#设置字体以便支持中文


x = np.arange(4)#柱状图在横坐标上的位置
#列出你要显示的数据,数据的列表长度与x长度相同
y = age_num.values()

bar_width=0.3#设置柱状图的宽度
tick_label=age_num.keys()

# 记上标签,贴上数值
for a,b in zip(x,y):
    plt.text(a,b,'%.0f'%b,ha = 'center',va = 'bottom',fontsize=14)  # fontsize是字体

#绘制单一柱状图
plt.bar(x,y,bar_width,color='salmon',label='类别A')

plt.legend()#显示图例,即label
plt.xticks(x,tick_label)#显示x坐标轴的标签,即tick_label,调整位置,使其落在直方图中间位置
plt.savefig('squares.png') # 保存为squares.png
plt.show()

不适用场景:

  • 连续时间的变化趋势;
  • 数据条过多的离散时间的趋势展示(可以升维,划分更大的类)

(2)并列柱状图 要对比同意离散时间多个系列的情况,考虑使用并列柱状图,注意柱状图通常不超过三条,否则效果不好.

扫描二维码关注公众号,回复: 7973419 查看本文章

图示: 并列柱状图示例

代码:

# 并列柱状图
# 考虑将性别和年龄进行对比
x=np.arange(4)#柱状图在横坐标上的位置
#列出你要显示的数据,数据的列表长度与x长度相同
y1= [i[1] for i in ageSexCount.items() if i[0][1] == "FEMALE"]
y2= [i[1] for i in ageSexCount.items() if i[0][1] == "MALE"]

bar_width=0.3#设置柱状图的宽度
tick_label=age_num.keys()

#绘制并列柱状图
plt.title("并列柱状图demo")
plt.bar(x,y1,bar_width,color='salmon',label='女性')
plt.bar(x+bar_width,y2,bar_width,color='orchid',label='男性')

# 记上标签,贴上数值
for a,b in zip(x,y1):
    plt.text(a,b,'%.0f'%b,ha = 'center',va = 'bottom',fontsize=14)  # fontsize是字体大小
for a,b in zip(x,y2):
    plt.text(a+0.2,b,'%.0f'%b,ha = 'left',va = 'bottom',fontsize=14)  # fontsize是字体大小,通过不断调整a和b的大小调整标签位置

plt.legend()#显示图例,即label
plt.xticks(x+bar_width/2,tick_label)#显示x坐标轴的标签,即tick_label,调整位置,使其落在两个直方图中间位置
plt.savefig("demo2.png")
plt.show()

(3)堆叠柱状图

单一柱状图展示各个离散时间点,我们想知道总体构成的时候就需要引入堆叠柱状图.

  • 普通柱状图,展示实际体量;
  • 百分比堆叠柱状图,展示相对体量.

1)普通堆叠柱状图

普通堆叠柱状图,整体的构成部分,最好不要超过5项。若实际构成项大于5个时,需要做适当的归类,以保证图表重点突出。

图示: 堆叠柱状图示例

代码:

# 堆叠柱状图
# 这里不能用dict_keys,只能转化成list
name_list = [i for i in age_num.keys()]
num_list1 = [i[1] for i in ageSexCount.items() if i[0][1] == "FEMALE"]
num_list2 = [i[1] for i in ageSexCount.items() if i[0][1] == "MALE"]
z1 = plt.bar(range(len(num_list)), num_list1, label='女性', fc='b')
z2 = plt.bar(range(len(num_list)), num_list2, bottom=num_list, label='男性', tick_label=name_list, fc='g')
plt.ylabel("单位:人", # 坐标轴文本标签
          fontproperties="stkaiti", # 中文字体
           rotation="horizontal", # 文本方向,还可以为vertical(默认)
           fontsize = 14, # 字号
           verticalalignment = "bottom", # 设置垂直对齐,还可以为top或center
           horizontalalignment = "center" # 还可以为left或者right
          )
# 显示高度
for a,b in zip(x,y1):
    plt.text(a,b,'%.0f'%b,
             ha = 'center',
             va = 'bottom',# va可以为bottom,center,top
             fontsize=14)  # fontsize是字号
plt.legend()
plt.savefig("demo3.png")
plt.show()
# 堆叠不太熟悉,似乎有点问题

2)百分比堆叠柱状图 百分比python不太会做,只能用excel或者tableau进行加工了.这里借助别人的例子. 展示: 百分比堆叠柱状图示例

代码:

import numpy as np
import matplotlib.pyplot as plt


category_names = ['Strongly disagree', 'Disagree',
                  'Neither agree nor disagree', 'Agree', 'Strongly agree']
results = {
    'Question 1': [10, 15, 17, 32, 26],
    'Question 2': [26, 22, 29, 10, 13],
    'Question 3': [35, 37, 7, 2, 19],
    'Question 4': [32, 11, 9, 15, 33],
    'Question 5': [21, 29, 5, 5, 40],
    'Question 6': [8, 19, 5, 30, 38]
}


def survey(results, category_names):
    labels = list(results.keys())
    # 获取标签
    data = np.array(list(results.values()))
    # 获取具体数值
    data_cum = data.cumsum(axis=1)
    # 逐项加和
    category_colors = plt.get_cmap('RdYlGn')(np.linspace(0.15, 0.85, data.shape[1]))

    """
    在cmmap中取出五组颜色
    category_colors:
        [[0.89888504 0.30549789 0.20676663 1.        ]
         [0.99315648 0.73233372 0.42237601 1.        ]
         [0.99707805 0.9987697  0.74502115 1.        ]
         [0.70196078 0.87297193 0.44867359 1.        ]
         [0.24805844 0.66720492 0.3502499  1.        ]]
    
    """

    print(category_colors)
    # 常见颜色序列, 在cmap中取色

    fig, ax = plt.subplots(figsize=(5, 9))
    # 绘图
    # ax.invert_xaxis()
    # 使其更符合视觉习惯,index本身从下到上
    ax.yaxis.set_visible(False)
    ax.set_xticklabels(labels=labels, rotation=90)
    # 不需要可见
    ax.set_ylim(0, np.sum(data, axis=1).max())

    for i, (colname, color) in enumerate(zip(category_names, category_colors)):
        heights = data[:, i]
        # 取第一列数值
        starts = data_cum[:, i] - heights
        # 取每段的起始点
        ax.bar(labels, heights, bottom=starts, width=0.5,
                label=colname, color=color)
        xcenters = starts + heights / 2
        r, g, b, _ = color
        text_color = 'white' if r * g * b < 0.5 else 'darkgrey'
        for y, (x, c) in enumerate(zip(xcenters, heights)):
            ax.text(y, x, str(int(c)), ha='center', va='center',
                    color=text_color, rotation = 90)
    ax.legend()
    return fig, ax


survey(results, category_names)
plt.show()

(3)散点图

散点图一般表示两个变量之间的相关关系. 表示离散时间数据的时候,其表达的是某一变量随时间的变化关系. 柱状图是用高度作为数值的映射,而散点图是用位置来作为数值的视觉通道.

图示 散点图

代码

#产生测试数据  
x = np.arange(1,10)  
y = x  
fig = plt.figure()  
ax1 = fig.add_subplot(111)  
#设置标题  
ax1.set_title('Scatter Plot')  
#设置X轴标签  
plt.xlabel('X')  
#设置Y轴标签  
plt.ylabel('Y')  
#画散点图  
sValue = x*10  
ax1.scatter(x,y,s=sValue,c='r',marker='x')  
#设置图标  
plt.legend('x1')  
#显示所画的图  
plt.savefig("demo5.png")
plt.show()  

2.2 连续时间

连续时间:连续时间数据的可视化和离散时间数据的可视化相似. 因为就算数据连续的,我们采集的数据大部分是离散且有限. 可以看出四种趋势:长期性趋势,季节性趋势,周期性趋势,不规则波动. (1)折线图 折线图用于显示数据在一个连续的时间间隔或者时间跨度的变化. 在折线图中,一般水平轴(x轴)表示时间的推移,并且间隔相同,而垂直轴(y轴)代表不同时刻的数据的大小.

折线图包括:点线图,折线图,曲线图.

  • 点线图:当数据集中的数据项有限,不超过12个小时,采用此种点线图比较合适.
  • 折线图:当数据集中的数据项比较多,大于12条时,采用点线图,会让整条线上的点很密集,影响看数据的趋势,采用折线图;
  • 曲线图:相比折线图,曲线图相邻节点的连线更加平滑.

点线图 图示: 点线图示例

代码:

# 点线图
# coding:utf8
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
x = [i for i in age.keys()]
y = [i for i in age.values()]
ax1.plot(x,y,'c*-', label='number of age', linewidth=2)

# 坐标轴标记

ax1.set_title("relationship between age and number")
ax1.set_xlabel("danwei:ren")
ax1.set_ylabel("danwei:nianling")

ax1.legend()
plt.savefig("demo6.png")
plt.show()

折线图 图示: 折线图示例

代码:

# 点线图
# coding:utf8
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
x = [i for i in age.keys()]
y = [i for i in age.values()]
ax1.plot(x,y)

# 坐标轴标记

ax1.set_title("relationship between age and number")
ax1.set_xlabel("danwei:ren")
ax1.set_ylabel("danwei:nianling")

ax1.legend()


plt.savefig("demo7.png")
plt.show()

曲线图(插值法)(插值是曲线一定经过点,拟合是曲线不一定经过点)

图示 插值法示例一 插值法示例二

代码

#coding:utf8
# 实现平滑曲线图
# 两种方式:插值法或者拟合(机器学习生成的我认为可以归为拟合)

# 插值法
from scipy import interpolate

x = [i for i in age.keys() if i != "age"]
x.sort()
y = list(age.values())[1:]
func = interpolate.interp1d(x, y, kind='cubic')


# 插值法之后的x轴值,表示从0到9的若干个数
xnew = np.linspace(x[1], x[-1], 10000)
# 利用xnew和func函数生成ynew,xnew的数量等于ynew数量
ynew = func(xnew)

# 画图部分
# 原图
# plt.plot(x, y, 'ro-')
# 拟合之后的平滑曲线图
plt.plot(xnew, ynew)
# plt.savefig("demo8.png")
plt.savefig("demo9.png")
plt.show()


# 注意可能会出现如下错误:
# TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
# 原因是元素个数不一致导致。
# 参见链接:https://www.cnblogs.com/Yanjy-OnlyOne/p/11189547.html

(2)阶梯图 阶梯图常用来表示,某两个相邻的节点,后一个节点的数据相对前一个节点数据的升降变化,一般用在商品价格变动,股票价格变动,税率变化等.

阶梯图有三个关键值: 1)前一时间节点数值; 2)当前时间节点数值; 3)当前节点较前一节点的差值.

图示: 阶梯图

代码:

# 阶梯图(原来准备的数据用不了不清楚为什么)
import matplotlib.pyplot as plt
import numpy as np

x = [1,2,3,4,5,6,7,8,9,10]
y = [i/2 for i in x]

plt.step(x, y, color="#8dd3c7", where="pre", lw=2)

plt.xlim(0, 11)
plt.xticks(np.arange(1, 11, 1))
plt.ylim(0, 6)

plt.savefig("demo10.png")
plt.show()

(3)拟合曲线图 之前说插值的时候有所涉及,比如说做传统的回归或者流行的机器学习,在此不做扩展.

3.比例型数据可视化

1.饼图 饼图是通过角度来映射各类别对应的数值。 当构成整体的数据项较少时,采用饼图是一种不错的选择。 但是一个维度下属性较多会失去美感,杂乱不堪,重点不突出。 因此,对于饼图来说,建议扇区个数最大值在5~7个之间。当数据项超过一定数量时,可以按照占比,把排名最末的几项归位「其他」。

  • 当数据项n<=6时,直接显示各扇区原始类别的名称。
  • 当数据项n>6时,直接显示占比排名TOP5扇区的原始类别名称,剩余的数据项则归为「其他」。 图示: 饼图示例

代码:

# coding:utf8
# 饼图
x = age_rangeCount.keys()
y = age_rangeCount.values()
# -*- coding: utf-8 -*-
import numpy as np  
import matplotlib.mlab as mlab  
import matplotlib.pyplot as plt  
labels=x
Y=y
 
fig = plt.figure()
plt.pie(Y,labels=labels,autopct='%1.2f%%') #画饼图(数据,数据对应的标签,百分数保留两位小数点)
plt.title("Pie chart")
  
plt.savefig("demo11.png")
plt.show()  

# 无法显示中文怎么办?

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False

2.环形图

环形图中心部位是空的,可以放置标签、整体数值、平均数值或其他内容。环形图中,数据项的分类和饼图类似,就不在赘述。 图示: 环形图示例

代码:

import matplotlib as mpl
import matplotlib.pyplot as plt

# 设置图片大小
plt.figure(figsize = (10, 8))

# 生成数据
X = x
Y = y
colors = ['c', 'r', 'y', 'g']



# 内环
wedges2, texts2, autotexts2 = plt.pie(Y,
    autopct = '%3.1f%%',
    radius = 0.7, # 控制半径
    pctdistance = 0.75, # 控制文字位置
    colors = colors,
    startangle = 180,
    textprops = {'color': 'w'},
    wedgeprops = {'width': 0.3, 'edgecolor': 'w'}
)

# 图例
plt.legend(wedges1,
          X,
          fontsize = 12,
          title = '年龄划分',
          loc = 'center right',
          bbox_to_anchor = (1, 0.6))

# 设置文本样式
plt.setp(autotexts1, size=15, weight='bold')
plt.setp(texts1, size=15)

# 标题
plt.title('年龄与人数关系', fontsize=20)

plt.savefig('demo12.png')
plt.show()

双环形图 高级环形图(效果超级赞,不放图了,抄来的)

from matplotlib import pyplot as plt

import numpy as np 

fig = plt.figure(figsize=[13.44,7.5],facecolor=(235/255,235/255,235/255))
ax1=fig.add_subplot(1,1,1,facecolor=(235/255,235/255,235/255),projection='polar')
ax1.axis('off')


ax1.barh(height=0.005,width=-0.4*3,y=0.4,color=(243/255,133/255,36/255))
ax1.scatter(-0.4*3,0.4,color=(243/255,133/255,36/255))

ax1.barh(height=0.005,width=-0.5*3,y=0.5,color=(243/255,10/255,36/255))
ax1.scatter(-0.5*3,0.5,color=(243/255,10/255,36/255))

ax1.barh(height=0.005,width=-2*2,y=0.6,color=(243/255,133/255,36/255))
ax1.scatter(-2*2,0.6,color=(243/255,133/255,36/255))

ax1.barh(height=0.005,width=-0.5*np.pi*2,y=0.7,color=(243/255,133/255,36/255))
ax1.scatter(-0.5*np.pi*2,y=0.7,color=(243/255,133/255,36/255))

3.百分比堆叠柱状图 当比例数据中存在多个父系列,每个父系列又由多个子类构成,且各个系列的子类相同时,此时展示比例数据,可以采用百分比堆叠柱状图。

  • 各个系列对应的柱形条的高度是相同的,顶部刻度都为100%。
  • 每根柱形条内部,各子项柱形条的高度,代表在该系列中的占比。
  • 当各系列的子类数目较少时,可以直接在矩形内部展示占比;当数目较多时,建议隐藏。
  • 当各系列的子类目较多时,为了保证重点突出和视觉效果,需要对子类目进行归类,归类方法参照饼图。

作图方法参照上文.

4.百分比堆叠面积图

当比例数据中存在多个父系列,且父系列的数据类型为时间,要分析父系列的各构成部分占比随时间的变化趋势,此时可以采用堆叠面积图来表示比例关系的变化。如果从某一点上对堆叠面积图进行垂直切片,那么就可以得到该时间段上的比例分布情况。 暂未找到用Python写的教程,这里用Excel实现. (Excel写的很详细了,直接选取即可,这里因为没有太好的数据,做出来效果很差,就不展示了)

5.矩形树图

矩形树图,是一种基于面积的可视化方法。外部矩形代表父级类别,内部矩形代表子类别。相比于其他表示比例型的数据,矩形树图更适合展示具有树状结构的数据。 树状结构,简单理解,就是首先按一级分类来观测各构成部分的比例,然后再看某个一级分类下,是由哪些二级分类构成的,依次类推,逐步细化,可以直到叶子结点。

这里推荐用tableau制作矩形树图.

4.总结

时序数据,主要目的是研究数据随时间的变化,这种变化包括总量的变化、构成部分的变化、以及变化的趋势和规律。 比例数据,区别于其他数据类型的一个关键,在于它是为了寻求整体中的各个构成部分,及其相互关系。

5.问题回答

柱状图、趋势图中,坐标轴不从0开始可以吗?说明原因?

当然可以,而且在某种程度上还会起警示或误导的作用. 比如说30,32,这种情况放在0看波动很平缓,如果从28开始看的话波动剧烈,容易误导人.

猜你喜欢

转载自www.cnblogs.com/smithpath/p/11929235.html