Python通过matplotlib动态绘图实现中美GDP历年对比趋势动图

news2024/11/17 9:50:48

随着中国的各种实力的提高,经常在各种媒体上看到中国与各个国家历年的各种指标数据的对比,为了更清楚的展示历年的发展趋势,有的还做成了动图,看到中国各种指标数据的近年的不断逆袭,心中的自豪感油然而生。今天通过Python来实现matplotlib的动态绘图,将中美两国近年的GDP做个对比,展示中国GPD对美国的追赶态势,相信不久的将来中国的GDP数据将稳超美国。
效果如下:
中美GDP历年对比趋势动图

实现上面的动态绘图效果,综合用到了pandas的数据采集、数据整理、matplotlib绘图、坐标轴及数据的动态定义、定时器等知识。最终通过Python的GUI库PySide进行展示形成一个GUI的可执行程序。

一、数据采集和准备

中美历年的GDP数据通过百度在网上一搜一大把。我是从https://www.kylc.com/stats/global/yearly_per_country/g_gdp/chn-usa.html 找到的数据。将数据整理成EXCEL保存至data\中国VS美国.xlsx。
中国VS美国GDP数据集

有从1966年至2022年的中美GDP的数据。
首先对这些数据进行整理,因为获取的GDP数据是字符串类型如17.96万亿 (17,963,170,521,079),我们需要将GDP的数据从文本中提取出来,也就是取括号中的数据。
这里通过正则表达式将括号中的GDP数据提取出来,并转换为亿元为单位。

import re
import pandas as pd
import locale
import matplotlib.pyplot as plt

pattern = re.compile('\((\S*)\)')

def getgdpvalue(gdpstr):
    re_obj=pattern.search(gdpstr)
    gdp_value=locale.atof(re_obj.group(1))/100000000
    return gdp_value
    
df_data = pd.read_excel('data\中国VS美国.xlsx')
df_data = df_data.loc[1:len(df_data)]
df_data['china_gdp_value'] = df_data['中国'].map(getgdpvalue)
df_data['us_gdp_value'] = df_data['美国'].map(getgdpvalue)
df_data = df_data.sort_values('年份')

有了数据以后就可以通过数据绘图了。

二、matplotlib绘图

先通过matplotlib绘图看看数据的效果。

import matplotlib.pyplot as plt
plt.figure()
plt.plot(df_data['年份'],df_data['china_gdp_value'])
plt.plot(df_data['年份'],df_data['us_gdp_value'])
plt.title('中美GDP对比')
plt.xlabel('年份')
plt.ylim('GDP(亿)')
plt.show()

中美GDP对比趋势

可以看到中国的GDP数据在1960年至1990年都是比较平稳的,到了1990年后中国开始了爆发式的追赶模式。
我们要将这种趋势通过动态的方式展示出来。

三、数据展示与动态更新

首先通过QMainWindw定义QWidget组件,在QWidget中加入FigureCanvasQTAgg组件通过canvas载入matplotlib绘图。

