python使用matplotlib 画柱状图代码_零: python matplotlib 画图进阶(含完整代码)

导论:

在科研和研究的过程中,无论是哪个学科或者将来走上工作岗位,可视化是非常重要的一个环节。

这里的重要性,在我看来有三点:人是视觉动物,老板看你工作做的怎么样,paper reviewer看你研究做的怎么样,有相当一部分来自于图表的合理展示以及对图表的‘故事性’叙述。

通过对数据的可视化,进一步找到规律,发现问题并解决问题。因为数据都是冷冰冰的,只有把让他们“跃然纸上“,才能进一步进行挖掘价值。

针对特定研究领域(如计算机视觉,图形学),需在算法的某些步骤进行可视化以检验算法的(大致)准确性。

以上就是个人对其重要性的理解,其他就不哆嗦了。

本篇文章主要介绍matplotlib的进阶教程。基本涵盖了大部分的使用场景。matplotlib是基于python语言的一个可视化的package,在2D可视化领域还是极其强大的,应该不比R或者matlab的2D绘图功能差。

Note1: 适合入门级选手,大神请绕道~

Note2:如果研究兴趣是图形学,或者说处理对象是point cloud, mesh等3D对象,欢迎使用亮亮老师的mapple软件,非常强大。(链接如下)

顺便吐槽一下,matplotlib或者任何其他基于python的package可视化点云或者面片的效果均不理想,可以尝试下上面的链接,事半功倍。

概述:

下面五幅图是截取一些以前做research相关的中间图

其实在二维可视化场景大致分为五大类型(常用的一般都是这五种),上面的五个示意图除了条形图未覆盖其他均有。正文部分根据每个类型以一个完整Simple case +More complicated case 说明。Line-style 线状图

Scatter-style 散点图

Histograms-style 直方图

Bar-style 条形图

Image 图像

正文:

1. Line-style 线状图

(1) Simple case:

非常简单,平常画画函数是绰绰有余的

先上图:2D Line plot(simple)2D Line plot(simple)

再上代码:(这个就不注释了)

import numpy as np

import matplotlib.pyplot as plt

# 第一幅图

X = np.linspace(-np.pi, np.pi, 20, endpoint=True)

Cos, Sin = np.cos(X), np.sin(X)

plt.plot(X,Cos)

plt.plot(X,Sin )

plt.show()

# 第二幅图

n = 256

X = np.linspace(-np.pi,np.pi,n,endpoint=True)

Y = np.sin(2*X)

plt.axes([0.025,0.025,0.95,0.95])

plt.plot (X, Y+1, color='blue', alpha=1.00)

plt.fill_between(X, 1, Y+1, color='green', alpha=.25)

plt.plot (X, Y-1, color='blue', alpha=1.00)

plt.fill_between(X, -1, Y-1, (Y-1) > -1, color='blue', alpha=.25)

plt.fill_between(X, -1, Y-1, (Y-1) < -1, color='red', alpha=.25)

plt.xlim(-np.pi,np.pi), plt.xticks([])

plt.ylim(-2.5,2.5), plt.yticks([])

plt.show()

(2)More complicated case

标准的画法,基本的参数设置都有提及。

用的最多的一种形式,可以将多个曲线绘制在同一张fig中,同时可以高度定制线条、坐标轴、网格线、图例、注释等等。

先上图:2D Line plot(comprehend)

再上代码:(适当的地方我会给出注释)

要点:

设置线条:color, linewidth, linestyle, marker, markersize以及后面legend会用到的label

设置坐标轴:主要是label, ticks, lim

设置图例:主要就是简单的loc(做右下至左下分别设置为0,1,2,3),以及可以定制的bbox_to_anchor,以及是否frameon。高级用法可以有个handle可以使用(不过一般用不上)

设置网格:只需要调用plt.grid()即可

设置spine: 可以取消可见以及移动到任意位置

设置标注:两种方式。一是指向data的标注(plt.annotate),另一种是纯文本标注(plt.text)

import numpy as np

import matplotlib.pyplot as plt

import os

import sys

# 找出当前路径

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

# 生成2-D数据

X = np.linspace(-np.pi, np.pi, 20, endpoint=True)

Cos, Sin = np.cos(X), np.sin(X)

# 这里显示调用了plt.figure返回一个fig对象, 为了能够后面保存这个fig对象

