03_Python 使用Matplotlib绘图

2019.5.13

不知不觉,已经进入第12周了,Python数据分析的学习现今也已经进入了中后期,在继上周进行了Numpy的康威生命游戏的编写之后;紧接着进行的学习就是利用Python的Matplotlib模块来练习绘图。这次由于涉及到图像,所以引用了一些丁烨老师的pdf的截图。主要是进行用Matplotlib模块来进行MATLAB能做的数据分析绘图工作,并结合Numpy和Matplotlib来做一个扫雷小游戏。


matplotlib

一. Matplotlib模块


1. 概述

matplotlib官网

Matplotlib是一个Python 2D绘图库可以生成各种硬拷贝格式和跨平台的交互式环境的出版物质量数据只需几行代码即可生成绘图,直方图,功率谱,条形图,错误图,散点图等。 对于简单的绘图pyplot模块提供了类似MATLAB的接口,特别是与IPython结合使用时。而我们进行数据分析就是在使用这个模块。 对于高级用户,您可以通过面向对象的界面或MATLAB用户熟悉的一组函数完全控制线型,字体属性,轴属性等。



2. 基本用法


  1. 基本概念
    (图片源自丁烨老师的讲义pdf,侵权删)
绘图的基本概念01.png
绘图的基本概念02.png
绘图的基本概念03.png
绘图的基本概念04.png

  1. 数据准备
    1. 输入数据应当是 np.array 或 np.ma.masked_array 格式 。
    2. 其他类似数组的格式,例如标准库的 list、Pandas 的 pandas.DataFrame、NumPy 的 np.matrix 等也可能能用。
    3. 在绘制图表前,最好将输入格式转换为 np.array。


  1. 函数讲解

  1. matplotlib.pyplot.plot()

    plot()用于在figure上画出曲线图其中比较值得注意的参数有 x, y, label, 样式等。x, y决定了曲线的形状,即哪些点(可传入特定点,或者x ** 2等函数方式)。label决定了曲线的名字。样式决定了图像中的点的颜色,样式,线的样子。

    from matplotlib import pyplot as plt
    import numpy as np
    
    x = np.linspace(0, 2, 100) # 利用numpy创建一个矩阵,方便用于数据输入
    plt.plot(x, x, label='linear') # 画出直线 y=x
    plt.plot(x, x**2, label='quadratic') # 画出曲线 y = x²
    plt.plot(x, x**3, label='cubic') # 画出曲线 y = x^3
    plt.xlabel('x label') # 设置x轴名称
    plt.ylabel('y label') # 设置y轴名称
    plt.title("Simple Plot") # 设置图片的标题
    plt.legend() # 画出一个图例,用于标出什么颜色和样式的线代表什么
    plt.show()
    
    sample plot.png

  1. 线条的样式

    修改图片的样式01.png

    修改图片的样式02.png
    from matplotlib import pyplot as plt
    plt.plot([1, 2, 3, 4], [1, 4, 9, 16], 'ro') # 根据表格可知,画出的图形是红色的圈
    plt.axis([0, 6, 0, 20])
    plt.show()
    
    样式使用案例.png


  1. 其他几种绘图的函数

    • matplotlib.pyplot.hist() 用于绘制直方图
    • matplotlib.pyplot.bar() 用于绘制柱状图
    • matplotlib.pyplot.scatter() 用于绘制散点图
    from matplotlib import pyplot as plt
    import numpy as np
    
    mu, sigma = 100, 15 
    x = mu + sigma * np.random.randn(10000)
    # the histogram of the data 
    n, bins, patches = plt.hist( x, 50, density=1, facecolor='g', alpha=0.75 )
    plt.xlabel('Smarts') 
    plt.ylabel('Probability') 
    plt.title('Histogram of IQ') 
    plt.text(60, .025, r'$\mu=100,\ \sigma=15$') 
    plt.axis([40, 160, 0, 0.03]) 
    plt.grid(True) 
    plt.show()
    
    绘制直方图.png
    from matplotlib import pyplot as plt
    
    names = ['group_a', 'group_b', 'group_c'] # 用一个列表存储三个图的名字
    values = [1, 10, 100] # 用列表存储用到的点
    plt.figure(1, figsize=(9, 3)) # 创建一副图
    plt.subplot(131) # 创建子图
    plt.bar(names, values) # 绘制柱状图
    plt.subplot(132)
    plt.scatter(names, values) # 绘制散点图
    plt.subplot(133)
    plt.plot(names, values) # 绘制曲线图
    plt.suptitle('Categorical Plotting')
    plt.show()
    
    其他类型的绘图.png


  1. 绘制子图

    import numpy as np
    from matplotlib import pyplot as plt
    
    def f(t):
        return np.exp(-t) * np.cos(2*np.pi*t)
    t1 = np.arange(0.0, 5.0, 0.1)
    t2 = np.arange(0.0, 5.0, 0.02)
    plt.figure(1)
    plt.subplot(211)
    plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k')
    plt.subplot(212)
    plt.plot(t2, np.cos(2*np.pi*t2), 'r--')
    plt.show()
    
    绘制子图.png