class ApplicationWindow(QMainWindow):

    def __init__(self, parent=None,org_data=None):
        QMainWindow.__init__(self, parent)
        self.axes = None
        self.axis_china=None
        self.axis_us=None
        self.datacount=10
        self.org_data = org_data
        self.auto_offset = 0
        # Central widget
        self._main = QWidget()
        self.setCentralWidget(self._main)
        # Figure
        self.canvas = FigureCanvasQTAgg(figure)
        if len(self.org_data) > 0:
            show_data = self.org_data[0:self.datacount]
            self.axes = self.canvas.figure.subplots()
            self.axes.set_title('中美GDP对比')
            self.axis_china = self.axes.plot(show_data['年份'], show_data['china_gdp_value'], label='中国GDP')
            self.axis_us = self.axes.plot(show_data['年份'], show_data['us_gdp_value'], label='美国GDP')
            y_max = max(self.org_data['us_gdp_value'].max(), self.org_data['china_gdp_value'].max())
            self.axes.set_ylabel('GDP(亿元)')
            self.axes.set_xlabel('年份')
            self.axes.set_ylim(0, y_max)
            self.axes.set_xlim(show_data['年份'].min(), show_data['年份'].max())
            self.axes.legend(loc="upper left")
            self.axes.yaxis.set_major_locator(mticker.MultipleLocator(20000))
            self.axes.xaxis.set_major_locator(mticker.MultipleLocator(1))
            figure.tight_layout()  # 自动调整子图参数,使之填充整个图像区域
        # 下拉框,选择模式 # ComboBox (combo_type)
        self.combo_type = QComboBox()
        self.combo_type.addItems(['自动播放', '手动播放'])
        # Sliders
        min_value = 0
        self.max_value = len(self.org_data)-cur_data_len
        self.slider_update = QSlider(minimum=min_value, maximum=self.max_value, orientation=Qt.Horizontal) # 滑动条
        layout1 = QHBoxLayout()
        layout1.addWidget(self.combo_type)
        # layout
        layout2 = QVBoxLayout()
        layout2.addWidget(self.canvas, 88)
        layout2.addWidget(self.slider_update)
        # Main layout
        layout = QVBoxLayout(self._main)
        layout.addLayout(layout1)
        layout.addLayout(layout2, 100)
        self.canvas.draw()
        # Signal and Slots connections
        self.combo_type.currentTextChanged.connect(self.selecttype)
        self.slider_update.valueChanged.connect(self.update_frequency)
        self.autoslider()

一种方式是通过QSlider组件,通过手动拉slider组件来实现数据的变化,一种通过QTimer组件自动让数据变化。

1、QSlider组件,手动方式实现动态绘图

@Slot()
def update_frequency(self, new_val):
    # 偏移量每次偏移1
    f = int(new_val)
    offset = f + cur_data_len  # 偏移刻度
    show_data = self.org_data[f: offset]
    x = show_data['年份']
    y_china = show_data['china_gdp_value']
    y_us = show_data['us_gdp_value']
    self.axes.set_xlim(x.min(), x.max())
    self.axis_china[0].set_data(x, y_china)
    self.axis_us[0].set_data(x, y_us)
    self.canvas.draw()

手动拉slider组件来实现数据的变化效果:
手动数据变化

2、QTimer组件,自动动态绘图

    self.autoslider()

def autoslider(self):
    self.timer = QTimer()
    self.timer.setInterval(100) # 100毫秒更新一次数据
    self.timer.timeout.connect(self.autoupdate) #自动更新数据,每次更新偏移量加1,也就是跳一年的数据 
    self.timer.start()

def autoupdate(self):
    self.update_frequency(self.auto_offset)
    self.slider_update.setSliderPosition(self.auto_offset)
    if self.auto_offset < self.max_value:
        self.auto_offset = self.auto_offset+1
    else:
        self.auto_offset = 0

效果如文章最前面所示。

四、完整代码

import re
import sys
import pandas as pd
import locale
import matplotlib.ticker as mticker
from PySide6.QtCore import Qt, Slot, QTimer
from PySide6.QtWidgets import QMainWindow, QApplication, QVBoxLayout, QHBoxLayout, QWidget, QSlider, QComboBox
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
from matplotlib.figure import Figure

figure = Figure(figsize=(12, 6), dpi=90)

global cur_data_len, cur_major_locator
cur_data_len = 10  # 当前显示的数据量(显示10年的数据)
cur_major_locator = 10  # 当前刻度的定位器(主刻度)

pattern = re.compile('\((\S*)\)')

def getgdpvalue(gdpstr):
    re_obj=pattern.search(gdpstr)
    gdp_value=locale.atof(re_obj.group(1))/100000000
    return gdp_value

