我心中的王者:Python-第23章 数据图表的设计

我心中的王者:Python-第23章 数据图表的设计

本章所叙述的重点是数据图形的绘制,所使用的工具是matplotlib绘图库模块,使用前需先安装:

pip install matplotlib

matplotlib是一个庞大的绘图库模块,本章我们只导入其中的pyplot子模块就可以完成许多图表绘制,如下所示,未来就可以使用plt调用相关的方法。

import matplotlib.pyplot as plt

本章将叙述matplotlib的重点,更完整使用说明可以参考下列网站。

http://matplotlib.org

23-1 绘制简单的折线图

这一节将从最简单的折线图开始解说。

23-1-1 显示绘制的图形show( )

这个show( )方法主要是显示所绘制的图形,当我们绘制图形完成后,可以调用此方法。

23-1-2 画线plot( )

应用方式是将含数据的列表当参数传给plot( ),列表内的数据会被视为y轴的值,x轴的值会依列表值的索引位置自动产生。

程序实例ch23_1.py:绘制折线的应用,数据基本上是1-8的平方值序列。

# ch23_1.py
import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25, 36, 49, 64]
plt.plot(squares)
plt.show()

执行结果
在这里插入图片描述

从上述执行结果可以看到左下角的轴刻度不是(0,0),我们可以使用axis( )设定x,y轴的最小和最大刻度。

程序实例ch23_1_1.py:重新设计ch23_1.py,将轴刻度x轴设为0,8,y轴刻度设为0,70。

# ch23_1_1.py
import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25, 36, 49, 64]
plt.plot(squares)
plt.axis([0, 8, 0, 70])     
plt.show()

执行结果
在这里插入图片描述

23-1-3 线条宽度linewidth

使用plot( )时,可以多加一个linewidth(缩写是lw)参数设定线条的粗细。

程序实例ch23_2.py:设定线条宽度是3。

# ch23_2.py
import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25, 36, 49, 64]
plt.plot(squares, linewidth=3)
plt.show()

执行结果

在这里插入图片描述

23-1-4 标题的显示

目前matplotlib模块不支持中文显示,下列是几个图表重要的方法。

title( ):图表标题。

xlabel( ):x轴标题。

ylabel( ):y轴标题。

上述方法可以显示默认大小是12的字体,它的语法如下:

 title(标题名称, fontsize=数值大小)  # 同时可用在xlabel( )和ylabel( )

程序实例ch23_3.py:使用默认字号为图表与x/y轴建立标题。

# ch23_3.py
import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25, 36, 49, 64]
plt.plot(squares, linewidth=3)
plt.title("Test Chart")
plt.xlabel("Value")
plt.ylabel("Square")
plt.show()

执行结果 可参考下方上图。
在这里插入图片描述

程序实例ch23_4.py:使用设定字号为图表与x/y轴建立标题。

# ch23_4.py
import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25, 36, 49, 64]
plt.plot(squares, linewidth=3)
plt.title("Test Chart", fontsize=24)
plt.xlabel("Value", fontsize=16)
plt.ylabel("Square", fontsize=16)
plt.show()

执行结果 可参考上方下图。

23-1-5 坐标轴刻度的设定

在设计图表时可以使用tick_params( )设计设定坐标轴的刻度大小、颜色以及应用范围。

     tick_params(axis=‘xx', labelsize=xx, color=‘xx')  # labelsize的xx代表刻
 度大小

如果axis的xx是both代表应用到x和y轴,如果xx是x代表应用到x轴,如果xx是y代表应用到y轴。color则是设定刻度的线条颜色,例如,red代表红色。

程序实例ch23_5.py:使用不同刻度与颜色的应用。

# ch23_5.py
import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25, 36, 49, 64]
plt.plot(squares, linewidth=3)
plt.title("Test Chart", fontsize=24)
plt.xlabel("Value", fontsize=16)
plt.ylabel("Square", fontsize=16)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

23-1-6 修订图表的起始值

从上图可以看到平方列表的值是有8个数据,依照Python语法起始数字是从0开始,所以整个数值到7结束。但是在我们日常生活呈现的报表中,通常数字是从1开始,为了要做这个修订,可以再增加一个列表,这个列表主要是设定数值索引,细节可参考下列实例的第5行。

程序实例ch23_6.py:修订图表的起始值,读者应该注意到x轴标计从1开始。

# ch23_6.py
import matplotlib.pyplot as plt

squares = [1, 4, 9, 16, 25, 36, 49, 64]
seq = [1,2,3,4,5,6,7,8]
plt.plot(seq, squares, linewidth=3)
plt.title("Test Chart", fontsize=24)
plt.xlabel("Value", fontsize=16)
plt.ylabel("Square", fontsize=16)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

23-1-7 多组数据的应用

目前所有的图表皆只有一组数据,其实可以扩充多组数据,只要在plot( )内增加数据列表参数即可。此时plot( )的参数如下:

 plot(第一组数据, 第二组数据, … )

程序实例ch23_7:设计多组数据图的应用。

# ch23_7.py
import matplotlib.pyplot as plt