# 并且设置了fig的大小和每英寸的分辨率

# 注意: resolution = figsize*dpi(因此这里的savefig的分辨率为1200X900)

fig = plt.figure(figsize=(4,3),dpi=300)

ax = plt.gca() # gca: get current axis

# 调用plt.plot函数将两条曲线画在同一个坐标系内,并设置相关的参数

# 设置线条参数:设置颜色,线宽,线形,标记,标记大小,图例标签等等

plt.plot(X, Cos, color='blue', linewidth=1, linestyle='-', marker='>', ms=5, label='cosine')

plt.plot(X, Sin, color='red', linewidth=1, linestyle='--', marker='<', ms=5, label='sine')

# 设置图例(legend)

# plt.legend(loc='auto', frameon=False) # frameon is flag to draw a frame around the legend

# Advanced legend

plt.legend(bbox_to_anchor=(0.02, .95), loc=3,

borderaxespad=0., frameon=False)

# 设置坐标轴的取值范围(lim)

plt.xlim(X.min()*1.1, X.max()*1.1)

plt.ylim(-1.2, 1.2)

# 设置坐标轴的记号(ticks)

plt.xticks(np.linspace(-np.pi, np.pi, 5, endpoint=True), [r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])

plt.yticks([-1, 0, +1], [r'$-1$', r'$0$', r'$+1$'], )

# 设置坐标轴的标签(label)

plt.xlabel('x_axis')

plt.ylabel('y_axis')

# # 打开grid选项

# plt.grid()

# 移动坐标轴到原点

# 先将上方和右方的spine去掉(color设为none即可)

# 再将x(y)坐标轴设为下方(左方)的spine,并且移动至原点

ax.spines['right'].set_color('none')

ax.spines['top'].set_color('none')

ax.xaxis.set_ticks_position('bottom')

ax.spines['bottom'].set_position(('data',0))

ax.yaxis.set_ticks_position('left')

ax.spines['left'].set_position(('data',0))

# 标注(annotate)

# 在x=t处画虚线,并且把(t, y)这个用plt.scatter的方式标记出来

# 在(t, y)处用plt.annotate方法以箭头的方式做标注。

t = 2*np.pi/3

plt.plot([t,t], [0, np.cos(t)], color='blue', linewidth=1, linestyle='--')

plt.scatter([t], [np.cos(t)], 50, color='blue')

plt.annotate(r'$\cos(\frac{2\pi}{3})=\frac{\sqrt{3}}{2}$',

xy=(t, np.cos(t)), xycoords='data',

xytext=(-90, -30), textcoords='offset points', fontsize=11,

arrowprops=dict(arrowstyle='->', connectionstyle='arc3, rad=.2'))

plt.plot([t,t], [0, np.sin(t)], color='red', linewidth=1, linestyle='--')

plt.scatter([t], [np.sin(t)], 50, color='red')

plt.annotate(r'$\sin(\frac{2\pi}{3})=\frac{\sqrt{3}}{2}$',

xy=(t, np.sin(t)), xycoords='data',

xytext=(10, 30), textcoords='offset points', fontsize=11,

arrowprops=dict(arrowstyle='->', connectionstyle='arc3, rad=.2'))

# 标注(text)

plt.text(-2, 0.8, 'Annotation with pure text', verticalalignment='bottom', horizontalalignment='right',

color='green', fontsize=8, bbox={'facecolor':'red', 'alpha':0.4, 'pad':2})

# # 将figure保存在path

# fig_name = os.path.join(BASE_DIR, 'figure.jpg')

# fig.savefig(fig_name)

plt.show()

(3) First Special case:规则化多图

多图通常用于横向或者纵向对比。可以是同类型的也可以是不同类型的。

本例主要用于示例,所以只画了四个背景色填充的fig。

先上图:regular multiple plotregular multiple plot(without ticks)

再上代码:

要点:

学会画多图,通常有两种方式:

a. plt.subplot(). 这里调用函数即可,偏于面向过程的思想

b. fig.add_subplot(). 这里的fig是plt.figure()出来的实例,偏向面向对象的思想

Note:其实还有一种方式,使用方法为: fig, ax_list = plt.subplot()。目前碰到唯一的缺陷是不能绘制不规则的多图。(不规则多图请见(4)Second special case)