class ApplicationWindow(QMainWindow):

    def __init__(self, parent=None,org_data=None):
        QMainWindow.__init__(self, parent)
        self.axes = None
        self.axis_china=None
        self.axis_us=None
        self.datacount=10
        self.org_data = org_data
        self.auto_offset = 0
        # Central widget
        self._main = QWidget()
        self.setCentralWidget(self._main)
        # Figure
        self.canvas = FigureCanvasQTAgg(figure)
        if len(self.org_data) > 0:
            show_data = self.org_data[0:self.datacount]
            self.axes = self.canvas.figure.subplots()
            self.axes.set_title('中美GDP对比')
            self.axis_china = self.axes.plot(show_data['年份'], show_data['china_gdp_value'], label='中国GDP')
            self.axis_us = self.axes.plot(show_data['年份'], show_data['us_gdp_value'], label='美国GDP')
            y_max = max(self.org_data['us_gdp_value'].max(), self.org_data['china_gdp_value'].max())
            self.axes.set_ylabel('GDP(亿元)')
            self.axes.set_xlabel('年份')
            self.axes.set_ylim(0, y_max)
            self.axes.set_xlim(show_data['年份'].min(), show_data['年份'].max())
            self.axes.legend(loc="upper left")
            self.axes.yaxis.set_major_locator(mticker.MultipleLocator(20000))
            self.axes.xaxis.set_major_locator(mticker.MultipleLocator(1))
            figure.tight_layout()  # 自动调整子图参数,使之填充整个图像区域
        # 下拉框,选择模式 # ComboBox (combo_type)
        self.combo_type = QComboBox()
        self.combo_type.addItems(['自动播放', '手动播放'])
        # Sliders
        min_value = 0
        self.max_value = len(self.org_data)-cur_data_len
        self.slider_update = QSlider(minimum=min_value, maximum=self.max_value, orientation=Qt.Horizontal) # 滑动条
        layout1 = QHBoxLayout()
        layout1.addWidget(self.combo_type)
        # layout
        layout2 = QVBoxLayout()
        layout2.addWidget(self.canvas, 88)
        layout2.addWidget(self.slider_update)
        # Main layout
        layout = QVBoxLayout(self._main)
        layout.addLayout(layout1)
        layout.addLayout(layout2, 100)
        self.canvas.draw()
        # Signal and Slots connections
        self.combo_type.currentTextChanged.connect(self.selecttype)
        self.slider_update.valueChanged.connect(self.update_frequency)
        self.autoslider()

    def autoslider(self):
        self.timer = QTimer()
        self.timer.setInterval(100) # 100毫秒更新一次数据
        self.timer.timeout.connect(self.autoupdate) #自动更新数据,每次更新偏移量加1,也就是跳一年的数据
        self.timer.start()

    def autoupdate(self):
        self.update_frequency(self.auto_offset)
        self.slider_update.setSliderPosition(self.auto_offset)
        if self.auto_offset < self.max_value:
            self.auto_offset = self.auto_offset+1
        else:
            self.auto_offset = 0

    @Slot()
    def selecttype(self, text):
        if '自动播放' == text:
            self.autoslider()
        elif '手动播放' == text:
            self.timer.stop()

    @Slot()
    def update_frequency(self, new_val):
        # 偏移量每次偏移1
        f = int(new_val)
        offset = f + cur_data_len  # 偏移刻度
        show_data = self.org_data[f: offset]
        x = show_data['年份']
        y_china = show_data['china_gdp_value']
        y_us = show_data['us_gdp_value']
        self.axes.set_xlim(x.min(), x.max())
        self.axis_china[0].set_data(x, y_china)
        self.axis_us[0].set_data(x, y_us)
        self.canvas.draw()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
    df_data = pd.read_excel('data\中国VS美国.xlsx')
    df_data = df_data.loc[1:len(df_data)]
    df_data['china_gdp_value'] = df_data['中国'].map(getgdpvalue)
    df_data['us_gdp_value'] = df_data['美国'].map(getgdpvalue)
    df_data = df_data.sort_values('年份')
    w = ApplicationWindow(org_data=df_data)
    w.setFixedSize(1000, 500)
    w.show()
    app.exec()

六、总结

Python实现matplotlib动态绘图,是非常简单和容易的,其实关键还是在数据的组织,也就是要准备好要绘图的坐标轴的x的数据和y的数据,通过set_data(x,y)来动态更新数据,要注意的是变化的数据后X轴或Y轴的显示要变化,这里可以通过轴的set_xlim()或set_ylim()方法来动态设置,刻度也可通过set_major_locator()来指定。