data1 = [1, 4, 9, 16, 25, 36, 49, 64]           # data1线条
data2 = [1, 3, 6, 10, 15, 21, 28, 36]           # data2线条
seq = [1,2,3,4,5,6,7,8]
plt.plot(seq, data1, seq, data2)                # data1&2线条
plt.title("Test Chart", fontsize=24)
plt.xlabel("x-Value", fontsize=14)
plt.ylabel("y-Value", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

上述以不同颜色显示线条是系统默认,我们也可以自定义线条色彩。

23-1-8 线条色彩与样式

如果想设定线条色彩,可以在plot( )内增加下列参数设定,下列是常见的色彩表。
在这里插入图片描述

下列是常见的样式表。可以混合使用,例如,‘r-.’代表红色虚点线。
在这里插入图片描述

程序实例ch23_8.py:采用不同色彩与线条样式绘制图表。

# ch23_8.py
import matplotlib.pyplot as plt

data1 = [1, 2, 3, 4, 5, 6, 7, 8]                # data1线条
data2 = [1, 4, 9, 16, 25, 36, 49, 64]           # data2线条
data3 = [1, 3, 6, 10, 15, 21, 28, 36]           # data3线条
data4 = [1, 7, 15, 26, 40, 57, 77, 100]         # data4线条

seq = [1, 2, 3, 4, 5, 6, 7, 8]
plt.plot(seq, data1, 'g--', seq, data2, 'r-.', seq, data3, 'y:', seq, data4, 'k.')   
plt.title("Test Chart", fontsize=24)
plt.xlabel("x-Value", fontsize=14)
plt.ylabel("y-Value", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

在上述第10行最右边‘k.’代表绘制黑点而不是绘制线条,由这个观念读者应该可以使用不同颜色绘制散点图(23-2节会介绍另一个方法scatter( )绘制散点图)。上述格式应用是很活的,如果我们使用‘-*’可以绘制线条,同时在指定点加上星星标记。

程序实例ch23_9.py:重新设计ch23_8.py绘制线条,同时为各个点加上标记。
在这里插入图片描述

执行结果
在这里插入图片描述

23-1-9 刻度设计

目前所有绘制图表x轴和y轴的刻度皆是plot( )方法针对所输入的参数采用默认值设定,请先参考下列实例。

程序实例ch23_10.py:有一个假设3大品牌车辆2018-2020的销售数据如下:

Benz 3367 4120 5539

BMW 4000 3590 4423

Lexus 5200 4930 5350

请使用上述方法将上述数据绘制成图表。

# ch23_10.py
import matplotlib.pyplot as plt

Benz = [3367, 4120, 5539]               # Benz线条
BMW = [4000, 3590, 4423]                # BMW线条
Lexus = [5200, 4930, 5350]              # Lexus线条

seq = [2018, 2019, 2020]                # 年度
plt.plot(seq, Benz, '-*', seq, BMW, '-o', seq, Lexus, '-^')   
plt.title("Sales Report", fontsize=24)
plt.xlabel("Year", fontsize=14)
plt.ylabel("Number of Sales", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

上述程序最大的遗憾是x轴的刻度,对我们而言,其实只要有2018-2020这3个年度的刻度即可,还好可以使用pyplot模块的xticks( )/yticks( )分别设定x/y轴刻度,可参考下列实例。

程序实例ch23_11.py:重新设计ch23_10.py,自行设定刻度,这个程序的重点是第9行,将seq列表当参数放在plt.xticks( )内。

# ch23_11.py
import matplotlib.pyplot as plt

Benz = [3367, 4120, 5539]               # Benz线条
BMW = [4000, 3590, 4423]                # BMW线条
Lexus = [5200, 4930, 5350]              # Lexus线条

seq = [2018, 2019, 2020]                # 年度
plt.xticks(seq)                         # 设定x轴刻度
plt.plot(seq, Benz, '-*', seq, BMW, '-o', seq, Lexus, '-^')   
plt.title("Sales Report", fontsize=24)
plt.xlabel("Year", fontsize=14)
plt.ylabel("Number of Sales", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

23-1-10 图例legend( )

程序实例ch23_11.py所建立的图表,坦白说已经很好了,缺点是缺乏各种线条代表的意义,在Excel中称图例(legend),下列笔者将直接以实例说明。

程序实例ch23_12.py:为ch23_11.py建立图例。

# ch23_12.py
import matplotlib.pyplot as plt

Benz = [3367, 4120, 5539]               # Benz线条
BMW = [4000, 3590, 4423]                # BMW线条
Lexus = [5200, 4930, 5350]              # Lexus线条

seq = [2018, 2019, 2020]                # 年度
plt.xticks(seq)                         # 设定x轴刻度
lineBenz, = plt.plot(seq, Benz, '-*', label='Benz')
lineBMW, = plt.plot(seq, BMW, '-o', label='BMW')
lineLexus, = plt.plot(seq, Lexus, '-^', label='Lexus')
plt.legend(handles=[lineBenz, lineBMW, lineLexus], loc='best')
plt.title("Sales Report", fontsize=24)
plt.xlabel("Year", fontsize=14)
plt.ylabel("Number of Sales", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

这个程序最大不同在第10-12行,以第10行解说。

 lineBenz, = plt.plot(seq, Benz, ‘-*', label=‘Benz')  # 留意linzBenz,

上述调用plt.plot( )时需同时设定label,注意返回值的使用,变量右边的‘,’,最后使用第13行方式执行legend( )图例的调用。其中参数loc可以设定图例的位置,可以有下列设定方式:

‘best’:0,

‘upper right’:1

‘upper left’:2,

‘lower left’:3,

‘lower right’:4,

‘right’:5, (与‘center right’相同)‘center left’:6,

‘center right’:7,

‘lower center’:8,

‘upper center’:9,

‘center’:10,如果省略loc设定,则使用预设‘best’,在应用时可以使用设定整数值,例如,设定loc=0与上述效果相同。若是顾虑程序可读性建议使用文字符串方式设定,当然也可以直接设定数字,可以小小炫耀或迷惑不懂的人吧!

在这里插入图片描述

执行结果 下方右图。

在这里插入图片描述

经过上述解说,我们已经可以将图例放在图表内了,如果想将图例放在图表外,笔者先解释坐标,在右图表内左下角位置是(0,0),右上角是(1,1)。

首先须使用bbox_to_anchor( )当作legend( )的一个参数,设定锚点(anchor),也就是图例位置,例如,我们想将图例放在图表右上角外侧,需设定loc=‘upper left’,然后设定bbox_to_anchor(1,1)。

程序实例ch23_12_5.py:将图例放在图表右上角外侧。
在这里插入图片描述

上述最大的缺点是由于图表与Figure 1的留白不足,造成无法完整显示图例。Matplotlib模块内有tight_layout( )函数,可利用设定pad参数在图表与Figure 1间设定留白。

程序实例ch23_12_6.py:设定pad=7,重新设计ch23_12_5.py。

执行结果 下方左图。

在这里插入图片描述

很明显我们改善了图例显示不完整的问题了。如果将pad改为h_pad/w_pad可以分别设定高度/宽度的留白。

23-1-11 保存图片文件

图表设计完成,可以使用savefig( )保存图片文件,这个方法需放在show( )的前方,表示先存储再显示图表。

程序实例ch23_13.py:扩充ch23_12.py,在屏幕显示图表前,先将图表存入当前文件夹的out23_13.py。执行结果读者可以在ch23文件夹看到out23_13.jpg文件。

# ch23_13.py
import matplotlib.pyplot as plt

Benz = [3367, 4120, 5539]                           # Benz线条
BMW = [4000, 3590, 4423]                            # BMW线条
Lexus = [5200, 4930, 5350]                          # Lexus线条

seq = [2018, 2019, 2020]                            # 年度
plt.xticks(seq)                                     # 设定x轴刻度
lineBenz, = plt.plot(seq, Benz, '-*', label='Benz')
lineBMW, = plt.plot(seq, BMW, '-o', label='BMW')
lineLexus, = plt.plot(seq, Lexus, '-^', label='Lexus')
plt.legend(handles=[lineBenz, lineBMW, lineLexus])
plt.title("Sales Report", fontsize=24)
plt.xlabel("Year", fontsize=14)
plt.ylabel("Number of Sales", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.savefig('out23_13.jpg', bbox_inches='tight')    # 存档
plt.show()

上述plt.savefig( )第一个参数是所存的文件名,第二个参数代表将图表外多余的空间删除。

23-2 绘制散点图scatter( )

23-2-1 基本散点图的绘制

绘制散点图可以使用scatter( ),最基本语法应用如下:

 scatter(x, y, s, c)  # 更多参数应用未来几小节会解说

上述相当于可以在(x,y)位置绘图,其中(0,0)位置在左下角,x轴刻度往右增加,y轴刻度往上增加。s是绘图点的大小,预设是20。c是颜色,预设是蓝色。暂时s与c皆用默认值处理,未来将一步一步解说。

程序实例ch23_14.py:在坐标轴(5,5)绘制一个点。

# ch23_14.py
import matplotlib.pyplot as plt

plt.scatter(5, 5)
plt.show()

执行结果
在这里插入图片描述

23-2-2 绘制系列点

如果我们想绘制系列点,可以将系列点的x轴值放在一个列表,y轴值放在另一个列表,然后将这2个列表当参数放在scatter( )即可。

程序实例ch23_15.py:绘制系列点的应用。

# ch23_15.py
import matplotlib.pyplot as plt

xpt = [1,2,3,4,5]
ypt = [1,4,9,16,25]
plt.scatter(xpt, ypt)
plt.show()

执行结果
在这里插入图片描述

在程序设计时,有些系列点的坐标可能是由程序产生,其实应用方式是一样的。另外,可以在scatter( )内增加color(也可用c)参数,设定点的颜色。

程序实例ch23_16.py:绘制黄色的系列点,这个系列点有100个点,x轴的点由range(1,101)产生,相对应y轴的值则是x的平方值。

# ch23_16.py
import matplotlib.pyplot as plt

xpt = list(range(1,101))        # 建立1-100序列x坐标点
ypt = [x**2 for x in xpt]       # 以x平方方式建立y坐标点
plt.scatter(xpt, ypt, color='y')
plt.show()

执行结果
在这里插入图片描述

上述程序第6行使用直接的指定色彩,也可以使用RGB(Red, Green, Blue)颜色模式设定色彩,RGB( )内每个参数数值在0.0到1.0之间。

23-2-3 设定绘图区间

可以使用axis( )设定绘图区间,语法格式如下:

 axis([xmin, xmax, ymin, ymax]) # 分别代表x和y轴的最小和最大区间

程序实例ch23_17.py:设定绘图区间为[0,100,0,10000]的应用,读者可以将这个执行结果与ch23_16.py作比较。另外,第7行以不同方式建立色彩。

# ch23_17.py
import matplotlib.pyplot as plt

xpt = list(range(1,101))        # 建立1-100序列x坐标点
ypt = [x**2 for x in xpt]       # 以x平方方式建立y坐标点
plt.axis([0, 100, 0, 10000])    # 留意参数是列表
plt.scatter(xpt, ypt, c=(0, 1, 0))  # 绿色
plt.show()

执行结果
在这里插入图片描述

上述程序第5行是依据xpt列表产生ypt列表值的方式,由于在网络上大部分的文章使用数组方式产生图表列表,所以下一节笔者将对此做说明,期待可为读者建立基础。

23-3 Numpy模块

Numpy是Python的一个扩充模块,主要是可以支持多维度空间的数组与矩阵运算,本节笔者将使用其最简单的产生数组功能做解说,由此可以将这个功能扩充到数据图表的设计。使用前我们需导入Numpy模块,如下所示:

 import Numpy as np

23-3-1 建立一个简单的数组linspace( )和arange( )

在Numpy模块中最基本的就是linspace( )方法,使用它可以很方便产生相同等距的数组,它的语法如下:

 linspace(start, end, num)  # 这是最常用简化的语法

start是起始值,end是结束值,num是设定产生多少个等距的数组值,num的默认值是50。

在网络上阅读他人使用Python设计的图表时,另一个常看到产生数组的方法是arange( ),语法如下:

 arange(start, stop, step)  # start和step是可以省略

start是起始值如果省略默认值是0,stop是结束值但是所产生的数组通常不包含此值,step是数组相邻元素的间距如果省略默认值是1。

程序实例ch23_18:建立0, 1, …, 9, 10的数组。

# ch23_18.py
import numpy as np

x1 = np.linspace(0, 10, num=11)     # 使用linspace()产生数组
print(type(x1), x1)
x2 = np.arange(0,11,1)              # 使用arange()产生数组
print(type(x2), x2)
x3 = np.arange(11)                  # 简化语法产生数组
print(type(x3), x3)

执行结果

<class 'numpy.ndarray'> [ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9. 10.]
<class 'numpy.ndarray'> [ 0  1  2  3  4  5  6  7  8  9 10]
<class 'numpy.ndarray'> [ 0  1  2  3  4  5  6  7  8  9 10]

23-3-2 绘制波形

在初中数学中我们有学过sin( )和cos( )观念,其实有了数组数据,我们可以很方便绘制sin和cos的波形变化。

程序实例ch23_19.py:绘制sin( )和cos( )的波形,在这个实例中调用plt.scatter( )方法2次,相当于也可以绘制2次波形图表。

# ch23_19.py
import matplotlib.pyplot as plt
import numpy as np

xpt = np.linspace(0, 10, 500)           # 建立含500个元素的数组
ypt1 = np.sin(xpt)                      # y数组的变化
ypt2 = np.cos(xpt)
plt.scatter(xpt, ypt1, color=(0, 1, 0)) # 绿色
plt.scatter(xpt, ypt2)                  # 预设颜色
plt.show()

执行结果
在这里插入图片描述

23-3-3 建立不等宽度的散点图

在scatter( )方法中,(x,y)的数据可以是列表也可以是矩阵,预设所绘制点大小s的值是20,这个s可以是一个值也可以是一个数组数据,当它是一个数组数据时,利用更改数组值的大小,我们就可以建立不同大小的散点图。

在我们使用Python绘制散点图时,如果将2个点之间绘了上百或上千个点,则可以产生绘制线条的视觉,如果再加上每个点的大小不同,且依一定规律变化,则可以有特别效果。

程序实例ch23_20.py:建立一个不等宽度的图形。

# ch23_20.py
import matplotlib.pyplot as plt
import numpy as np

xpt = np.linspace(0, 5, 500)                        # 建立含500个元素的数组
ypt = 1 - 0.5*np.abs(xpt-2)                         # y数组的变化
lwidths = (1+xpt)**2                                # 宽度数组  
plt.scatter(xpt, ypt, s=lwidths, color=(0, 1, 0))   # 绿色
plt.show()

执行结果
在这里插入图片描述

23-3-4 色彩映射color mapping

至今我们针对一组数组(或列表)所绘制的图皆是单色,若是以ch23_20.py第8行为例,色彩设定是color=(0,1,0),这是固定颜色的用法。在色彩的使用中是允许色彩也是数组(或列表)随着数据而变化,此时色彩的变化是根据所设定的色彩映射值(color mapping)而定,例如有一个色彩映射值是rainbow,内容如下:
在这里插入图片描述

在数组(或列表)中,数值低的值颜色在左边,会随着数值变高颜色往右边移动。当然在程序设计中,我们需在scatter( )中增加color(也可用c)设定,这时color的值就变成一个数组(或列表)。然后我们需增加参数cmap(英文是color map),这个参数主要是指定使用哪一种色彩映射值。

程序实例ch23_21.py:色彩映射的应用。

# ch23_21.py
import matplotlib.pyplot as plt
import numpy as np

x = np.arange(100)
y = x
t = x
plt.scatter(x, y, c=t, cmap='rainbow')
plt.show()

执行结果
在这里插入图片描述

有时候我们在程序设计时,色彩映射也可以设定是根据x轴的值变化,或是y轴的值变化,整个效果是不一样的。

程序实例ch23_22.py:重新设计ch23_20.py,主要是设定差别是固定点的宽度为50,将色彩改为依y轴值变化,同时使用hsv色彩映射表。
在这里插入图片描述

程序实例ch23_23.py:重新设计ch23_22.py,主要是将将色彩改为依x轴值变化。

执行结果 如下方左图。
在这里插入图片描述

执行结果 如下方右图。

在这里插入图片描述

目前matplotlib协会所提供的色彩映射内容如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数据源matplotlib协会网址如下:

http://matplotlib.org/examples/color/colormaps_reference.html

如果有一天你做大数据研究,当收集了无数的数据后,可以将数据以图表显示,然后用色彩判断整个数据趋势。

23-4 随机数的应用

随机数在统计的应用中是非常重要的知识,这一节笔者试着用随机数方法,了解Python的随机数分布。这一节将介绍下列随机方法:

 np.random.random(N)  # 传回N个0.0至1.0之间的数字

23-4-1 一个简单的应用

程序实例ch23_24.py:产生100个0.0至1.0之间的随机数,使用brg色彩映射表绘出这个图表。当关闭图表时,会询问是否继续,如果输入n/N则结束。其实因为数据是随机数,所以每次皆可产生不同的效果。

# ch23_24.py
import matplotlib.pyplot as plt
import numpy as np

num = 100
while True:
    x = np.random.random(100)                   # 可以产生num个0.0至1.0之间的数字
    y = np.random.random(100)
    t = x                                       # 色彩随x轴变化
    plt.scatter(x, y, s=100, c=t, cmap='brg')
    plt.show()
    yORn = input("是否继续 ?(y/n) ")            # 询问是否继续
    if yORn == 'n' or yORn == 'N':              # 输入n或N则程序结束
        break

执行结果
在这里插入图片描述

上述程序笔者使用第5行的num控制产生随机数的数量,其实读者可以自行修订,增加或减少随机数的数量,以体会本程序的运作。

23-4-2 随机数的移动

其实我们也可以针对随机数的特性,让每个点随着随机数的变化产生有序列的随机移动,经过大量值的运算后,每次均可产生不同但有趣的图形。

程序实例ch23_25.py:随机数移动的程序设计,这个程序在设计时,最初点的起始位置是(0,0),程序第7行可以设定下一个点的x轴是往右移动3或是往左移动3,程序第9行可以设定下一个点的y轴是往上移动1或5或是往下移动1或5。每此执行完10000点的测试后,会询问是否继续。如果继续,先将上一回合的终点坐标当作新回合的起点坐标(27至28行),然后清除列表索引x[0]和y[0]以外的元素(29至30行)。

# ch23_25.py
import matplotlib.pyplot as plt
import random

def loc(index):
    ''' 处理坐标的移动 '''
    x_mov = random.choice([-3, 3])              # 随机x轴移动值
    xloc = x[index-1] + x_mov                   # 计算x轴新位置
    y_mov = random.choice([-5, -1, 1, 5])       # 随机y轴移动值
    yloc = y[index-1] + y_mov                   # 计算y轴新位置
    x.append(xloc)                              # x轴新位置加入列表
    y.append(yloc)                              # y轴新位置加入列表
    
num = 10000                                     # 设定随机点的数量
x = [0]                                         # 设定第一次执行x坐标
y = [0]                                         # 设定第一次执行y坐标
while True:
    for i in range(1, num):                     # 建立点的坐标
        loc(i)
    t = x                                       # 色彩随x轴变化
    plt.scatter(x, y, s=2, c=t, cmap='brg')
    plt.show()
    yORn = input("是否继续 ?(y/n) ")            # 询问是否继续
    if yORn == 'n' or yORn == 'N':              # 输入n或N则程序结束
        break
    else:
        x[0] = x[num-1]                         # 上次结束x坐标成新的起点x坐标
        y[0] = y[num-1]                         # 上次结束y坐标成新的起点y坐标
        del x[1:]                               # 删除旧列表x坐标元素
        del y[1:]                               # 删除旧列表y坐标元素

执行结果
在这里插入图片描述

23-4-3 隐藏坐标

有时候我们设计随机数移动建立了美丽的图案后,觉得坐标好像很煞风景,可以使用下列程序实例ch23_26.py内的axes( ).get_xaxis( )、axes( ).get_yaxis( )、set_visible( )方法隐藏坐标。

程序实例ch23_26.py:重新设计ch23_25.py隐藏坐标,这个程序只是增加下列行。
在这里插入图片描述

# ch23_26.py
import matplotlib.pyplot as plt
import random

def loc(index):
    ''' 处理坐标的移动 '''
    x_mov = random.choice([-3, 3])              # 随机x轴移动值
    xloc = x[index-1] + x_mov                   # 计算x轴新位置
    y_mov = random.choice([-5, -1, 1, 5])       # 随机y轴移动值
    yloc = y[index-1] + y_mov                   # 计算y轴新位置
    x.append(xloc)                              # x轴新位置加入列表
    y.append(yloc)                              # y轴新位置加入列表
    
num = 10000                                     # 设定随机点的数量
x = [0]                                         # 设定第一次执行x坐标
y = [0]                                         # 设定第一次执行y坐标
while True:
    for i in range(1, num):                     # 建立点的坐标
        loc(i)
    t = x                                       # 色彩随x轴变化
    plt.scatter(x, y, s=2, c=t, cmap='brg')
    plt.axes().get_xaxis().set_visible(False)   # 隐藏x轴坐标
    plt.axes().get_yaxis().set_visible(False)   # 隐藏y轴坐标
    plt.show()
    yORn = input("是否继续 ?(y/n) ")            # 询问是否继续
    if yORn == 'n' or yORn == 'N':              # 输入n或N则程序结束
        break
    else:
        x[0] = x[num-1]                         # 上次结束x坐标成新的起点x坐标
        y[0] = y[num-1]                         # 上次结束y坐标成新的起点y坐标
        del x[1:]                               # 删除旧列表x坐标元素
        del y[1:]                               # 删除旧列表y坐标元素

执行结果

在这里插入图片描述

23-5 绘制多个图表

23-5-1 一个程序有多个图表

Python允许一个程序绘制多个图表,默认是一个程序绘制一个图表(Figure),如果想要绘制多个图表,可以使用figure(N)设定图表,N是图表的序号。在建立多个图表时,只要将所要绘制的图接在欲放置的图表后面即可。

程序实例ch23_27.py:设计2个图表,将data1线条放在图表Figure 1,将data2线条放在图表Figure 2。同时图表Figure 2将会建立图表标题与x/y轴的标签。

# ch23_27.py
import matplotlib.pyplot as plt

data1 = [1, 2, 3, 4, 5, 6, 7, 8]                # data1线条
data2 = [1, 4, 9, 16, 25, 36, 49, 64]           # data2线条
seq = [1, 2, 3, 4, 5, 6, 7, 8]
plt.figure(1)                                   # 建立图表1              
plt.plot(seq, data1, '-*')                      # 绘制图表1
plt.figure(2)                                   # 建立图表2
plt.plot(seq, data2, '-o')                      # 以下皆是绘制图表2
plt.title("Test Chart 2", fontsize=24)
plt.xlabel("x-Value", fontsize=14)
plt.ylabel("y-Value", fontsize=14)
plt.show()

执行结果
在这里插入图片描述

上述第8行所绘制的data1图表因为是接在plt.figure(1)后面,所以所绘制的图出现在Figure 1。上述第10-13行所绘制的data2图表因为是接在plt.figure(2)后面,所以所绘制的图出现在Figure 2。

23-5-2 含有子图的图表

要设计含有子图的图表需要使用subplot( )方法,语法如下:

 subplot(x1, x2, x3)

x1代表上下(垂直)要绘几张图,x2代表左右(水平)要绘几张图。x3代表这是第几张图。如果规划是一个Figure绘制上下2张图,那么subplot( )的应用如下:

在这里插入图片描述

如果规划是一个Figure绘制左右2张图,那么subplot( )的应用如下:

在这里插入图片描述

如果规划是一个Figure绘制上下2张图,左右3张图,那么subplot( )的应用如下:
在这里插入图片描述

程序实例ch23_28.py:在一个Fugure内绘制上下子图的应用。

# ch23_28.py
import matplotlib.pyplot as plt

data1 = [1, 2, 3, 4, 5, 6, 7, 8]                # data1线条
data2 = [1, 4, 9, 16, 25, 36, 49, 64]           # data2线条
seq = [1, 2, 3, 4, 5, 6, 7, 8]
plt.subplot(2, 1, 1)                            # 子图1
plt.plot(seq, data1, '-*')
plt.subplot(2, 1, 2)                            # 子图2
plt.plot(seq, data2, '-o')                      
plt.show()

执行结果
在这里插入图片描述

程序实例ch23_29.py:在一个Fugure内绘制上下子图的应用。

# ch23_29.py
import matplotlib.pyplot as plt

data1 = [1, 2, 3, 4, 5, 6, 7, 8]                # data1线条
data2 = [1, 4, 9, 16, 25, 36, 49, 64]           # data2线条
seq = [1, 2, 3, 4, 5, 6, 7, 8]
plt.subplot(1, 2, 1)                            # 子图1
plt.plot(seq, data1, '-*')
plt.subplot(1, 2, 2)                            # 子图2
plt.plot(seq, data2, '-o')                      
plt.show()

执行结果
在这里插入图片描述

23-6 直方图的制作bar( )

在直方图的制作中,我们可以使用bar( )方法,常用的语法如下:

 bar(x, height, width)

x是一个序列,主要是直方图x轴位置。height是序列数值的大小。width是直方图的宽度,预设是0.85。

程序实例ch23_30:有一个选举,James得票135、Peter得票412、Norton得票397,用直方图表示。

# ch23_30.py
import numpy as np
import matplotlib.pyplot as plt

votes = [135, 412, 397]         # 得票数
N = len(votes)                  # 计算长度
x = np.arange(N)                # 直方图x轴坐标
width = 0.35                    # 直方图宽度
plt.bar(x, votes, width)        # 绘制直方图

plt.ylabel('The number of votes')
plt.title('The election results')
plt.xticks(x, ('James', 'Peter', 'Norton'))
plt.yticks(np.arange(0, 450, 30))
plt.show()

执行结果

在这里插入图片描述

上述程序第11行是打印y轴的标签,第12行是打印直方图的标题,第13行则是打印x轴各直方图的标签,第14行是设定y轴刻度。

程序实例ch23_31.py:掷骰子的机率设计,一个骰子有6面分别记载1, 2, 3, 4, 5, 6,我们这个程序会用随机数计算600次,每个数字出现的次数,同时用柱形图表示,为了让读者有不同体验,笔者将图表颜色改为绿色。

# ch23_31.py
import numpy as np
import matplotlib.pyplot as plt
from random import randint

def dice_generator(times, sides):
    ''' 处理随机数 '''
    for i in range(times):              
        ranNum = randint(1, sides)              # 产生1-6随机数
        dice.append(ranNum)
def dice_count(sides):
    '''计算1-6个出现次数'''
    for i in range(1, sides+1):
        frequency = dice.count(i)               # 计算i出现在dice列表的次数
        frequencies.append(frequency)
          
times = 600                                     # 掷骰子次数
sides = 6                                       # 骰子有几面
dice = []                                       # 建立掷骰子的列表
frequencies = []                                # 储存每一面骰子出现次数列表
dice_generator(times, sides)                    # 产生掷骰子的列表
dice_count(sides)                               # 将骰子列表转成次数列表                          
x = np.arange(6)                                # 直方图x轴坐标
width = 0.35                                    # 直方图宽度
plt.bar(x, frequencies, width, color='g')       # 绘制直方图
plt.ylabel('Frequency')
plt.title('Test 600 times')
plt.xticks(x, ('1', '2', '3', '4', '5', '6'))
plt.yticks(np.arange(0, 150, 15))
plt.show()

执行结果
在这里插入图片描述

上述程序最重要的是第11-15行的dice_count( )函数,这个函数主要是将含600个元素的dice列表,分别计算1, 2, 3, 4, 5, 6各出现的次数,然后将结果存储至frequencies列表。如果读者忘记count( )方法的用法可以参考6-6-2小节。

23-7 使用CSV文件绘制图表

其实网络上有许多CSV文件,原始的文件有些复杂,不过我们可以使用Python读取文件,然后筛选我们要的字段,整个工作就变得比较简单了。本节主要是用实例介绍将图表设计应用在CSV文件。

23-7-1 台北2017年1月气象资料

在ch23文件夹内有TaipeiWeatherJan.csv文件,这是2017年1月份台北市的气象资料,这个文件的Excel内容如下:
在这里插入图片描述

程序实例ch23_32.py:读取TaipeiWeatherJan.csv文件,然后列出标题栏。

# ch23_32.py
import csv

fn = 'TaipeiWeatherJan.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    headerRow = next(csvReader)         # 读取文件下一行
print(headerRow)

执行结果

['Date', 'HighTemperature', 'MeanTemperature', 'LowTemperature']

从上图我们可以得到TaipeiWeatherJan.csv有4个字段,分别是记载日期(Date)、当天最高温(HighTemperature)、平均温度(MeanTemperature)、最低温度(LowTemperature)。

23-7-2 列出标题数据

我们可以使用6-12节所介绍的enumerate( )。

程序实例ch23_33.py:列出TaipeiWeatherJan.csv文件的标题与相对应的索引。

# ch23_33.py
import csv

fn = 'TaipeiWeatherJan.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    headerRow = next(csvReader)         # 读取文件下一行
for i, header in enumerate(headerRow):
    print(i, header)

执行结果

0 Date
1 HighTemperature
2 MeanTemperature
3 LowTemperature

23-7-3 读取最高温与最低温

程序实例ch23_34.py:读取TaipeiWeatherJan.csv文件的最高温与最低温。这个程序会将一月份的最高温放在highTemps列表,最低温放在lowTemps列表。

# ch23_34.py
import csv

fn = 'TaipeiWeatherJan.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    headerRow = next(csvReader)         # 读取文件下一行
    highTemps, lowTemps = [], []        # 设定空列表
    for row in csvReader:
        highTemps.append(row[1])        # 储存最高温
        lowTemps.append(row[3])         # 储存最低温

print("最高温 : ", highTemps)
print("最低温 : ", lowTemps)   

执行结果

最高温 :  ['26', '25', '22', '27', '25', '25', '26', '22', '18', '20', '21', '22', '18', '15', '15', '16', '23', '23', '22', '18', '15', '17', '16', '17', '18', '19', '24', '26', '25', '27', '18']
最低温 :  ['20', '18', '19', '20', '19', '20', '20', '18', '17', '16', '18', '18', '14', '12', '13', '13', '16', '18', '18', '12', '12', '12', '13', '14', '13', '13', '13', '16', '17', '14', '14']

23-7-4 绘制最高温

其实这一节内容不复杂,所有绘图方法前面各小节已有说明。

程序实例ch23_35.py:绘制2017年1月份,台北每天气温的最高温。

# ch23_35.py
import csv
import matplotlib.pyplot as plt

fn = 'TaipeiWeatherJan.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    headerRow = next(csvReader)          # 读取文件下一行
    highTemps = []                       # 设定空列表
    for row in csvReader:
        highTemps.append(row[1])         # 储存最高温
        
plt.plot(highTemps)
plt.title("Weather Report, Jan. 2017", fontsize=24)
plt.xlabel("", fontsize=14)
plt.ylabel("Temperature (C)", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

23-7-5 设定绘图区大小

 if gure(dpi=n,figsize=(width, height))

经上述设定后,绘图区的宽将是n×width像素,高是n×width像素。

程序实例ch23_36.py:重新设计ch23_35.py,设定绘图区宽度是960,高度是640,这个程序只是增加下列行。

目前绘图区大小是使用系统默认,不过我们可以使用figure( )设定绘图区大小,设定方式如下:

在这里插入图片描述

执行结果
在这里插入图片描述

23-7-6 日期格式

天气图表建立过程,我们可能想加上日期在x轴的刻度上,这时我们需要使用Python内置的datetime模块,在使用前请使用下列方式导入模块。

 from datetime import datetime

然后可以使用下列方法将日期字符串解析为日期对象:

 strptime(string, format)

string是要解析的日期字符串,format是该日期字符串目前格式,下表是日期格式参数的意义。

在这里插入图片描述

程序实例ch23_37.py:将字符串转成日期对象。

# ch23_37.py
from datetime import datetime

dateObj = datetime.strptime('2017/1/1', '%Y/%m/%d')
print(dateObj)

执行结果

2017-01-01 00:00:00

有关datetime对象的更进一步使用可以参考30-1节。

23-7-7 在图表增加日期刻度

其实我们可以在plot( )方法内增加日期列表参数时,在图表增加日期刻度。

程序实例ch23_38.py:为图表增加日期刻度。

# ch23_38.py
import csv
import matplotlib.pyplot as plt
from datetime import datetime

fn = 'TaipeiWeatherJan.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    headerRow = next(csvReader)             # 读取文件下一行
    dates, highTemps = [], []               # 设定空列表
    for row in csvReader:
        highTemps.append(row[1])            # 储存最高温
        currentDate = datetime.strptime(row[0], "%Y/%m/%d")
        dates.append(currentDate)
       
plt.figure(dpi=80, figsize=(12, 8))         # 设定绘图区大小                  
plt.plot(dates, highTemps)                  # 图标增加日期刻度
plt.title("Weather Report, Jan. 2017", fontsize=24)
plt.xlabel("", fontsize=14)
plt.ylabel("Temperature (C)", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

这个程序的第一个重点是第13行和14行,主要是将日期字符串转成对象,然后存入dates日期列表。第二个重点是第17行,在plot( )方法中第一个参数是放dates日期列表。

23-7-8 日期位置的旋转

上一节的执行结果可以发现日期是水平放置,autofmt_xdate( )设定日期旋转,语法如下:

fig = plt.figure( xxx )       # xxx是相关设定信息
 …
 if g.autofmt_xdate(rotation=xx)  # rotation若省略则系统使用优化默认

程序实例ch23_39.py:重新设计ch23_38.py,增加将日期旋转。
在这里插入图片描述

执行结果
在这里插入图片描述

程序实例ch23_40.py:是特别将日期字符串调整为旋转60度的结果。

# ch23_40.py
import csv
import matplotlib.pyplot as plt
from datetime import datetime

fn = 'TaipeiWeatherJan.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    headerRow = next(csvReader)             # 读取文件下一行
    dates, highTemps = [], []               # 设定空列表
    for row in csvReader:
        highTemps.append(row[1])            # 储存最高温
        currentDate = datetime.strptime(row[0], "%Y/%m/%d")
        dates.append(currentDate)
       
fig = plt.figure(dpi=80, figsize=(12, 8))   # 设定绘图区大小                  
plt.plot(dates, highTemps)                  # 图标增加日期刻度
fig.autofmt_xdate(rotation=60)              # 日期旋转
plt.title("Weather Report, Jan. 2017", fontsize=24)
plt.xlabel("", fontsize=14)
plt.ylabel("Temperature (C)", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

23-7-9 绘制最高温与最低温

在TaipeiWeatherJan.csv文件内有最高温与最低温的字段,下列将同时绘制最高温与最低温。

程序实例ch23_41.py:绘制最高温与最低温,这个程序第一个重点是程序第11至21行使用异常处理方式,因为读者在读取真实的网络数据时,常常会有不可预期的数据发生,例如,数据少了或是数据格式错误,往往造成程序中断,为了避免程序因数据不良,所以使用异常处理方式。第二个重点为程序第24和25行是分别绘制最高温与最低温。

# ch23_41.py
import csv
import matplotlib.pyplot as plt
from datetime import datetime

fn = 'TaipeiWeatherJan.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    headerRow = next(csvReader)             # 读取文件下一行
    dates, highTemps, lowTemps = [], [], [] # 设定空列表
    for row in csvReader:
        try:                    
            currentDate = datetime.strptime(row[0], "%Y/%m/%d")
            highTemp = int(row[1])          # 设定最高温
            lowTemp = int(row[3])           # 设定最低温
        except Exception:
            print('有缺值')
        else:
            highTemps.append(highTemp)      # 储存最高温
            lowTemps.append(lowTemp)        # 储存最低温
            dates.append(currentDate)       # 储存日期
       
fig = plt.figure(dpi=80, figsize=(12, 8))   # 设定绘图区大小
plt.plot(dates, highTemps)                  # 绘制最高温
plt.plot(dates, lowTemps)                   # 绘制最低温
fig.autofmt_xdate()                         # 日期旋转
plt.title("Weather Report, Jan. 2017", fontsize=24)
plt.xlabel("", fontsize=14)
plt.ylabel("Temperature (C)", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

23-7-10 填满最高温与最低温之间的区域

可以使用fill_between( )方法执行填满最高温与最低温之间的区域。
在这里插入图片描述

程序实例ch23_42.py:使用透明度是0.2的黄色填满区间,这个程序只是增加下列行。

# ch23_42.py
import csv
import matplotlib.pyplot as plt
from datetime import datetime

fn = 'TaipeiWeatherJan.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    headerRow = next(csvReader)             # 读取文件下一行
    dates, highTemps, lowTemps = [], [], [] # 设定空列表
    for row in csvReader:
        try:                    
            currentDate = datetime.strptime(row[0], "%Y/%m/%d")
            highTemp = int(row[1])          # 设定最高温
            lowTemp = int(row[3])           # 设定最低温
        except Exception:
            print('有缺值')
        else:
            highTemps.append(highTemp)      # 储存最高温
            lowTemps.append(lowTemp)        # 储存最低温
            dates.append(currentDate)       # 储存日期
       
fig = plt.figure(dpi=80, figsize=(12, 8))   # 设定绘图区大小
plt.plot(dates, highTemps)                  # 绘制最高温
plt.plot(dates, lowTemps)                   # 绘制最低温
plt.fill_between(dates, highTemps, lowTemps, color='y', alpha=0.2) # 填满区间
fig.autofmt_xdate()                         # 日期旋转
plt.title("Weather Report, Jan. 2017", fontsize=24)
plt.xlabel("", fontsize=14)
plt.ylabel("Temperature (C)", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果
在这里插入图片描述

23-7-11 再谈轴刻度

在23-1-2小节笔者介绍过可以使用axis( )设定x,y轴的最小和最大刻度,可以参考程序实例ch23_1_1.py,对于上述天气图表而言,x轴是以日期为刻度,如果我们想要设定x轴刻度,可以设置x轴最小刻度是2017-01-01,最大刻度是2017-01-31。

程序实例ch23_43.py:重新设计程序实例ch23_42.py,让x轴最小刻度是2017-01-01,最大刻度是2017-01-31。y轴(气温)则是在0℃~40℃。下列dates[0]就是指2017-01-01,date[30]就是指2017-01-31。
在这里插入图片描述

# ch23_43.py
import csv
import matplotlib.pyplot as plt
from datetime import datetime

fn = 'TaipeiWeatherJan.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    headerRow = next(csvReader)             # 读取文件下一行
    dates, highTemps, lowTemps = [], [], [] # 设定空列表
    for row in csvReader:
        try:                    
            currentDate = datetime.strptime(row[0], "%Y/%m/%d")
            highTemp = int(row[1])          # 设定最高温
            lowTemp = int(row[3])           # 设定最低温
        except Exception:
            print('有缺值')
        else:
            highTemps.append(highTemp)      # 储存最高温
            lowTemps.append(lowTemp)        # 储存最低温
            dates.append(currentDate)       # 储存日期
       
fig = plt.figure(dpi=80, figsize=(12, 8))   # 设定绘图区大小
plt.axis([dates[0], dates[30], 0, 40])      # 设定x,y轴刻度
plt.plot(dates, highTemps)                  # 绘制最高温
plt.plot(dates, lowTemps)                   # 绘制最低温
plt.fill_between(dates, highTemps, lowTemps, color='y', alpha=0.2) # 填满区间
fig.autofmt_xdate()                         # 日期旋转
plt.title("Weather Report, Jan. 2017", fontsize=24)
plt.xlabel("", fontsize=14)
plt.ylabel("Temperature (C)", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

执行结果

在这里插入图片描述

结果发现x轴宽度变了,日期标签也变多了。
在这里插入图片描述

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值