完整代码如下:

import numpy as np

import matplotlib.pyplot as plt

import os

import sys

# 第一个图

for i,color in enumerate("rgby"):

plt.subplot(221+i, facecolor=color) # facecolor一般用于控制背景色

plt.show()

# 第二个图

fig = plt.figure()

for i,color in enumerate("rgby"):

fig.add_subplot(221+i, facecolor=color)

plt.xticks([]) # 用于去掉ticks

plt.yticks([]) # 用于去掉ticks

plt.show()

(4) Second Special case:不规则化多图

偶尔也会用到。

先上图:irregular multiple plotirregular multiple plot

再上代码:

要点:

在调用fig.add_subplot时,要清楚是如何划分的

import numpy as np

import matplotlib.pyplot as plt

import matplotlib.gridspec as gridspec

import os

import sys

# 第一个图

fig = plt.figure()

ax1 = fig.add_subplot(121, facecolor='r')

ax1.set_xticks([])

ax1.set_yticks([])

ax2 = fig.add_subplot(222, facecolor='g')

ax2.set_xticks([])

ax2.set_yticks([])

ax3 = fig.add_subplot(224, facecolor='k')

ax3.set_xticks([])

ax3.set_yticks([])

plt.show()

# 第二个图

G = gridspec.GridSpec(3, 3)

axes_1 = plt.subplot(G[0, :], facecolor='r')

plt.xticks([]), plt.yticks([])

plt.text(0.5,0.5, 'Axes 1',ha='center',va='center',size=24,alpha=.5)

axes_2 = plt.subplot(G[1,:-1], facecolor='g')

plt.xticks([]), plt.yticks([])

plt.text(0.5,0.5, 'Axes 2',ha='center',va='center',size=24,alpha=.5)

axes_3 = plt.subplot(G[1:, -1], facecolor='b')

plt.xticks([]), plt.yticks([])

plt.text(0.5,0.5, 'Axes 3',ha='center',va='center',size=24,alpha=.5)

axes_4 = plt.subplot(G[-1,0], facecolor='y')

plt.xticks([]), plt.yticks([])

plt.text(0.5,0.5, 'Axes 4',ha='center',va='center',size=24,alpha=.5)

axes_5 = plt.subplot(G[-1,-2], facecolor='k')

plt.xticks([]), plt.yticks([])

plt.text(0.5,0.5, 'Axes 5',ha='center',va='center',size=24,alpha=.5)

plt.show()

=======================(手动分割)=====================

2. Scatter-style 线状图

(1) Simple case:

第一幅图时使用了默认的cmap(应该是Sequential colormaps中的'hot')。第二个为qualitative colormaps中的'Set1'。

具体请参照:

先上图:cmap: defaultcmap: &#39;Set1&#39;

再上代码:

import matplotlib.pyplot as plt

import numpy as np

# 生成mean=0.0, sigma=1的二维标准正态分布,数据点为1000

# 并且采用一个函数生成一个color的一个序列(只是为了好看而已,无须研究)

n = 1000

normal_2D_data = np.random.normal(0, 1, (n, 2))

T = np.arctan2(normal_2D_data[:, 1],normal_2D_data[:, 0]) # for color value

# 调用plt.scatter进行画图,第一句采用默认的cmap即第一个图,第二句采用称为‘Set1’的 cmap即第二个图

# plt.scatter(normal_2D_data[:, 0], normal_2D_data[:, 1], s=75, c=T, alpha=.6)

plt.scatter(normal_2D_data[:, 0], normal_2D_data[:, 1], s=75, c=T, alpha=.6, cmap='Set1')

plt.xlim(-1.5, 1.5)

plt.xticks(()) # ignore xticks

plt.ylim(-1.5, 1.5)

plt.yticks(()) # ignore yticks

plt.show()

(2)More complicated case

标准的画法,基本的参数设置都有提及

假设我们有五个二维点集p1...p5。我们希望将五个点集用不同的颜色显示以区分(相当于区分不同的class)

先上图:

再上代码:

要点:

区分:本例和(1) Simple case中的第二张图,可视化出来看似有label是因为生成了一个color的一个序列并且给出了一个qualitative colormap,但是和本例有本质的区别。

核心步骤:是根据label归一化出一个值,并且根据这个值通过选择的colormap生成一个color。有两种方式:

