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

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

随着中国的各种实力的提高,经常在各种媒体上看到中国与各个国家历年的各种指标数据的对比,为了更清楚的展示历年的发展趋势,有的还做成了动图,看到中国各种指标数据的近年的不断逆袭,心中的自豪感油然而生。今天通过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()来指定。

数据集见 https://xiejava1018.github.io/xiejavaimagesrc/images/2023/20230827/中国VS美国.xlsx


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

目录
相关文章
|
7天前
|
Python
以下是一些常用的图表类型及其Python代码示例,使用Matplotlib和Seaborn库。
以下是一些常用的图表类型及其Python代码示例,使用Matplotlib和Seaborn库。
|
6天前
|
机器学习/深度学习 搜索推荐 数据可视化
Python量化炒股常用的Matplotlib包
Python量化炒股常用的Matplotlib包
19 7
|
3天前
|
数据可视化 数据挖掘 API
Python中的数据可视化利器:Matplotlib与Seaborn对比解析
在Python数据科学领域,数据可视化是一个重要环节。它不仅帮助我们理解数据,更能够让我们洞察数据背后的故事。本文将深入探讨两种广泛使用的数据可视化库——Matplotlib与Seaborn,通过对比它们的特点、优劣势以及适用场景,为读者提供一个清晰的选择指南。无论是初学者还是有经验的开发者,都能从中找到有价值的信息,提升自己的数据可视化技能。
|
5天前
|
Python
Matplotlib 教程 之 Matplotlib 绘图标记 9
在本教程中,我们将探讨如何使用 Matplotlib 的 `plot()` 方法中的 `marker` 参数来自定义图表标记。您可以选择不同的线类型(如实线 `&#39;-&#39;`、虚线 `&#39;:&#39;` 等),以及颜色类型(如红色 `&#39;r&#39;`、绿色 `&#39;g&#39;` 等)。同时,通过调整 `markersize (ms)`、`markerfacecolor (mfc)` 和 `markeredgecolor (mec)` 参数,可以定制标记的大小和颜色。
10 1
|
6天前
|
API Python
30天拿下Python之matplotlib模块
30天拿下Python之matplotlib模块
|
6天前
|
Python
Matplotlib 教程 之 Matplotlib 绘图标记 8
在 Matplotlib 中,可以通过 `plot()` 方法的 `marker` 参数自定义图表标记。此外,还可以设置线类型(如 `&#39;-&#39;` 实线、`&#39;:&#39;` 虚线等)和颜色(如 `&#39;r&#39;` 红色、`&#39;g&#39;` 绿色等)。使用 `markersize` (`ms`) 定义大小,`markerfacecolor` (`mfc`) 和 `markeredgecolor` (`mec`) 分别定义标记的内部和边框颜色。
13 0
|
7天前
|
数据可视化 数据挖掘 Linux
10幅必须掌握的Seaborn绘图
10幅必须掌握的Seaborn绘图
20 0
|
7天前
|
数据可视化 Python
Matplotlib 教程 之 Matplotlib 绘图标记 6
在本教程中,我们将探讨如何利用 Matplotlib 的 `plot()` 方法中的 `marker` 参数来自定义图表标记,以增强数据可视化效果。此外,还介绍了线类型(如实线 `&#39;-&#39;`、虚线 `&#39;:&#39;` 等)、颜色类型(如红色 `&#39;r&#39;`、绿色 `&#39;g&#39;` 等)以及如何通过 `markersize` (`ms`)、`markerfacecolor` (`mfc`) 和 `markeredgecolor` (`mec`) 来调整标记的大小和颜色。通过一个示例展示了如何设置标记大小。
14 0
|
7天前
|
Python
Matplotlib 教程 之 Matplotlib 绘图标记 5
使用 Matplotlib 的 `plot()` 方法通过 `marker` 参数来自定义图表标记,同时解释了如何利用 `fmt` 参数定义标记、线条样式及颜色,例如 &#39;o:r&#39; 分别表示实心圆标记、虚线及红色。并通过一个实例演示了其使用方法。
14 0
|
7天前
|
数据可视化 数据处理 Python
Matplotlib:Python绘图利器之王
Matplotlib:Python绘图利器之王
11 0
下一篇
无影云桌面