matplotlib从起点出发(15)_Tutorial_15_blitting

0 位图传输技术与快速渲染

Blitting,即位图传输、块传输技术是栅格图形化中的标准技术。在Matplotlib的上下文中,该技术可用于(大幅度)提高交互式图形的性能。例如,动画和小部件模块在内部使用位图传输。在这里,我们将演示如何在这些类之外实现自己的blitting。

位图传输技术通过将所有不变的图形元素渲染到背景图像中来加速重复绘图。然后,对于每次绘图,只需要将不断变化的元素绘制到此背景上。例如,如果一个Axes的限制没有改变,我们可以渲染一次空轴,包括所有刻度和标签,然后只绘制变化的数据。

这种策略是:

  • 准备常量背景:
    • 绘制图形,但通过将所有要动画化的artists对象标记为动画来排除它们(参看Artist.set_animated);
    • 保存一份RBGA缓存的备份。
  • 渲染单个图像:
    • 还原RBGA缓冲区的副本;
    • 使用Axes.draw_artist/Figure.draw_artist重新绘制动画Artist;
    • 在屏幕上显示生成的图像。

此过程的一个结果是,你的动态artists始终绘制在静态artists之上。

并非所有的后端都支持传输。你可以通过以下的方式检查给定的画布是否支持这样做:FigureCanvasBase.supports_blit属性。

警告
此代码不适用于OSX后端(但适用于Mac上的其他GUI后端)。

1 最小示例

我们可以将FigureCanvasAgg方法copy_from_bboxrestore_region结合在artists上设置animated=True来实现一个使用位图传输来加速渲染的最小示例。

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2 * np.pi, 100)

fig, ax = plt.subplots()

# animated=True 告诉 matplotlib 只在我们显式请求时才绘制
# 某个artist
(ln,) = ax.plot(x, np.sin(x), animated=True)

# 确保窗口已经显示,但脚本继续运行
plt.show(block=False)

# 停止欣赏空荡荡的窗口,确保至少渲染一次
#
# 我们需要在屏幕上完整绘制这个图形直到最终的大小
# 在我们继续之前 :
#  a) 我们有正确的大小和绘制的背景可以抓取
#  b) 我们可以渲染缓存,从而 ``ax.draw_artist`` 可以工作
# 所以我们旋转事件循环,让后端处理任何待处理的操作
plt.pause(0.1)

# 获取整张图像的副本(所有fig.bbox中的内容)
bg = fig.canvas.copy_from_bbox(fig.bbox)
# 绘制动画artist, 这里使用了一个缓存渲染
ax.draw_artist(ln)
# 将结果显示到屏幕上,这将RGBA缓存更新从渲染器中推送到GUI框架上
# 从而让你能看得见它
fig.canvas.blit(fig.bbox)

for j in range(100):
    # 将背景重置为画布状态,屏幕不变
    fig.canvas.restore_region(bg)
    # 更新artist, 画布状态和屏幕都保持不变
    ln.set_ydata(np.sin(x + (j / 100) * np.pi))
    # 重新渲染artist, 更新画布状态, 但不更新屏幕
    ax.draw_artist(ln)
    # 将图像复制到GUI状态,但屏幕可能尚未改变
    fig.canvas.blit(fig.bbox)
    # 刷新任何挂起的 GUI 事件,如果需要,重新绘制屏幕
    fig.canvas.flush_events()
    # 你可以旋转一个暂停在此如果你想要让整个过程降速
    # plt.pause(.1)

在这里插入图片描述

这个示例有效并显示了一个简单的动画,但是因为我们只抓取了一次背景,如果图形的像素大小发生变化(由于图形的大小或者dpi发生变化),背景就失效,并导致错误发生(但有时看起来会很酷,还有一个全局变量和相当多的样板,这表明我们应该将其包装在一个类中)。

2 基于类的示例

我们可以使用一个类来封装恢复背景、绘制artist,然后将结果传输到屏幕上的样板逻辑和状态。此外,每当发生完全重新绘制以正确处理调整大小时,我们使用"draw_event"回调来捕获新的背景。