# 方式一

import matplotlib.cm as cm

import matplotlib.colors as colors

cmap = cm.Set10

norm = Normalize(vmin=0, vmax=4) # 假设有5类

cmap(norm(0)) # 第1类的color

#方式二

norm = Normalize(vmin=0, vmax=4) # 假设有5类

color_map = cm.ScalarMappable(norm=norm , cmap=cm.Set1)

完整代码如下:

import numpy as np

import matplotlib.pyplot as plt

import matplotlib.gridspec as gridspec

import matplotlib.cm as cm

import matplotlib.colors as colors

import os

import sys

# 生成数据和标签

n_points=200

n_classes = 5

plot_with_labels = True

pts = (10-1)*np.random.random(size=(n_points ,2))-1 # 1000 poinrs, range is (1, 10]

labels = np.random.randint(0, n_classes, size=pts.shape[0]) # 5 classes, [0, 1, 2, 3, 4]

labels_dict = {0: 'pts_1', 1: 'pts_2', 2: 'pts_3', 3: 'pots_4', 4: 'pts_5'}

fig = plt.figure(dpi=120)

axe = plt.axes([0.1, 0.1, 0.7, 0.7])

# axe = fig.add_subplot(111)

if not plot_with_labels:

axe.scatter(pts[:, 0], pts[:, 1], s=100, alpha=0.6)

else:

# # 第一种方法(use: cm.color_map(color_norm(index)))

# unique_labels = np.unique(labels)

# print(unique_labels)

# n_classes = len(unique_labels)

# n_classes = n_classes - 1

# color_norm = colors.Normalize(vmin=0, vmax=4)

# for class_idx, label in enumerate(unique_labels):

# mask = np.where(labels == label)[0]

# print("mask len", len(mask))

# axe.scatter(pts[:, 0][mask], pts[:, 1][mask],

# s=100,

# color=cm.Set1(color_norm(class_idx)),

# label=labels_dict[class_idx],

# alpha=0.6)

# 第二种方法(use: combine cm.ScalarMappable and colors.Normalize)

unique_labels = np.unique(labels)

print(unique_labels)

n_classes = len(unique_labels)

n_classes = n_classes - 1

color_norm = colors.Normalize(vmin=0, vmax=4)

color_map = cm.ScalarMappable(norm=color_norm, cmap=cm.Set1)

for class_idx, label in enumerate(unique_labels):

mask = np.where(labels == label)[0]

print("mask len", len(mask))

axe.scatter(pts[:, 0][mask], pts[:, 1][mask],

s=100,

color=color_map.to_rgba(class_idx),

label=labels_dict[class_idx],

alpha=0.6)

plt.legend(bbox_to_anchor=(1.02, .8), loc=3,

borderaxespad=0., frameon=True)

axe.grid()

axe.set_title('Five Class Points Set')

# fig_name = os.path.join(BASE_DIR, 'figure_1.jpg')

# fig.savefig(fig_name)

plt.show()

=======================(手动分割)=====================

3. Histogram-style 直方图

(1) Simple case:

先上图:

再上代码:

import matplotlib.pyplot as plt

import numpy as np

import matplotlib.mlab as mlab

\mu, sigma = 100, 15

x = mu + sigma*np.random.randn(100000)

n, bins, patches = plt.hist(x, bins=30, histtype='bar', rwidth=0.8, normed=1)

print(n, bins, patches)

# add a 'best fit' line

y = mlab.normpdf( bins, mu, sigma)

l = plt.plot(bins, y, 'r--', linewidth=1)

plt.xlabel('Smarts')

plt.ylabel('Probability')

plt.title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$')

plt.axis([40, 160, 0, 0.03])

plt.grid(True)

plt.show()

(2)More complicated case

标准的画法,基本的参数设置都有提及

先上图:

再上代码:

要点:

bin的个数,柱状图的类型,透明度等

import matplotlib.pyplot as plt

import numpy as np

import matplotlib.mlab as mlab

gaussian_numbers_1 = np.random.normal(size=100000)

gaussian_numbers_2 = np.random.normal(3, 2, size=100000)

n, bins, patches = plt.hist(gaussian_numbers_1, bins=30, histtype='bar', rwidth=0.8, normed=1, color='g', alpha=0.5, label='Gaussian_1')

