编程语言
首页 > 编程语言> > python-使用Cartopy制作动画

python-使用Cartopy制作动画

作者:互联网

我正在尝试编写一个python程序,该程序显示世界地图的动画,其中各国根据使用的可再生能源的使用量来改变颜色.我试图让它显示1960年所有国家的颜色,然后显示1961年和1962年所有国家的颜色…

我正在使用cartopy在图中添加国家/地区,并根据我从SQL数据库提取到pandas数据框中的值将其颜色作为基础.我能够得到这样的地图来显示我想要的一年:
enter image description here

但是,我不知道如何对其进行动画处理.我尝试使用FuncAnimate,但是我真的很难理解它的工作原理.所有示例似乎都具有返回线的功能,但我没有在绘制线或轮廓.这是我尝试过的:

import sqlite3
import pandas as pd
import os
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.animation as animation
import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
from math import log
from math import exp
from matplotlib import colors
path = 'H:/USER/DVanLunen/indicator_data/world-development-indicators/'
os.chdir(path)
con = sqlite3.connect('database.sqlite')

# Grab :
# % of electricity from renewable sources EG.ELC.RNWX.ZS
# 1960 - 2013

Indicator_df = pd.read_sql('SELECT * '
                           'FROM Indicators '
                           'WHERE IndicatorCode in('
                                                   '"EG.ELC.RNWX.ZS"'
                                                   ')'
                           , con)
# setup colorbar stuff and shape files
norm = mpl.colors.Normalize(vmin=0, vmax=30)
colors_in_map = []
for i in range(30):
    val = log(i + 1, logbase) / log(31, logbase)
    colors_in_map.append((1 - val, val, 0))
cmap = colors.ListedColormap(colors_in_map)

shpfilename = shpreader.natural_earth(resolution='110m',
                                      category='cultural',
                                      name='admin_0_countries')
reader = shpreader.Reader(shpfilename)
countries_map = reader.records()
logbase = exp(1)
fig, ax = plt.subplots(figsize=(12, 6),
                       subplot_kw={'projection': ccrs.PlateCarree()})


def run(data):
    """Update the Dist"""
    year = 1960 + data % 54
    logbase = exp(1)
    for n, country in enumerate(countries_map):
        facecolor = 'gray'
        edgecolor = 'black'
        indval = Indicator_df.loc[(Indicator_df['CountryName'] ==
                                   country.attributes['name_long']) &
                                  (Indicator_df['Year'] == year), 'Value']
        if indval.any():
                greenamount = (log(float(indval) + 1, logbase) /
                               log(31, logbase))
                facecolor = 1 - greenamount, greenamount, 0
        ax.add_geometries(country.geometry, ccrs.PlateCarree(),
                          facecolor=facecolor, edgecolor=edgecolor)
        ax.set_title('Percent of Electricity from Renewable Sources ' +
                     str(year))
    ax.figure.canvas.draw()

cax = fig.add_axes([0.92, 0.2, 0.02, 0.6])
cb = mpl.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm,
                               spacing='proportional')
cb.set_label('%')

ani = animation.FuncAnimation(fig, run, interval=200, blit=False)
plt.show()

任何帮助将不胜感激.谢谢!

Indicator_df的一些示例数据(不真实):

CountryName     Year     Value
United States     1960     5
United States     1961     10
United States     1962     20
United States     1963     30

解决方法:

设置run()的方式实际上存在几个问题,但主要的问题似乎实际上是枚举(countries_map). records()函数返回一个生成器,一旦您运行了它,一次看起来就不喜欢再次运行-我尝试将其与动画分开以确保.

也就是说,通过将大量代码移出run()可以完全避免该问题.目前,即使可行,您仍在重新绘制每个国家/地区的每个框架,而不仅是带有颜色的框架.它既费力又不必要-您不需要多次绘制任何灰色的图形.

我已经对您的代码进行了一些重组,并使用了我在美国和阿根廷输入的虚假数据,对我来说效果很好.

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.animation as animation
import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
from math import log
from math import exp
from matplotlib import colors

# Grab :
# % of electricity from renewable sources EG.ELC.RNWX.ZS
# 1960 - 2013

# Make fake data
Indicator_df = pd.DataFrame({'CountryName':['United States']*4+['Argentina']*4,
                             'Year':[1960, 1961, 1962, 1963]*2,
                             'Value':[5, 10, 20, 30]*2})

# setup colorbar stuff and shape files
norm = mpl.colors.Normalize(vmin=0, vmax=30)
colors_in_map = []
logbase = exp(1)
for i in range(30):
    val = log(i + 1, logbase) / log(31, logbase)
    colors_in_map.append((1 - val, val, 0))
cmap = colors.ListedColormap(colors_in_map)

shpfilename = shpreader.natural_earth(resolution='110m',
                                      category='cultural',
                                      name='admin_0_countries')
reader = shpreader.Reader(shpfilename)
countries_map = reader.records()

# These don't need to constantly be redefined, especially edgecolor
facecolor = 'gray'
edgecolor = 'black'

fig, ax = plt.subplots(figsize=(12, 6),
                       subplot_kw={'projection': ccrs.PlateCarree()})

# Draw all the gray countries just once in an init function
# I also make a dictionary for easy lookup of the geometries by country name later
geom_dict = {}
def init_run():
    for n, country in enumerate(countries_map):
        ax.add_geometries(country.geometry, ccrs.PlateCarree(),
                          facecolor=facecolor, edgecolor=edgecolor)
        geom_dict[country.attributes['name_long']] = country.geometry


def run(data):
    """Update the Dist"""
    # "data" in this setup is a frame number starting from 0, so it corresponds nicely
    # with your years
    year = 1960 + data

    # get a subset of the df for the current year
    year_df = Indicator_df[Indicator_df['Year'] == year]
    for i, row in year_df.iterrows():
        # This loops over countries, gets the value and geometry and adds
        # the new-colored shape
        geom = geom_dict[row['CountryName']]
        value = row['Value']
        greenamount = (log(float(value) + 1, logbase) /
                       log(31, logbase))
        facecolor = 1 - greenamount, greenamount, 0
        ax.add_geometries(geom, ccrs.PlateCarree(),
                          facecolor=facecolor, edgecolor=edgecolor)

    # I decreased the indent of this, you only need to do it once per call to run()
    ax.set_title('Percent of Electricity from Renewable Sources ' +
                 str(year))

cax = fig.add_axes([0.92, 0.2, 0.02, 0.6])
cb = mpl.colorbar.ColorbarBase(cax, cmap=cmap, norm=norm,
                               spacing='proportional')
cb.set_label('%')

ani = animation.FuncAnimation(fig, run, init_func=init_run, frames=4,
                              interval=500, blit=False)
plt.show()

主要区别在于,我根本不在运行功能内访问shpreader.制作动画时,运行功能中唯一应做的事情就是更改后的事情,您无需在每一帧都重新绘制所有内容.

就是说,如果您仅从第一个绘制开始就保留美术师,并在run函数中更改其颜色,而不是重新制作一个新的ax.add_geometries,这可能会更好.您必须研究如何为此更改Cartopy FeatureArtist的颜色.

标签:matplotlib-basemap,cartopy,matplotlib,animation,python
来源: https://codeday.me/bug/20191118/2031949.html