二.利用Numpy和matplotlib.pyplot来实现扫雷游戏


  1. 效果图
扫雷01.png

扫描02.png


  1. 源代码
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import RegularPolygon
from scipy.signal import convolve2d
 
 
class MineSweeper(object):
    """docstring for MineSweeper"""
    covered_color = '#DDDDDD'
    uncovered_color = '#AAAAAA'
    edge_color = '#888888'
    count_colors = ['none', 'blue', 'green', 'red', 'darkred', 'darkgreen', 'black', 'black']
    flag_vertices = np.array([[0.25, 0.2], [0.25, 0.8], [0.75, 0.65], [0.25, 0.5]])
 
    @classmethod
    def beginner(cls):
        return cls(8, 8, 10)
 
    @classmethod
    def intermediate(cls):
        return cls(16, 16, 40)
 
    @classmethod
    def expert(cls):
        return cls(30, 16, 99)
 
    def __init__(self, width, height, nmines):
        self.width, self.height, self.nmines = width, height, nmines
 
        # Create the figure and axes
        self.fig = plt.figure(figsize=((width + 2) / 3., (height + 2) / 3.))
        self.ax = self.fig.add_axes(
            (0.05, 0.05, 0.9, 0.9),
            aspect='equal',
            frameon=False,
            xlim=(-0.05, width + 0.05),
            ylim=(-0.05, height + 0.05))
        for axis in (self.ax.xaxis, self.ax.yaxis):
            axis.set_major_formatter(plt.NullFormatter())
            axis.set_major_locator(plt.NullLocator())
 
        # Create the grid of squares
        self.squares = np.array([[RegularPolygon(
            (i + 0.5, j + 0.5),
            numVertices=4,
            radius=0.5 * np.sqrt(2),
            orientation=np.pi / 4,
            ec=self.edge_color,
            fc=self.covered_color
            ) for j in range(height)] for i in range(width)])
        [self.ax.add_patch(sq) for sq in self.squares.flat]
 
        # Define internal state variables
        self.mines = None
        self.counts = None
        self.clicked = np.zeros((self.width, self.height), dtype=bool)
        self.flags = np.zeros((self.width, self.height), dtype=object)
        self.game_over = False
 
        # Create event hook for mouse clicks
        self.fig.canvas.mpl_connect('button_press_event', self._button_press)
 
    def _draw_mine(self, i, j):
        self.ax.add_patch(plt.Circle((i + 0.5, j + 0.5), radius=0.25, ec='black', fc='black'))
 
    def draw_red_x(self, i, j):
        self.ax.text(i + 0.5, j + 0.5, 'X', color='r', fontsize=20, ha='center', va='center')
 
    def _toggle_mine_flag(self, i, j):
        if self.clicked[i, j]:
            pass
        elif self.flags[i, j]:
            self.ax.patches.remove(self.flags[i, j])
            self.flags[i, j] = None
        else:
            self.flags[i, j] = plt.Polygon(self.flag_vertices + [i, j], fc='red', ec='black', lw=2)
            self.ax.add_patch(self.flags[i, j])
 
    def _reveal_unmarked_mines(self):
        for (i, j) in zip(*np.where(self.mines & ~self.flags.astype(bool))):
            self._draw_mine(i, j)
 
    def _cross_out_wrong_flags(self):
        for (i, j) in zip(*np.where(self.mines & ~self.flags.astype(bool))):
            self.draw_red_x(i, j)
 
    def _mark_remaining_mines(self):
        for (i, j) in zip(*np.where(self.mines & ~self.flags.astype(bool))):
            self._toggle_mine_flag(i, j)
 
    def _setup_mines(self, i, j):
        # Randomly place mines on a grid, but not on space (i, j)
        idx = np.concatenate([
            np.arange(i * self.height + j),
            np.arange(i * self.height + j + 1, self.width * self.height)
        ])
        np.random.shuffle(idx)
        self.mines = np.zeros((self.width, self.height), dtype=bool)
        self.mines.flat[idx[:self.nmines]] = 1
 
        # Count the number of mines bordering each square
        self.counts = convolve2d(self.mines.astype(complex), np.ones((3, 3)), mode='same').real.astype(int)
 
    def isclicked(self, i, j):
        # to deal with the situation that the square is clikced
        # If the clicked square's number equals to the numbers of flags surrounded,
        # open all of squares surrounded it expect the flaged one
        count = 0
        for ii in range(max(0, j - 1), min(self.width, i + 2)):
            for jj in range(max(0, j - 1), min(self.height, j + 2)):
                if self.flags[ii, jj]:
                    count = count + 1
 
        if count == self.counts[i, j]:
            for ii in range(max(0, j - 1), min(self.width, i + 2)):
                for jj in range(max(0, j - 1), min(self.height, j + 2)):
                    if (self.flags[ii, jj] == 0) and (self.clicked[ii, jj] == False):
                        # why it goes wrong when I write like xxx is False?
                        self.clicked[ii, jj] = True
 
                        if self.mines[ii, jj]:
                            self.squares[ii, jj].set_facecolor(self.uncovered_color)
                            self._draw_mine(ii, jj)
                            self.draw_red_x(ii, jj)
 
                        elif self.counts[ii, jj] == 0:
                            self.squares[ii, jj].set_facecolor(self.uncovered_color)
 
                        else:
                            self.squares[ii, jj].set_facecolor(self.uncovered_color)
                            self.ax.text(
                                ii + 0.5, jj + 0.5,
                                str(self.counts[ii, jj]),
                                color=self.count_colors[self.counts[ii, jj]],
                                ha='center', va='center', fontsize=18,
                                fontweight='bold'
                            )
        return
 
    def _click_square(self, i, j):
        # If this is the first click, then set up the mines
        if self.mines is None:
            self._setup_mines(i, j)
 
        # If there is a flag or square is already clicked, do nothing
        if self.flags[i, j]:
            return
 
        if self.clicked[i, j]:
            self.isclicked(i, j)
            return
 
        # Mark this mines is clicked
        self.clicked[i, j] = True
 
        # Hit a mine: game over
        if self.mines[i, j]:
            self.game_over = True
            self._reveal_unmarked_mines()
            self.draw_red_x(i, j)
            self._cross_out_wrong_flags()
 
        # Square with no surrounding mines: Clear out all adjacent squares
        elif self.counts[i, j] == 0:
            self.squares[i, j].set_facecolor(self.uncovered_color)
            for ii in range(max(0, j - 1), min(self.width, i + 2)):
                for jj in range(max(0, j - 1), min(self.height, j + 2)):
                    self._click_square(ii, jj)
 
        # Hit an empty square: reveal the number
        else:
            self.squares[i, j].set_facecolor(self.uncovered_color)
            self.ax.text(
                i + 0.5, j + 0.5,
                str(self.counts[i, j]),
                color=self.count_colors[self.counts[i, j]],
                ha='center', va='center', fontsize=18,
                fontweight='bold'
            )
 
        # If all remaining squares are mines, mark them and end game
        if self.mines.sum() == (~self.clicked).sum():
            self.game_over = True
            self._mark_remaining_mines()
 
    def _button_press(self, event):
        if self.game_over or (event.xdata is None) or (event.ydata is None):
            return
        i, j = map(int, (event.xdata, event.ydata))
        if i < 0 or j < 0 or i >= self.width or j >= self.height:
            return
 
        # Left mouse button: reveal square
        if event.button == 1:
            self._click_square(i, j)
 
        # Right mouse button: mark or unmark flag
        elif (event.button == 3) and (not self.clicked[i, j]):
            self._toggle_mine_flag(i, j)
 
        self.fig.canvas.draw()
 
 
if __name__ == '__main__':
    ms = MineSweeper.beginner()
    plt.show()


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容