y = mlab.normpdf( bins, 0, 1)

l = plt.plot(bins, y, 'k--', linewidth=1)

n, bins, patches = plt.hist(gaussian_numbers_2, bins=30, histtype='bar', rwidth=0.8, normed=1, color='r', alpha=0.5, label='Gaussian_2')

y = mlab.normpdf( bins, 3, 2)

l = plt.plot(bins, y, 'k--', linewidth=1)

plt.title("Gaussian Comparasion Histogram")

plt.xlabel("Value")

plt.ylabel("Probability")

plt.legend(loc='best')

plt.show()

=======================(手动分割)=====================

4. Bar-style 条形图

(1) Simple case:

先上图:

再上代码:

import matplotlib.pyplot as plt

import numpy as np

x = np.arange(20)

y = x**2

plt.bar(x, y)

plt.xticks(np.arange(20))

plt.show()

(2)More complicated case

标准的画法,基本的参数设置都有提及

先上图:

再上代码:

要点:

n = 12

X = np.arange(n)

Y1 = (1-X/float(n)) * np.random.uniform(0.5,1.0,n)

Y2 = (1-X/float(n)) * np.random.uniform(0.5,1.0,n)

# plt.axes([0.025,0.025,0.95,0.95])

fig = plt.figure(2)

plt.bar(X, +Y1, facecolor='#9999ff', edgecolor='white', label='+Y1')

plt.bar(X, -Y2, facecolor='#ff9999', edgecolor='white', label='-Y2')

for x,y in zip(X,Y1):

plt.text(x, y+0.05, '%.2f' % y, ha='center', va= 'bottom')

for x,y in zip(X,Y2):

plt.text(x, -y-0.05, '%.2f' % y, ha='center', va= 'top')

plt.xlim(-.5,n)

plt.ylim(-1.25,+1.25)

plt.xticks([])

plt.legend()

plt.show()

=======================(手动分割)=====================

5. Image 图像

(1) Simple case:

先上图:

再上代码:

import matplotlib.pyplot as plt

import numpy as np

def f(x,y):

return (1-x/2+x**5+y**3)*np.exp(-x**2-y**2)

n = 10

x = np.linspace(-3,3,3.5*n)

y = np.linspace(-3,3,3.0*n)

X,Y = np.meshgrid(x,y)

Z = f(X,Y)

plt.axes([0.025,0.025,0.95,0.95])

plt.imshow(Z,interpolation='nearest', cmap='bone', origin='lower')

plt.colorbar(shrink=.92)

plt.xticks([]), plt.yticks([])

# savefig('../figures/imshow_ex.png', dpi=48)

plt.show()

(2)More complicated case

先上图:

再上代码:

要点:

这里是一个用于可视化模板匹配的结果。有模板,原图,热度图,此外还有colorbar。

fig = plt.figure() # the same as plt.subplot() or plt.subplot()==> return fig and a tuple of axis

ax1 = fig.add_subplot(221)

ax1.imshow(T)

ax1.set_title('Tempalte')

ax1.axis('off')

ax2 = fig.add_subplot(222)

ax2.imshow(I)

ax2.set_title('Result with bbox')

ax2.axis('off')

ax3 = fig.add_subplot(224)

cax = ax3.imshow(heatmap, cmap=cm.jet)

ax3.set_title('Heatmap')

ax3.axis('off')

ax4 = fig.add_subplot(223)

ax4.axis('off')

# Add colorbar, make sure to specify tick locations to match desired ticklabels

cbar = fig.colorbar(cax, ax=ax4, orientation='vertical', ticks=[0, np.max(heatmap)], shrink=0.6)

cbar.ax.set_yticklabels(['0', str(np.max(heatmap))]) # vertically oriented colorbar

# fig.colorbar(cax, ax=ax[2])

plt.suptitle('Method: '+similarity_method)

plt.show()

=======================(手动分割)=====================

好了,该完结了。有空再增加点三维可视化的东西。最后给大家推荐一个除了matplotlib之外的一个非常好用的packages:plotly(链接如下)

这篇博文算是这段时间经常用matplotlib的一个总结和再学习,同时也希望能够帮助入门同志们学习和使用(对,是入门级,如果是大神请直接再看一遍找找问题哈哈哈),如果有什么问题,欢迎在评论区交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值