完整代码及数据集见 http://xiejava.ishareread.com/


作者博客:http://xiejava.ishareread.com/

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023.8.27 碎碎念

碎碎念系列更新 离上次更新快一个月了 随便写写 一、关于工作 公司项目应用端开发&#xff08;了解了shell&#xff0c;awk等&#xff09;公司自研APP维护 后续计划写一篇shell相关的博客 二、关于学习 最近把算法也捡起来了&#xff0c;虽然还是很菜&#xff0c;今天周赛…

回归预测 | MATLAB实现GWO-ELM灰狼算法优化极限学习机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现GWO-ELM灰狼算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现GWO-ELM灰狼算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本介绍程…

单片机电子元器件-数码管

数码管分类 共阳 把所有数码管的阳极接到一起形成公共阳极COM 数码管 共阳极COM 接到 5V 电源 共阴 把所有数码管的阴极接到一起形成公共阴极COM 数码管 共阴极COM 接到 地 GND 上 八段 数码管 和 七段数码管&#xff0c; 多了一个 小数点 DP 数码管显示原理 一个数码管如…

YOLO目标检测——肺炎分类数据集下载分享

肺炎分类数据集总共21000图片&#xff0c;可应用于&#xff1a;肺炎检测、疾病诊断、疾病预测和预警等等。 数据集点击下载&#xff1a;YOLO肺炎分类数据集21000图片.rar

Fooocus启动时modules报错的解决方法

原理&#xff1a;是由于其他程序的安装导致modules的版本不对&#xff0c;先卸载现有版本&#xff0c;再运行run.bat让其自动安装响应的modules版本。 1、cmd运行windows dos终端。 2、将Fooocus_win64_1-1-1035文件夹备份&#xff0c;rename为Fooocus_win64_1-1-1035backup文…

轻松上传、管理和分享图片——PicGo for Mac,你的最佳选择

作为一名经常使用图片的用户&#xff0c;你一定经历过图片上传、管理和分享的烦恼。PicGo for Mac是一款专为Mac用户设计的图片上传工具&#xff0c;它能够帮助你轻松完成这些任务。 首先&#xff0c;PicGo for Mac提供了一种简单而高效的方式来上传图片。你只需将图片拖放到Pi…

《网络是怎样连接的》(五)

本文主要取材于 《网络是怎样连接的》 第五章。 目录 5.1 Web服务器的部署地点 5.2 防火墙的结构和原理 5.3服务器负载平衡 5.4 使用缓存服务器分担负载 5.5 内容分发服务 简述&#xff1a;本文主要内容是解释 网络包如何朝服务器前进&#xff0c;并通过服务器前面的防…

VM——西门子Smart 200进行S7通信

1、参考文章《海康VisionMaster与西门子Smart 200进行S7通信_机器人自动化控制的博客-CSDN博客》 2、注意事项&#xff1a; &#xff08;1&#xff09;PLC设置的变量类型是VW&#xff0c;而不是MW。 &#xff08;2&#xff09;与S7一样&#xff0c;默认端口号是102&#xff…

深入剖析Kubernetes之控制器模式的实现-Deployment

文章目录 Deployment Deployment Deployment 实现了 Kubernetes 项目中一个非常重要的功能&#xff1a;Pod 的“水平扩展 / 收缩”&#xff08;horizontal scaling out/in&#xff09;。这个功能&#xff0c;是从 PaaS 时代开始&#xff0c;一个平台级项目就必须具备的编排能力…

在Windows操作系统上安装Neo4j数据库

在Windows操作系统上安装Neo4j数据库 一、在Windows操作系统上安装Neo4j数据库 一、在Windows操作系统上安装Neo4j数据库 点击 MySQL可跳转至MySQL的官方下载地址。 在VUE3项目的工程目录中&#xff0c;通过以下命令可生成node_modules文件夹。 npm install&#xff08;1&am…

用U盘装Ubuntu22.04双系统前需要提前规避的两大问题

