Python制图 | 01.使用Matplotlib绘制统计图
Section One - Plotting with Matplotlib 源代码 学习目标: 解释matplotlib面向对象的绘图方法 使用matplotlib创建不同类型的绘图 使用matplotlib自定义绘图(包括标签和颜色) 使用matplotlib创建具有多个子图的绘图 Matplotlib是Python中最常用的绘图库,下面了解如何开始使用matplotlib创建和自定义绘图 1.1 概述 Matplotlib是一个Python绘图包,它使从存储在各种数据结构中的数据(包括列表、numpy数组和pandas数据框)创建二维图变得简单。Matplotlib使用了一种面向对象的绘图方法。这意味着可以通过向绘图中添加新的元素来逐步构建绘图 matplotlib绘图中主要会用到两个对象: figure对象:整体的图空间,可以包含一个或多个子图 axis对象:在图空间中呈现的各个子图,可以把figure对象看作是整个绘图画布,而axis对象看作是其中的一个子图 一个图空间可以容纳一个或多个axis对象,这种结构允许我们创建带有一个或多个子图的图形 虽然Matplotlib包含许多模块,提供不同的绘图功能,但最常用的模块是pyplot Pyplot提供的方法可用于向图形对象添加不同的组件,包括将各个图创建为axis对象,也就是子图 pyplot模块通常使用别名plt导入,如下所示: # Import pyplot import matplotlib.pyplot as plt 1.2 使用Matplotlib创建图像 要使用matplotlib的面向对象方法创建一个图,首先要使用pyplot模块中的subplots()函数创建一个图(可以称为fig)和至少一个轴(可以称为ax) fig, ax = plt.subplots() 请注意,通过将fig和ax设置为等于pyplot.subplots()函数的输出值,fig和ax被同时创建。由于没有提供其他参数,结果是一个带有一个空图的图 # Create figure and one plot (axis object) fig, ax = plt.subplots() 1.3 更改图片大小 使用figsize参数设置绘图空间的宽和高 figsize = (width, height) # Resize figure fig, ax = plt.subplots(figsize = (10, 6)) 1.4 绘制多个子图 使用matplotlib的面向对象方法,通过创建额外的axis对象,可以更容易地在图空间中创建多个子图 当添加多个axis对象时,最好的做法是给它们不同的名称(如ax1和ax2),这样就可以很容易地单独使用每个axis 因此,需要为plt.subplots提供新的参数,用于图的布局:(行数,列数) plt.subplots(1, 2) 在本例中,1、2表示布局为1行,2列 # Figure with two plots fig, (ax1, ax2) = plt.subplots(1, 2, figsize = (10, 6)) 相反地,(2,1)表示2行,1列格局分布 fig, (ax1, ax2) = plt.subplots(2, 1, figsize = (10, 6)) 由于定义了figsize=(10,6),figure绘图空间会保持这个大小,无论如何设置行数或列数是多少 但是,可以调整行数、列数以及figsize,以得到需要的大小 # Figure with two plots fig, (ax1, ax2) = plt.subplots(2, 1, figsize = (12, 12)) 可以根据需要继续添加任意数量的axis对象,以创建所需图形的整体布局,并根据需要继续调整图形大小 # Figure with three plots fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize = (15, 15)) Matplotlib 面向对象方法的一个主要优点是,每个axis都是独立的的对象,可以独立于图中的其他绘图独立地进行自定义绘制 2 使用 Matplotlib 绘制自定义图表 在本章的前面,学习了如何使用pyplot中的subplot ()函数创建图形和轴对象(使用别名plt导入) : fig,ax = plt.subplots() 现在已经知道如何使用matplotlib创建基本的绘图,可以开始向图中的绘图添加数据了 首先导入别名plt的matplotlib.pyplot模块,并创建一些列表来绘制由美国国家海洋和大气管理局(NOAA)提供的*科罗拉多州博尔德市的月平均降水量(英寸)* # Import pyplot 导入包 import matplotlib.pyplot as plt # Monthly average precipitation 月平均降水量 boulder_monthly_precip = [0.70, 0.75, 1.85, 2.93, 3.05, 2.02, 1.93, 1.62, 1.84, 1.31, 1.39, 0.84] # Month names for plotting 月份 months = ["Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"] 2.1 使用 Matplotlib 绘制数据 可以通过调用所需的ax对象将数据添加到绘图中,该对象是先前定义的axis元素: fig,ax = plt.subplots() 通过调用ax对象的plot()方法,并指定绘图的x轴(水平轴)和y轴(垂直轴)的参数如下 plot(x_axis, y_axis) 在这个例子中,你正在从之前定义的列表中添加数据,数据沿着x轴和y轴分布 # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.plot(months, boulder_monthly_precip) [<matplotlib.lines.Line2D at 0x7f0b21ed3e48>] 可以注意到,输出显示了图形的对象类型以及唯一标识符(内存位置) [<matplotlib.lines.Line2D at 0x7f81afe900b8>] 可以通过在代码末尾调用plt.show()来隐藏该信息 # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.plot(months,boulder_monthly_precip) plt.show() 2.2 Matplotlib Plot 对象的命名约定 Python 社区中的惯例是使用ax来命名axis对象,但这并不是唯一的 # Define plot space with ax named bob fig, bob = plt.subplots(figsize=(10, 6)) # Define x and y axes bob.plot(months,boulder_monthly_precip) plt.show() 2.3 创建不同类型的Matplotlib图: 散点图和条形图 默认情况下,ax.plot 将绘图创建为线图(这意味着所有的值都通过横跨绘图的连续线连接起来) 可以使用 ax 对象来创建: 散点图(使用ax.scatter) : 值显示为不连续线的单个点 条形图(使用ax.bar) : 值显示为条形,其高度指示特定点的值 # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Create scatter plot ax.scatter(months,boulder_monthly_precip) plt.show() # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Create bar plot ax.bar(months,boulder_monthly_precip) plt.show() 2.4 自定义绘图标题和坐标轴标签 可以使用ax.set()方法中的title、xlabel、ylabel参数为轴添加绘图标题和标签,从而自定义和添加更多信息到绘图中 ax.set(title = "Plot title here", xlabel = "X axis label here", ylabel = "Y axis label here") # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.plot(months, boulder_monthly_precip) # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation in Boulder, CO", xlabel = "Month", ylabel = "Precipitation (inches)") plt.show() 2.5 自定义多行绘图标题和坐标轴标签 使用两个单词之间的新行字符**\n**创建具有多行文本的标题和轴标签 # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.plot(months, boulder_monthly_precip) # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() 2.6 标签旋转 使用plt.setp函数设置整个绘图空间的参数,如自定义刻度标签 在下面的例子中,ax.get_xticklabels()函数控制x轴的刻度标签,rotation # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.plot(months, boulder_monthly_precip) # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.setp(ax.get_xticklabels(),rotation=45) plt.show() 2.7 自定义折线、点标记形状 可以通过marker=参数对线段、点的形状标识进行修改 Marker symbol Marker description . point , pixel o circle v triangle_down ^ triangle_up < triangle_left > triangle_right 访问Matplotlib文档可以获取更多标记类型列表 # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.scatter(months, boulder_monthly_precip, marker = ',') # pixel # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.plot(months, boulder_monthly_precip, marker = 'o') # point # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() 2.8 自定义绘图颜色 可以使用color参数自定义绘图颜色,在matplotlib中提供的一些基本颜色选项列表如下: b: blue g: green r: red c: cyan m: magenta y: yellow k: black w: white 对于这些基本颜色,可以将color参数设置为等于全名(例如cyan)或者仅仅是如上表所示的键字母(例如c) 要获得更多的颜色,请访问关于颜色的matplotlib文档 # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.plot(months, boulder_monthly_precip, marker = 'o', color = 'cyan') # color=c # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.scatter(months, boulder_monthly_precip, marker = ',', color = 'k') # color=black # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.bar(months, boulder_monthly_precip, color = 'darkblue') # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() 2.8 设置颜色透明度 使用alpha =参数调整颜色的透明度,其值接近0.0表示更高的透明度 # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.bar(months, boulder_monthly_precip, color = 'darkblue', alpha = 0.3) # 透明度设置 # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() 2.9 自定义条形图的颜色 通过使用参数edgeccolor=将每个条的轮廓颜色更改为蓝色,并从前面讨论过的matplotlib颜色选项中指定一种颜色,可以进一步自定义条形图 # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.bar(months, boulder_monthly_precip, color = 'cyan', edgecolor = 'darkblue') # 轮廓颜色设置 # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() 2.10 自定义散点图的颜色 在使用散点图时,还可以使用c和cmap参数根据每个点的数据值为其分配一种颜色 c参数允许指定将被颜色映射的值序列(例如boulder _ monthly _ precip) ,而cmap允许指定用于该序列的颜色映射 下面的例子使用了YlGnBu颜色图,其中较低的值用黄色到绿色色调填充,而较高的值用越来越深的蓝色色调填充 要查看彩色地图选项列表,请访问的matplotlib cmpas文档 # Define plot space fig, ax = plt.subplots(figsize=(10, 6)) # Define x and y axes ax.scatter(months, boulder_monthly_precip, c = boulder_monthly_precip, cmap = 'YlGnBu') # Set plot title and axes labels ax.set(title = "Average Monthly Precipitation\nBoulder, CO", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() 2.11 将数据绘制为多图 回想matplotlib的面向对象方法,通过创建额外的axis对象,可以很容易地在一个图形中包含多个图形: fig, (ax1, ax2) = plt.subplots(num_rows, num_columns) 一旦定义了fig和两个axis对象,就可以向每个轴添加数据并定义具有独特特征的图形 在下面的示例中,ax1.bar在第一个绘图中创建一个定制的条形图,而ax2.scatter在第二个绘图中创建一个定制的散点图 # Define plot space fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12)) # 两行一列 # Define x and y axes ax1.bar(months, boulder_monthly_precip, color = 'cyan', edgecolor = 'darkblue') # Define x and y axes ax2.scatter(months, boulder_monthly_precip, c = boulder_monthly_precip, cmap = 'YlGnBu') plt.show() 2.12 为多个子图添加标题和轴标签 可以继续添加ax1和ax2,例如为每个单独的绘图添加标题和轴标签,就像您以前只有一个绘图时所做的那样 可以使用ax1.set()为第一个绘图(柱状图)定义元素,使用ax2.set()为第二个绘图(散点图)定义元素 # Define plot space fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12)) # Define x and y axes ax1.bar(months, boulder_monthly_precip, color = 'cyan', edgecolor = 'darkblue') # Set plot title and axes labels ax1.set(title = "Bar Plot of Average Monthly Precipitation", xlabel = "Month", ylabel = "Precipitation\n(inches)"); # Define x and y axes ax2.scatter(months, boulder_monthly_precip, c = boulder_monthly_precip, cmap = 'YlGnBu') # Set plot title and axes labels ax2.set(title = "Scatter Plot of Average Monthly Precipitation", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() 现在已经有了多个图形(每个图形都有自己的标签) ,还可以为整个图形添加一个总体标题(使用指定的字体大小) ,使用: fig.suptitle("Title text", fontsize = 16) # Define plot space fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12)) fig.suptitle("Average Monthly Precipitation for Boulder, CO", fontsize = 16) # Define x and y axes ax1.bar(months, boulder_monthly_precip, color = 'cyan', edgecolor = 'darkblue') # Set plot title and axes labels ax1.set(title = "Bar Plot", xlabel = "Month", ylabel = "Precipitation\n(inches)"); # Define x and y axes ax2.scatter(months, boulder_monthly_precip, c = boulder_monthly_precip, cmap = 'YlGnBu') # Set plot title and axes labels ax2.set(title = "Scatter Plot", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.show() 2.13 将 Matplotlib 图形保存为图像文件 可以使用以下命令轻松地将图形保存到图像文件中,例如 .png: plt.savefig ("path/name-of-file.png") 可以保存最新的数据,如果没有为文件指定一个路径,文件将会在你当前的工作目录文件夹中创建 查看Matplotlib文档以查看用于保存图形的其他文件格式的列表 # Define plot space fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12)) fig.suptitle("Average Monthly Precipitation for Boulder, CO", fontsize = 16) # Define x and y axes ax1.bar(months, boulder_monthly_precip, color = 'cyan', edgecolor = 'darkblue') # Set plot title and axes labels ax1.set(title = "Bar Plot", xlabel = "Month", ylabel = "Precipitation\n(inches)"); # Define x and y axes ax2.scatter(months, boulder_monthly_precip, c = boulder_monthly_precip, cmap = 'YlGnBu') # Set plot title and axes labels ax2.set(title = "Scatter Plot", xlabel = "Month", ylabel = "Precipitation\n(inches)") plt.savefig("output/average-monthly-precip-boulder-co.png") plt.show() 2.14 额外资源 关于颜色条的更多信息color bars 深入介绍matplotlib 3.1 自定义x轴日期刻度 # Import required python packages import os import pandas as pd import matplotlib.pyplot as plt from matplotlib.dates import DateFormatter import matplotlib.dates as mdates import seaborn as sns import earthpy as et # Date time conversion registration from pandas.plotting import register_matplotlib_converters register_matplotlib_converters() # Get the data # data = et.data.get_data('colorado-flood') # Set working directory os.chdir(os.path.join(et.io.HOME, 'learning','python_data_plot')) # Prettier plotting with seaborn sns.set(font_scale=1.5) sns.set_style("whitegrid") 在本节中,将学习如何在Python中使用matplotlib绘制时间序列 # Read in the data data_path = "data/precipitation/805325-precip-dailysum-2003-2013.csv" boulder_daily_precip = pd.read_csv(data_path, parse_dates=['DATE'], # 将csv中的时间字符串转换成日期格式 na_values=['999.99'], index_col=['DATE']) boulder_daily_precip.head() <div> <style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style> <table border="1" class="dataframe"> <thead> <tr style="text-align: right;"> <th></th> <th>DAILY_PRECIP</th> <th>STATION</th> <th>STATION_NAME</th> <th>ELEVATION</th> <th>LATITUDE</th> <th>LONGITUDE</th> <th>YEAR</th> <th>JULIAN</th> </tr> <tr> <th>DATE</th> <th></th> <th></th> <th></th> <th></th> <th></th> <th></th> <th></th> <th></th> </tr> </thead> <tbody> <tr> <th>2003-01-01</th> <td>0.0</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.03389</td> <td>-105.28111</td> <td>2003</td> <td>1</td> </tr> <tr> <th>2003-01-05</th> <td>NaN</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.03389</td> <td>-105.28111</td> <td>2003</td> <td>5</td> </tr> <tr> <th>2003-02-01</th> <td>0.0</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.03389</td> <td>-105.28111</td> <td>2003</td> <td>32</td> </tr> <tr> <th>2003-02-02</th> <td>NaN</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.03389</td> <td>-105.28111</td> <td>2003</td> <td>33</td> </tr> <tr> <th>2003-02-03</th> <td>0.4</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.03389</td> <td>-105.28111</td> <td>2003</td> <td>34</td> </tr> </tbody> </table> </div> # Subset the data # 提取8月15至10月15之间的数据 precip_boulder_AugOct = boulder_daily_precip["2013-08-15":"2013-10-15"] # View first few rows of data precip_boulder_AugOct.head() <div> <style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style> <table border="1" class="dataframe"> <thead> <tr style="text-align: right;"> <th></th> <th>DAILY_PRECIP</th> <th>STATION</th> <th>STATION_NAME</th> <th>ELEVATION</th> <th>LATITUDE</th> <th>LONGITUDE</th> <th>YEAR</th> <th>JULIAN</th> </tr> <tr> <th>DATE</th> <th></th> <th></th> <th></th> <th></th> <th></th> <th></th> <th></th> <th></th> </tr> </thead> <tbody> <tr> <th>2013-08-21</th> <td>0.1</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.0338</td> <td>-105.2811</td> <td>2013</td> <td>233</td> </tr> <tr> <th>2013-08-26</th> <td>0.1</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.0338</td> <td>-105.2811</td> <td>2013</td> <td>238</td> </tr> <tr> <th>2013-08-27</th> <td>0.1</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.0338</td> <td>-105.2811</td> <td>2013</td> <td>239</td> </tr> <tr> <th>2013-09-01</th> <td>0.0</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.0338</td> <td>-105.2811</td> <td>2013</td> <td>244</td> </tr> <tr> <th>2013-09-09</th> <td>0.1</td> <td>COOP:050843</td> <td>BOULDER 2 CO US</td> <td>1650.5</td> <td>40.0338</td> <td>-105.2811</td> <td>2013</td> <td>252</td> </tr> </tbody> </table> </div> fig, ax = plt.subplots(figsize=(12, 8)) ax.plot(precip_boulder_AugOct.index.values, precip_boulder_AugOct['DAILY_PRECIP'].values, '-o', color='purple') ax.set(xlabel="Date", ylabel="Precipitation (Inches)", title="Daily Precipitation \nBoulder, Colorado 2013") # Format the x axis # 对x轴进行日期格式化 ax.xaxis.set_major_locator(mdates.WeekdayLocator(interval=2)) ax.xaxis.set_major_formatter(DateFormatter("%m-%d")) plt.show() 3.2 对Matplotlib进行日期格式化 在 matplotlib 中,也可以使用 DateFormatter 模块更改绘图轴上的日期格式 需要从 matplotlib 导入 DateFormatter,然后使用以下语法指定日期 DateFormatter 要使用的格式: %Y-4位数年份 %y-2位数年份 %m-月份 %d-天 实现自定义日期的步骤: 定义日期格式: myFmt = DateFormatter("%m/%d"),这个日期格式是月/日,所以它看起来像这样: 10/05,代表10月5日 调用set_major_formatter()方法: ax.xaxis.set_major_formatter(myFmt) 将上面定义的日期格式应用于绘图空间中 # Plot the data fig, ax = plt.subplots(figsize=(10,6)) ax.scatter(precip_boulder_AugOct.index.values, precip_boulder_AugOct['DAILY_PRECIP'].values, color='purple') ax.set(xlabel="Date", ylabel="Precipitation (Inches)", title="Daily Precipitation (inches)\nBoulder, Colorado 2013") # Define the date format date_form = DateFormatter("%m/%d") ax.xaxis.set_major_formatter(date_form) 3.3 X轴的日期刻度 特定的时间刻度可以沿着x轴添加,例如:大的刻度可以表示每个新的工作周的开始,小的刻度可以表示每个工作日 函数xaxis.set_major_locator()控制大刻度的位置,函数xaxis.set_minor_locator控制小刻度 # Plot the data fig, ax = plt.subplots(figsize=(10,6)) ax.scatter(precip_boulder_AugOct.index.values, precip_boulder_AugOct['DAILY_PRECIP'].values, color='purple') ax.set(xlabel="Date", ylabel="Precipitation (Inches)", title="Daily Precipitation (inches)\nBoulder, Colorado 2013") # 定义日期格式 date_form = DateFormatter("%m/%d") ax.xaxis.set_major_formatter(date_form) # 确保每隔一周刻度减小一次 ax.xaxis.set_major_locator(mdates.WeekdayLocator(interval=1)) # ax.xaxis.set_minor_locator(mdates.DayLocator(1)) 参考资料: https://www.earthdatascience.org/courses/scientists-guide-to-plotting-data-in-python-textbook/