class BlitManager:
    def __init__(self, canvas, animated_artists=()):
        """
        Parameters
        ----------
        canvas : FigureCanvasAgg
            The canvas to work with, this only works for subclasses of the Agg
            canvas which have the `~FigureCanvasAgg.copy_from_bbox` and
            `~FigureCanvasAgg.restore_region` methods.

        animated_artists : Iterable[Artist]
            List of the artists to manage
        """
        self.canvas = canvas
        self._bg = None
        self._artists = []

        for a in animated_artists:
            self.add_artist(a)
        # 在每次绘图上抓取背景
        self.cid = canvas.mpl_connect("draw_event", self.on_draw)

    def on_draw(self, event):
        """Callback to register with 'draw_event'."""
        cv = self.canvas
        if event is not None:
            if event.canvas != cv:
                raise RuntimeError
        self._bg = cv.copy_from_bbox(cv.figure.bbox)
        self._draw_animated()

    def add_artist(self, art):
        """
        Add an artist to be managed.

        Parameters
        ----------
        art : Artist

            The artist to be added.  Will be set to 'animated' (just
            to be safe).  *art* must be in the figure associated with
            the canvas this class is managing.

        """
        if art.figure != self.canvas.figure:
            raise RuntimeError
        art.set_animated(True)
        self._artists.append(art)

    def _draw_animated(self):
        """Draw all of the animated artists."""
        fig = self.canvas.figure
        for a in self._artists:
            fig.draw_artist(a)

    def update(self):
        """Update the screen with animated artists."""
        cv = self.canvas
        fig = cv.figure
        # 如果错过了绘制事件,则什么也不画
        if self._bg is None:
            self.on_draw(None)
        else:
            # 还原背景
            cv.restore_region(self._bg)
            # 绘制所有的动画artists
            self._draw_animated()
            # 更新GUI状态
            cv.blit(fig.bbox)
        # 让GUI事件循环处理所有它该干的事儿
        cv.flush_events()

以下是我们将如何使用我们的类。这是一个比第一种情况稍微复杂一些的例子,因为我们是学添加了一个文本框架计数器。

# 创建一个新的绘图
fig, ax = plt.subplots()
# 添加一条线
(ln,) = ax.plot(x, np.sin(x), animated=True)
# 添加帧序号
fr_number = ax.annotate(
    "0",
    (0, 1),
    xycoords="axes fraction",
    xytext=(10, -10),
    textcoords="offset points",
    ha="left",
    va="top",
    animated=True,
)
bm = BlitManager(fig.canvas, [ln, fr_number])
# 确保你的窗口在屏幕上,绘图
plt.show(block=False)
plt.pause(.1)

for j in range(100):
    #更新artists
    ln.set_ydata(np.sin(x + (j / 100) * np.pi))
    fr_number.set_text(f"frame: {j}")
    # 告诉位图传输管理器来更新
    bm.update()

在这里插入图片描述

此类不依赖于pyplot,适合嵌入到更大的GUI应用程序中。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/562985.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

记录一个hive中跑insert语句说没创建spark客户端的问题

【背景说明】 我目前搭建离线数仓,并将hive的执行引擎改成了Spark,在将ods层的数据装载到dim层,执行insert语句时报如下错误 【报错】 [42000][40000] Error while compiling statement: FAILED: SemanticException Failed to get a spark…

Rust序列化和反序列化

Rust 编写python 模块 必备库 docker 启动 nginx 服务 NGINX 反向代理配置

RAG技术从入门到精通

LLM之RAG技术从入门到精通 RAG技术介绍诞生背景定义 RAG与微调RAG流程架构RAG三种范式Naive RAGAdvanced RAG预检索过程嵌入后期检索过程RAG管道优化 Modular RAG RAG工作流程企业知识问答知识库RAG评估评价方法独立评估端到端评估 关键指标和能力 RAG优化RAG在企业知识库应用下…

WebSocket 快速入门 - springboo聊天功能

目录 一、概述 1、HTTP(超文本传输协议) 2、轮询和长轮询 3、WebSocket 二、WebSocket快速使用 1、基于Java注解实现WebSocket服务器端 2、JS前端测试 三、WebSocket进阶使用 1、如何获取当前用户信息 2、 后端聊天功能实现 一、概述 HTTP…

Navicat Premium 16最新版激活 mac/win

Navicat Premium 16 for Mac是一款专业的多连接数据库管理工具。它支持连接多种类型的数据库,包括MySQL、MongoDB、Oracle、SQLite、SQL Server、PostgreSQL等,可以同时连接多种数据库,帮助用户轻松地管理和迁移数据。 Navicat Premium 16 fo…

Wpf 使用 Prism 实战开发Day21

配置默认首页 当应用程序启动时&#xff0c;默认显示首页 一.实现思路&#xff0c;通过自定义接口来配置应用程序加载完成时&#xff0c;设置默认显示页 步骤1.创建自定义 IConfigureService 接口 namespace MyToDo.Common {/// <summary>/// 配置默认显示页接口/// <…

Golang那些违背直觉的编程陷阱

目录 知识点1&#xff1a;切片拷贝之后都是同一个元素 知识点2&#xff1a;方法集合决定接口实现&#xff0c;类型方法集合是接口方法集合的超集则认定为实现接口&#xff0c;否则未实现接口 切片拷贝之后都是同一个元素 package mainimport ("encoding/json"&quo…

springboot是什么?

可以应用于Web相关的应用开发。 选择合适的框架&#xff0c;去开发相关的功能&#xff0c;会有更高的效率。 为什么Spring Boot才是你该学的!学java找工作必会技能!在职程序员带你梳理JavaEE框架_哔哩哔哩_bilibili java工程师的必备技能 Spring是Java EE领域的企业级开发宽…