如果你是GPT分区&#xff0c;且Bios开启了UEFI&#xff08;无论你选的是启动模式是LegacyUEFI还是UEFI&#xff0c;都算开启了UEFI&#xff09;那你装Ubuntu时可以忽略本文&#xff0c;只看最末尾的装机教程 以下2个问题叠加&#xff0c;就会出现引导丢失的问题&#xff08;版…

【持续更新中】QAGroup1

OVERVIEW Q&AGroup1一、语言基础1.C语言&#xff08;1&#xff09;含参数的宏与函数的不同点&#xff08;2&#xff09;sizeof与strlen的区别&#xff08;3&#xff09;大/小端&#xff08;4&#xff09;strcpy与memcpy的区别&#xff08;5&#xff09;extern与static的区别…

代码随想录算法训练营之JAVA|第三十九天|474. 一和零

今天是第39天刷leetcode&#xff0c;立个flag&#xff0c;打卡60天。 算法挑战链接 474. 一和零https://leetcode.cn/problems/ones-and-zeroes/ 第一想法 题目理解&#xff1a;找到符合条件的子集&#xff0c;这又是一个组合的问题。 看到这个题目的时候&#xff0c;我好像…

软件测试报告包含哪些内容?

软件测试报告一般包含以下内容&#xff1a; 1、引言&#xff08;目的、背景、缩略语、参考文献&#xff09; 2、测试概述&#xff08;测试目的、项目介绍、测试目标&#xff09; 3、测试资源&#xff08;测试人员、测试软硬件环境及配置、测试环境的网络拓扑&#xff09; 4…

【办公类-16-01-02】2023年度上学期“机动班下午代班的排班表——跳过周三、节日和周末”(python 排班表系列)

背景需求&#xff1a; 2023年第一学期&#xff08;2023年9-2024年1月&#xff09;&#xff0c;我又被安排为“机动班”&#xff0c;根据新学期的校历&#xff0c;手动推算本学期的机动班的带班表 排版原则 1、班级数量&#xff1a;共有6个班级&#xff0c;循环滚动 2、每周次…

集丰照明|这种灯光效果既简约又漂亮适合汽修洗车美容店

明亮的灯光&#xff0c;既能吸引客户上门&#xff0c;营造美观舒适的氛围。洗车美容店灯光方面既要满足基本的照明亮度&#xff0c;也要有图案、形状的美感。 下面是一家汽车服务店面不同区域的灯光效果&#xff0c;仅供想要开洗车店或者准备店面改造升级的朋友做参考。 灯光是…

Linux系统编程之文件编程常用API回顾和文件编程一般步骤

目录 1.打开文件 2.创建文件 3.写入文件 4.读取文件 5.光标定位 6.关闭文件 7.文件编程一般步骤 Linux系统提供了一些常用API如&#xff1a; 打开/创建 open/creat 读写 write /read 光标定位 Iseek 关闭 close 1.打开文件 参数说明 Pathname:要打开的文件名 (含路径&…

Android Xfermode 使用解析

自定义绘制之图片 canvar.drawBitmap() ,BitMapFactory private fun getBitmap(width: Int): Bitmap? {val option BitmapFactory.Options()option.inJustDecodeBounds trueBitmapFactory.decodeResource(resources, R.mipmap.android111,option)option.inJustDecodeBounds…

Python中@property和@setter的用法

一、property 用法&#xff1a;可以使用property装饰器来创建只读属性&#xff0c;property装饰器会将方法转换为相同名称的只读属性&#xff0c;这样可以防止属性被修改。 实例 class DataSet(object):propertydef method_with_property(self): ##含有propertyreturn 15def…

搭建个人博客Linux + WordPress

这篇文章主要介绍如何搭建个人网站&#xff0c;环境是Linux WordPress。 前面我是搞了个个人网站&#xff0c;不过呢&#xff0c;现在访问不了了。域名过期后&#xff0c;我没及时重新买&#xff0c;然后原先的域名&#xff0c;不知道被哪位兄弟给买走了。 分下面这么几步&a…