import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
这里的plt.rcParams
是什么?
简单理解,这是自定义图形的各种默认属性。第一句是吧字体设置为’SimHei’由此可以显示中文,第二个就是可以解决x轴和y轴‘-’字符显示问题
但是这里又有个坑,由于SimHei是win自带的字体。所以mac的电脑这样设置是没用的,还是显示不了字符。
这时应该使用mac自带的字体,就可以了。
一、子图
1. 使用 plt.subplots
绘制均匀状态下的子图
返回元素分别是画布和子图构成的列表,第一个数字为行,第二个为列
figsize
参数可以指定整个画布的大小
sharex
和 sharey
分别表示是否共享横轴和纵轴刻度
tight_layout
函数可以调整子图的相对大小使字符不会重叠
fig, axs = plt.subplots(2, 5, figsize=(10, 4), sharex=True, sharey=True)
fig.suptitle('样例1', size=20,horizontalalignment='right',verticalalignment='center',x=0,y=1)
np.random.seed(0)
for i in range(2):
for j in range(5):
axs[i][j].scatter(np.random.randn(10), np.random.randn(10))
axs[i][j].set_title('第%d行,第%d列'%(i+1,j+1))
axs[i][j].set_xlim(-5,5)
axs[i][j].set_ylim(-5,5)
if i==1: axs[i][j].set_xlabel('横坐标')
if j==0: axs[i][j].set_ylabel('纵坐标')
fig.tight_layout()
plt.show()
plt.suptitle()可以传入x=,y=来控制suptitle的位置。
horizontalalignment与verticalalignment是调整suptitle与坐标的相对位置。
如果horizontalalignment=right,那么就是文本标题的最右边在(x,y)位置上,horizontalalignment=center,就是文本标题的中间位置处于(x,y)
2.极坐标
除了常规的直角坐标系,也可以通过projection
方法创建极坐标系下的图表
N = 150
r = 2 * np.random.rand(N)
theta = 2 * np.pi * np.random.rand(N)
area = 200 * r**2
colors = theta
plt.subplot(projection='polar')
plt.scatter(theta, r, c=colors, s=area, cmap='hsv', alpha=0.75)
这个图有点高阶。我们先看下极坐标的定义。
在平面内取一个定点O,叫极点,引一条射线Ox,叫做极轴,再选定一个长度单位和角度的正方向(通常取逆时针方向)。对于平面内任何一点M,用ρ表示线段OM的长度(有时也用r表示),θ表示从OX到OM的角度,ρ叫做点M的极径,θ叫做点M的极角,有序数对 (ρ,θ)就叫点M的极坐标,这样建立的坐标系叫做极坐标系。
import matplotlib.pyplot as plt
ax1 = plt.subplot(121, projection='polar')
ax2 = plt.subplot(122)
# 极坐标下需要的数据有极径和角度
r = np.arange(1,6,1) # 极径
theta = [i*np.pi/2 for i in range(5)] #角度
# 指定画图坐标为极坐标,projection='polar'
ax = plt.subplot(111, projection='polar')
ax.scatter(theta,r,linewidth=3,color='r')
# 加网格
ax.grid(True)
plt.show()
可以看到每个点都被标在相应的位置,只是坐标是(ρ,θ)
这里的1,2,3,4,5是网格线的极径值列表,最小值不能小于等于0。
3. 使用 GridSpec
绘制非均匀子图
所谓非均匀包含两层含义,第一是指图的比例大小不同但没有跨行或跨列,第二是指图为跨列或跨行状态
利用 add_gridspec
可以指定相对宽度比例 width_ratios
和相对高度比例参数 height_ratios
fig = plt.figure(figsize=(10, 4))
spec = fig.add_gridspec(nrows=2, ncols=5, width_ratios=[1,2,3,4,5], height_ratios=[1,3])
fig.suptitle('样例2', size=20)
for i in range(2):
for j in range(5):
ax = fig.add_subplot(spec[i, j])
ax.scatter(np.random.randn(10), np.random.randn(10))
ax.set_title('第%d行,第%d列'%(i+1,j+1))
if i==1: ax.set_xlabel('横坐标')
if j==0: ax.set_ylabel('纵坐标')
fig.tight_layout()
注意:非均匀子图与均匀子图的写法有些许不同,非均匀状态子图是先fig.add_gridspec()作出非均匀子图,这是一个,然后fig.add_subplot()将primitives存入axes容器中。
在上面的例子中出现了 spec[i, j]
的用法,事实上通过切片就可以实现子图的合并而达到跨图的共能
fig = plt.figure(figsize=(10, 4))
spec = fig.add_gridspec(nrows=2, ncols=6, width_ratios=[2,2.5,3,1,1.5,2], height_ratios=[1,2])
fig.suptitle('样例3', size=20,x=-0.05,y=1)
# sub1
ax = fig.add_subplot(spec[0, :3])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub2
ax = fig.add_subplot(spec[0, 3:5])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub3
ax = fig.add_subplot(spec[:, 5])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub4
ax = fig.add_subplot(spec[1, 0])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub5
ax = fig.add_subplot(spec[1, 1:5])
ax.scatter(np.random.randn(10), np.random.randn(10))
fig.tight_layout()
这里的切片就是切fig.add_gridspec()的width_ratios和height_ratios参数。spec[i,j]里i是对height_ratios切片,j是对width_ratios切片。
举个例子sub1与sub2的width宽度比是(2+2.5+3):(1+1.5)即3:1
注意:在一个fig下每个spec切片的索引不能相交,其实可以理解为把一个大的画布进行不均等分割。
二、子图上的方法
在 ax
对象上定义了和 plt
类似的图形绘制函数,常用的有: plot, hist, scatter, bar, barh, pie
常用直线的画法为: axhline, axvline, axline
(水平、垂直、任意方向)
ax.hline()添加一个水平线,第一个参数是与水平线垂直的值。第二个第三个参数是xmin和xmax,即与线平行的轴的值。
ax.vline()与其类似。
ax.axline()的参数可以看成两个坐标,然后相连。
使用 grid
可以加灰色网格
使用 set_xscale, set_title, set_xlabel
分别可以设置坐标轴的规度(指对数坐标等)、标题、轴名
.set_yscale(‘log’)是把y轴设置为对数坐标。
与一般的 plt
方法类似, legend, annotate, arrow, text
对象也可以进行相应的绘制
fig, ax = plt.subplots()
ax.arrow(0, 0, 1, 1, head_width=0.03, head_length=0.05, facecolor='red', edgecolor='blue')
ax.text(x=0, y=0,s='这是一段文字', fontsize=16, rotation=70, rotation_mode='anchor', color='green')
ax.annotate('这是中点', xy=(0.5, 0.5), xytext=(0.8, 0.2), arrowprops=dict(facecolor='yellow', edgecolor='black'), fontsize=16)
ax.arrow(x, y, dx, dy, **kwargs)
x,y是起始坐标,dx与dy是起始坐标的偏移量,head_width控制箭头宽度。
ax.text(x, y, s, fontdict=None, **kwargs)
在axes中加入文本。
x,y是文字的坐标(应该是text的开头坐标),fontdict是改变text的属性。
ax.annotate(text, xy, *args, **kwargs)
对某点添加注释。
text传入注释的文本,xy是注释点的坐标,xytest是注释文本的坐标。注意这里xy与xytest是用元组传入坐标。
fig, ax = plt.subplots()
ax.plot([1,2],[2,1],label="line1")
ax.plot([1,1],[1,2],label="line1")
ax.legend(loc=1)
其中,图例的 loc
参数如下:
string | code |
---|---|
best | 0 |
upper right | 1 |
upper left | 2 |
lower left | 3 |
lower right | 4 |
right | 5 |
center left | 6 |
center right | 7 |
lower center | 8 |
upper center | 9 |
center | 10 |
三、作业
1. 墨尔本1981年至1990年的每月温度情况
from matplotlib.pyplot import MultipleLocator
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
ex1 = pd.read_csv('data/layout_ex1.csv')
fig, axs = plt.subplots(2, 5, figsize=(16, 4),sharex=True, sharey=True)
fig.suptitle('墨尔本1981年至1990年月温度曲线', size=15,horizontalalignment='right',verticalalignment='center',x=0.55,y=1)
index_1=pd.Series(range(0,121,12))
for i in range(2):
for j in range(5):
axs[i][j].plot(range(1,13),ex1['Temperature'][index_1[i*5+j]:index_1[i*5+j+1]],marker='*')
axs[i][j].set_xlim(0.5,12.5)
axs[i][j].set_ylim(4,20)
axs[i][j].set_title('%d年'%(1981+5*i+j),size=10)
if j==0:axs[i][j].set_ylabel('气温')
x_major_locator=MultipleLocator(1)
axs[i][j].xaxis.set_major_locator(x_major_locator)
fig.tight_layout()
plt.show()
2. 画出数据的散点图和边际分布
- 用
np.random.randn(2, 150)
生成一组二维数据,使用两种非均匀子图的分割方法,做出该数据对应的散点图和边际分布图
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(22)
X=np.random.randn(2,150)
fig = plt.figure(figsize=(6,6))
spec = fig.add_gridspec(nrows=2, ncols=2, width_ratios=[4,1], height_ratios=[1,4])
for i in range(2):
for j in range(2):
if (i==0)&(j==1):
continue
ax=fig.add_subplot(spec[i,j])
if (i ==1) & (j==0):
ax.scatter(X[0],X[1])
ax.set_xlabel('my_data_x')
ax.set_ylabel('my_data_y')
ax.grid(True)
if (i==0)&(j==0):
ax.hist(X[0],rwidth=0.9) #设置柱子的宽度占bins宽的比例,可以理解为调整柱子的宽度
ax.xaxis.set_major_locator(plt.NullLocator()) #去掉双轴
ax.yaxis.set_major_locator(plt.NullLocator())
ax.axis('off') #去掉外面的框
if (i==1)&(j==1):
ax.hist(X[1],orientation='horizontal',rwidth=[0.9])
ax.xaxis.set_major_locator(plt.NullLocator())
ax.yaxis.set_major_locator(plt.NullLocator())
ax.axis('off')
fig.suptitle('习题2-解法1', size=20)
fig.tight_layout()
plt.show()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(22)
X=np.random.randn(2,150)
fig = plt.figure(figsize=(6,6))
spec = fig.add_gridspec(nrows=2, ncols=2, width_ratios=[4,1], height_ratios=[1,4])
ax = fig.add_subplot(spec[0,:1])
ax.hist(X[0],rwidth=0.8)
ax.xaxis.set_major_locator(plt.NullLocator()) #去掉双轴
ax.yaxis.set_major_locator(plt.NullLocator())
ax.axis('off') #去掉外面的框
ax = fig.add_subplot(spec[1,:1])
ax.scatter(X[0],X[1])
ax.set_xlabel('my_data_x')
ax.set_ylabel('my_data_y')
ax.grid(True)
ax = fig.add_subplot(spec[1,1:])
ax.hist(X[0],rwidth=0.8,orientation='horizontal')
ax.xaxis.set_major_locator(plt.NullLocator()) #去掉双轴
ax.yaxis.set_major_locator(plt.NullLocator())
ax.axis('off')
fig.tight_layout()