Kafka源码分析(四) - Server端-请求处理框架

系列文章目录 Kafka源码分析-目录 一. 总体结构 先给一张概览图&#xff1a; 服务端请求处理过程涉及到两个模块&#xff1a;kafka.network和kafka.server。 1.1 kafka.network 该包是kafka底层模块&#xff0c;提供了服务端NIO通信能力基础。 有4个核心类&#xff1a;…

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第六套

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第六套 (共9套&#xff0c;有答案和解析&#xff0c;答案非官方&#xff0c;未仔细校正&#xff0c;仅供参考&#xff09; 部分题目分享&#xff0c;完整版获取&#xff08;WX:didadidadidida313&#xff0c;加我备注&#x…

使用python socket搭建Client测试平台

目录 概述 1 背景 2 Client功能实现 2.1 何谓Client 2.2 代码功能介绍 2.3 代码实现 2.3.1 代码介绍 2.3.2 代码内容 3 测试 3.1 PC上创建Server 3.2 同一台PC上运行Client 3.2.1 建立连接 3.2.2 测试数据交互 3.3 Linux 环境下运行Client 3.3.1 建立连接 3.3.…

无限滚动分页加载与下拉刷新技术探析:原理深度解读与实战应用详述

滚动分页加载&#xff08;也称为无限滚动加载、滚动分页等&#xff09;是一种常见的Web和移动端应用界面设计模式&#xff0c;用于在用户滚动到底部时自动加载下一页内容&#xff0c;而无需点击传统的分页按钮。这种设计旨在提供更加流畅、连续的浏览体验&#xff0c;减少用户交…

Redis 如何实现分布式锁

课程地址 单机 Redis naive 版 加锁&#xff1a; SETNX ${lockName} ${value} # set if not exist如果不存在则插入成功&#xff0c;返回 1&#xff0c;加锁成功&#xff1b;否则返回 0&#xff0c;加锁失败 解锁&#xff1a; DEL ${lockName}问题1 2 个线程 A、B&#…

深入理解与实践“git add”命令的作用

文章目录 **git add命令的作用****git add命令的基本作用****高级用法与注意事项** git add命令的作用 引言&#xff1a; 在Git分布式版本控制系统中&#xff0c;git add命令扮演着至关重要的角色&#xff0c;它是将本地工作区的文件变动整合进版本控制流程的关键步骤。本文旨…

使用docker搭建GitLab个人开发项目私服

一、安装docker 1.更新系统 dnf update # 最后出现这个标识就说明更新系统成功 Complete!2.添加docker源 dnf config-manager --add-repohttps://download.docker.com/linux/centos/docker-ce.repo # 最后出现这个标识就说明添加成功 Adding repo from: https://download.…

ConcurrentHashMap 源码分析(一)

一、简述 本文对 ConcurrentHashMap#put() 源码进行分析。 二、源码概览 public V put(K key, V value) {return putVal(key, value, false); }上面是 ConcurrentHashMap#put() 的源码&#xff0c;我们可以看出其核心逻辑在 putVal() 方法中。 final V putVal(K key, V val…

在centos系统中使用boost库

打开MobaXterm软件 下载 boost_1_85_0.tar.gz tar -zxvf boost_1_85_0.tar.gz解压缩成boost_1_85_0文件夹 双击arrayDemo.cpp 在里面可以编写代码 arrayDemo.cpp #include <boost/timer/timer.hpp> #include <boost/array.hpp> #include <cmath> #inc…

Redis中的Lua脚本(六)

Lua脚本 清空repl_scriptcache_dict字典 每当主服务器添加一个新的从服务器时&#xff0c;主服务器都会清空自己的repl_scriptcache_dict字典&#xff0c;这是因为随着新从服务器的出现&#xff0c;repl_scriptcache_字典里面记录的脚本已经不再被所有从服务器载入过&#xf…

天梯赛 L2-052 吉利矩阵

//r[n]:当前第几列的值。 //l[n]:当前第几行的值。 暴力减止 #include<bits/stdc.h> using namespace std; #define int long long const int n1e3; int a,b,c,l[n],r[n],an; void dfs(int x,int y) {if(xb1){an;return ;}for(int i0;i<a;i){l[x]i;r[y]i;if(l[x]&l…

【001_音频开发-基础篇-专业术语】

001_音频开发-基础篇-专业术语 文章目录 001_音频开发-基础篇-专业术语创作背景术语表常见音源HDMI相关声音系统立体声2.1 声音系统5.1 环绕声系统5.1.2 环绕声系统7.1 环绕声系统7.1.4 环绕声系统9.1.4 环绕声系统 音质等级定义QQ音乐网易云音乐 创作背景 学历代表过去、能力…