import numpy as np
import matplotlib.pyplot as plt
objects = ('Python', 'C++', 'Java', 'Perl', 'Scala', 'Lisp')
y_pos = np.arange(len(objects))
performance = [10, 8, 6, 4, 2, 1]
plt.bar(y_pos, performance, align='center', alpha=0.5)
plt.xticks(y_pos, objects)
plt.ylabel('用户量')
plt.title('数据分析程序语言使用分布情况')
plt.show()
plt.bar()
函数参数:
将上例第8行改成:
plt.barh(y_pos, performance, align='center', alpha=0.5)
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
objects = ('Python', 'C++', 'Java', 'Perl', 'Scala', 'Lisp')
y_pos = np.arange(len(objects))
performance = [10, 8, 6, 4, 2, 1]
plt.barh(y_pos, performance, align='center', alpha=0.5, color='k', tick_label=objects)
plt.xlabel('用户量')
plt.title('数据分析程序语言使用分布情况')
plt.show()
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
# 绘图
n_group = 4
means_frank = (90, 55, 40, 65)
means_guido = (85, 62, 54, 20)
# 创建图像
fig, ax = plt.subplots()
# 定义条形图在横坐标上的分类位置
index = np.arange(n_group)
bar_width = 0.35
opacity = 0.8
rectsl = plt.bar(index,
means_frank,
bar_width,
alpha=opacity,
color='b',
label='张三')
rects2 = plt.bar(index + bar_width,
means_guido,
bar_width,
alpha=opacity,
color='g',
label='李四'
)
plt.xlabel('课程')
plt.ylabel('分数')
plt.title('分数对比图')
plt.xticks(index + bar_width, ('A', 'B', 'C', 'D'))
plt.legend()
plt.show()
在本质上,垂直并列条形图就是在X轴上分别画两组并列的条形图,但二者在X轴的位置上有先后关系。举例来说,代码第20~25行画出了第一个条形图。请注意,实际上代码第20~25行是一行语句,不过是为了注释方便,将不同的参数放置于不同的行罢了。
代码第27~31行画出了第二个条形图。值得注意的是,在细节处理上,它的X轴坐标的向右偏移量正好等于第一个条形图的宽度,通过X轴上的偏移操作index+bar_width,第二个条形图能与第一个条形图在X轴上无缝“肩并肩”。
为了区分两组条形图,我们用label属性(见代码第25行和第31行)来区分不同图形的标签。
我们知道,即使不同的条形图使用了不同颜色加以区分,但有时效果也欠佳。这是因为,在彩色的电子显示设备中,这些多彩图形清晰可分,但当黑白打印时,颜色往往难以区分。
因此,在科技论文写作中,常常使用不同纹理而非不同颜色来区分不同的条形图。这时,就需要使用条形图的hatch(填充)参数了。下面,我们接着改写前面的范例,绘制带有纹理填充的条形图。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
# 绘图
n_group = 4
means_frank = (90, 55, 40, 65)
means_guido = (85, 62, 54, 20)
# 创建图像
fig, ax = plt.subplots()
# 定义条形图在横坐标上的分类位置
index = np.arange(n_group)
bar_width = 0.35
opacity = 0.8
rectsl = plt.bar(index,
means_frank,
bar_width,
alpha=opacity,
color='w', edgecolor='k',
hatch='......',
label='张三')
rects2 = plt.bar(index + bar_width,
means_guido,
bar_width,
alpha=opacity,
color='w', edgecolor='k',
hatch='\\\\',
label='李四'
)
plt.xlabel('课程')
plt.ylabel('分数')
plt.title('分数对比图')
plt.xticks(index + bar_width, ('A', 'B', 'C', 'D'))
plt.legend()
plt.show()
本例的绘图关键在于,首先要将图形的填充色设置为白色:color=“w”。同时把图形的边界颜色设置为黑色:edgecolor=“k”。最后我们再设置图形的纹理。
参数hatch可用来设置填充的纹理类型,其可取值为/、\、|、-、+、x、o、O、.、*。这些符号表示图形中填充的符号,大多都能“见号知意”。
这里有一个小技巧,即你使用的填充单一符号越多,图形中对应的纹理就越密集,例如,通过第24行的hatch=’…‘绘制的图形就比通过hatch=’…‘绘制的图形纹理更密集,这个填充符号表示图形里面填充的都是点(.)。同理,第32行的hatch=’\\’,就比hatch=’\‘纹理密集,这里表示填充的是反斜线。
最后需要说明的是,注意转义字符的干扰。如果我们在第32行的字符串前添加一个字符r,即变为hatch=r’\\’,则图8-20中条形图的斜线纹理要密集得多.
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
# 绘图
n_group = 4
means_frank = (90, 55, 40, 65)
means_guido = (85, 62, 54, 20)
# 创建图像
fig, ax = plt.subplots()
# 定义条形图在横坐标上的分类位置
index = np.arange(n_group)
bar_width = 0.35
opacity = 0.8
rectsl = plt.bar(index,
means_frank,
bar_width,
alpha=opacity,
color='w', edgecolor='k',
hatch='......',
label='张三')
rects2 = plt.bar(index,
means_guido,
bar_width,
bottom=means_frank, ###############
alpha=opacity,
color='w', edgecolor='k',
hatch='\\\\',
label='李四'
)
plt.xlabel('课程')
plt.ylabel('分数')
plt.title('分数对比图')
plt.xticks(index + bar_width, ('A', 'B', 'C', 'D'))
plt.legend()
plt.show()
在本例中,成功绘图的关键有两点:首先,第一个条形图和第二个条形图的X轴坐标是一样的;其次,第二个条形图的Y轴坐标是站在第一个肩膀上的,第二个条形图是以第一个为底(bottom)的。于是,顺理成章地,如果我们还有第三个条形图需要叠加的话,它的起点是第二个条形图的顶点,以此类推。
前面我们讨论了条形图的绘制。如前所述,条形图一般用来描述顺序数据,其中的各个长条形之间留有空隙,以区分不同的类别,不同的类别之间没有必然的先后关系,调整彼此的顺序,并不会影响数据的可视化表达。
对比而言,直方图(Histogram)则像一种统计报告图。在外观上,它也由一个个的长条形构成,但直方图在宽度(即X轴)方向将样本的取值范围从小到大划分为若干个间隔(bin),这个间隔越大,表明涵盖的属性值跨度就越大(换句话说,间隔并不必须是等分的)。在高度(即Y轴)方向,直方图可表示特定间隔区间样本出现的次数(即频数),长条形越高,表明此间隔内的样本越多。换句话说,直方图的宽度和高度均有意义,特别是在宽度方向,“尊卑有序”,不可随意调整顺序。
为了构建直方图,第一步是将样本在某个特定属性的取值范围内进行分段,形成一系列间隔,然后计算每个间隔中有多少个样本。下面我们用范例来说明如何绘制频率分布直方图。
import numpy as np
import matplotlib.pyplot as plt
mu = 100
sigma = 15
x = mu + sigma * np.random.randn(200)
num_bins = 25
plt.figure(figsize=(9, 6), dpi=100)
n, bins, patches = plt.hist(x, num_bins,
color="w", edgecolor="k",
hatch=r'ooo',
density=1,
label='频率')
y = ((1 / (np.sqrt(2 * np.pi) * sigma)) *
np.exp(-0.5 * (1 / sigma * (bins - mu)) ** 2))
plt.plot(bins, y, '--', label='概率密度函数')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.xlabel('聪明度')
plt.ylabel('概率密度')
plt.title('IQ直方图:$\mu = 100$, $\sigma = 15$')
plt.legend()
plt.show()
代码第06行使用np.random.randn()函数随机生成期望为100,标准差为15的200个数据,num_bins表示划分的组数。本例中的核心函数是hist(),其原型如下所示。
hist(
x, bins=None, range=None, density=None, weights=None,
cumulative=False, bottom=None, histtype='bar', align='mid',
orientation='vertical', rwidth=None, log=False, color=None,
label=None, stacked=False, normed=None, *, data=None,
**kwargs):
参数:
import matplotlib.pyplot as plt
import numpy as np
x = np.random.normal(0, 1, 5000) # 生成正态分布的5000个随机样本
plt.figure(figsize=(14, 7)) # 设置图片大小 14*7inch
plt.style.use('seaborn-whitegrid') # 设置绘图风格
n, bins, patches = plt.hist(x, bins=90, facecolor='#2ab0ff',
edgecolor='#169acf', linewidth=0.5)
n = n.astype('int') # 返回值n必须是整型
# 设置显示中文的字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False # 显示负号
# 为每个条形设置颜色
for i in range(len(patches)):
patches[i].set_facecolor(plt.cm.viridis(n[i] / max(n)))
# 对某个特定条形做特别说明
patches[49].set_fc('red') # 设置颜色
patches[49].set_alpha(1) # 设置透明度:不透明
# 添加注释
plt.annotate('这是一个重要条形!', xy=(0.6, 155), xytext=(1.5, 130), fontsize=15,arrowprops={'width': 0.4, 'headwidth': 5, 'color': '#333333'})
# 设置x轴和y轴的标题、字体
plt.title('正态分布', fontsize=12)
plt.xlabel('不同的间隔(bins)', fontsize=10)
plt.ylabel('频度大小', fontsize=10)
plt.show()
在本例中,我们利用NumPy生成了5000个服从正态分布的随机样本点(第03行),然后通过直方图来可视化它们的分布。第06行除了绘制普通的直方图,更重要的是返回了是三个参数。
本例中的关键之处在于,不同的patch参数代表不同间隔(bin)的构造信息,第13~14行为每个patch设置了不同的前置色。第16~17行为特定的patch设置了填充色和透明度。
第19行是一个绘图小技巧,即利用annotate()方法在图形上给数据添加文本注解,以方便我们在合适的位置添加描述信息。