子图属性错误:“AxesSubplot”对象没有属性“get_extent”

Phi*_*eal 5 python maps matplotlib geopandas

我正在尝试在 matplotlib.pyplot 上实现一个函数,它可以在我的地图中插入标尺和指北针。

\n\n

我正在尝试调整“ http://stackoverflow.com/a/35705477/1072212 ”中的代码为 Geopandas 地理数据集。

\n\n

在我的尝试中,主要问题是获取每个图(轴)的边界框坐标。出现的错误是:“subplot AttributeError:\'AxesSubplot\'对象没有属性\'get_extent\'”

\n\n

我尝试了很多方法来规避这个问题,但没有成功(见附件中的代码)。

\n\n

如下例所示(附件中的代码),我使用巴西的社会经济数据(来自 IBGE - https://www.ibge.gov.br/estatisticas-novoportal/sociais/populacao/9109-projecao-da-populacao。 html?=&t=下载)。

\n\n

该社会经济数据已根据巴西的 shapefile 进行地理定位(获取于:http ://www.codegeo.com.br/2013/04/shapefiles-do-brasil-para-download.html)进行地理定位,并在下面的代码为“SHP_joined”。因此,为了更好地描述它,SHP_joined 是一个 geopandas 地理数据框,我试图从中实现其图中的标尺和指北针。

\n\n

还提供了我想要的最终图像的示例。“在此图像示例中,它仍然缺少标尺和指北针”

\n\n

感谢您抽出宝贵的时间,希望很快能收到您的回复。

\n\n
`# -*- coding: utf-8 -*-\n"""\nCreated on Fri Jul 20 14:53:26 2018\n\n@author: Terry Brown - Adapted by Philipe Leal\n"""\n\nimport os\nimport cartopy.crs as ccrs\nfrom math import floor\nimport matplotlib.pyplot as plt\nfrom matplotlib import patheffects\nimport numpy as np\nimport matplotlib\nif os.name == \'nt\':\n    matplotlib.rc(\'font\', family=\'Arial\')\nelse:  \n    # might need tweaking, must support black triangle for N arrow\n    matplotlib.rc(\'font\', family=\'DejaVu Sans\')\n\n\ndef utm_from_lon(lat,lon):\n    """\n\n    :param float lon: longitude\n    :return: UTM zone number\n    :rtype: int\n    """\n\n    UTM_zone_number = np.int(np.floor( ( lon + 180 ) / 6) + 1)\n    print("UTM Zone algorithm 1: ", UTM_zone_number)\n\n    import utm\n\n\n    UTM_zone_number2 = utm.latlon_to_zone_number(-14.2393, -54.39)\n\n    print("UTM Zone algorithm 2: ", UTM_zone_number2)\n\n    if UTM_zone_number2 == UTM_zone_number:\n        print("OK: UTM algorithms are equal!")\n\n        return UTM_zone_number\n\n    else:\n        print("UTM algorithms are different. Using library UTM instead!")\n        return UTM_zone_number2\n\n##### Caso Geopandas:\n\n\ndef scale_bar_geopandas(ax, Geopandas_dataset, length, location=(0.5, 0.05), linewidth=3,\n              units=\'km\', m_per_unit=1000):\n    """\n\n    http://stackoverflow.com/a/35705477/1072212\n    ax is the axes to draw the scalebar on.\n    proj is the projection the axes are in\n    location is center of the scalebar in axis coordinates ie. 0.5 is the middle of the plot\n    length is the length of the scalebar in km.\n    linewidth is the thickness of the scalebar.\n    units is the name of the unit\n    m_per_unit is the number of meters in a unit\n    """\n    # find lat/lon center to find best UTM zone\n\n    Minx, Miny, Maxx, Maxy = Geopandas_dataset.total_bounds\n\n    Latitude_central = (Miny+ Maxy) /2.\n\n    Longitude_central = (Minx + Maxx) /2.\n\n    print("Latitude_central: ", Latitude_central)\n\n    print("Longitude_central: ", Longitude_central)\n    # Projection in metres\n\n    try: \n        utm = ccrs.UTM(utm_from_lon( Latitude_central, Longitude_central))\n\n    except:\n        utm = ccrs.UTM(utm_from_lon(Latitude_central, Longitude_central),\n                        southern_hemisphere=True)\n\n\n    # Get the extent of the plotted area in coordinates in metres\n\n    # find lat/lon center to find best UTM zone\n\n    x0, x1, y0, y1 = Minx, Miny, Maxx, Maxy\n\n    # Turn the specified scalebar location into coordinates in metres\n    sbcx, sbcy = x0 + (x1 - x0) * location[0], y0 + (y1 - y0) * location[1]\n    # Generate the x coordinate for the ends of the scalebar\n    bar_xs = [sbcx - length * m_per_unit/2, sbcx + length * m_per_unit/2]\n    # buffer for scalebar\n    buffer = [patheffects.withStroke(linewidth=5, foreground="w")]\n    # Plot the scalebar with buffer\n    ax.plot(bar_xs, [sbcy, sbcy], transform=ax.transAxes, color=\'k\',\n        linewidth=linewidth, path_effects=buffer)\n    # buffer for text\n    buffer = [patheffects.withStroke(linewidth=3, foreground="w")]\n    # Plot the scalebar label\n    t0 = ax.text(sbcx, sbcy, str(length) + \' \' + units, transform=ax.transAxes,\n        horizontalalignment=\'center\', verticalalignment=\'bottom\',\n        path_effects=buffer, zorder=2)\n    left = x0+(x1-x0)*0.05\n    # Plot the N arrow\n    t1 = ax.text(left, sbcy, u\'\\u25B2\\nN\', transform=ax.transAxes,\n        horizontalalignment=\'center\', verticalalignment=\'bottom\',\n        path_effects=buffer, zorder=2)\n    # Plot the scalebar without buffer, in case covered by text buffer\n    ax.plot(bar_xs, [sbcy, sbcy], transform=ax.transAxes, color=\'k\',\n        linewidth=linewidth, zorder=3)\n\n\n\n\n\n\n\n\n###### Casos Normais:\n\ndef scale_bar(ax, proj, length, location=(0.5, 0.05), linewidth=3,\n              units=\'km\', m_per_unit=1000):\n    """\n\n    http://stackoverflow.com/a/35705477/1072212\n    ax is the axes to draw the scalebar on.\n    proj is the projection the axes are in\n    location is center of the scalebar in axis coordinates ie. 0.5 is the middle of the plot\n    length is the length of the scalebar in km.\n    linewidth is the thickness of the scalebar.\n    units is the name of the unit\n    m_per_unit is the number of meters in a unit\n    """\n    # find lat/lon center to find best UTM zone\n    try:\n        x0, x1, y0, y1 = ax.get_extent(proj.as_geodetic())\n    except:\n        try:\n            print("Trying to extract tje image extent by ax.get_window_extent()")\n            x0, x1, y0, y1 = ax.get_window_extent(proj.as_geodetic())\n\n        except:\n            try:\n                print("Trying to extract tje image extent by np.ravel(ax.get_window_extent())")\n                x0, x1, y0, y1 = np.ravel(ax.get_window_extent(proj.as_geodetic()))\n                print("\\n\\n x0, x1, y0 e y1 acquired succesfully: \\n\\n")\n                print(x0, x1, y0, y1, "\\n\\n")\n            except: \n                print("Error. x0, x1, y0 e y1 not extracted!")\n\n\n    Latitude_central = (y0+y1)/2.\n\n    Longitude_central = (x0+x1)/2.\n\n    print("Latitude_central: ", Latitude_central)\n\n    print("Longitude_central: ", Longitude_central)\n    # Projection in metres\n\n    try: \n        utm = ccrs.UTM(utm_from_lon( Latitude_central, Longitude_central))\n\n    except:\n        utm = ccrs.UTM(utm_from_lon(Latitude_central, Longitude_central),\n                        southern_hemisphere=True)\n\n\n    print(utm)\n    # Get the extent of the plotted area in coordinates in metres\n\n    # find lat/lon center to find best UTM zone\n    try:\n        x0, x1, y0, y1 = ax.get_extent(utm)\n    except:\n        print("Trying to extract the image extent by ax.get_window_extent()")\n        try:\n            x0, x1, y0, y1 = ax.get_window_extent(utm)\n        except:\n            try:\n                print("Trying to extract the image extent by np.ravel(ax.get_window_extent())")\n\n                x0, x1, y0, y1 = np.ravel(ax.get_window_extent(utm))\n                print("\\n\\n x0, x1, y0 e y1 in UTM Projection acquired succesfully: \\n\\n")\n                print(x0, x1, y0, y1, "\\n\\n")\n\n            except: \n                print("Error. x0, x1, y0 e y1 not extracted!")\n\n\n\n    # Turn the specified scalebar location into coordinates in metres\n    sbcx, sbcy = x0 + (x1 - x0) * location[0], y0 + (y1 - y0) * location[1]\n    # Generate the x coordinate for the ends of the scalebar\n    bar_xs = [sbcx - length * m_per_unit/2, sbcx + length * m_per_unit/2]\n    # buffer for scalebar\n    buffer = [patheffects.withStroke(linewidth=5, foreground="w")]\n    # Plot the scalebar with buffer\n    ax.plot(bar_xs, [sbcy, sbcy], transform=ax.transAxes, color=\'k\',\n        linewidth=linewidth, path_effects=buffer)\n    # buffer for text\n    buffer = [patheffects.withStroke(linewidth=3, foreground="w")]\n    # Plot the scalebar label\n    t0 = ax.text(sbcx, sbcy, str(length) + \' \' + units, transform=ax.transAxes,\n        horizontalalignment=\'center\', verticalalignment=\'bottom\',\n        path_effects=buffer, zorder=2)\n    left = x0+(x1-x0)*0.05\n    # Plot the N arrow\n    t1 = ax.text(left, sbcy, u\'\\u25B2\\nN\', transform=ax.transAxes,\n        horizontalalignment=\'center\', verticalalignment=\'bottom\',\n        path_effects=buffer, zorder=2)\n    # Plot the scalebar without buffer, in case covered by text buffer\n    ax.plot(bar_xs, [sbcy, sbcy], transform=ax.transAxes, color=\'k\',\n        linewidth=linewidth, zorder=3)\n\n\n\n############ Testing Data example:\n\n\nimport pandas as pd\n\nimport geopandas as gpd\n\n\nfile_name = r\'C:\\Doutorado\\Tese\\SINAN\\Casos_hepatite_A_por_estado_por_ano\\Por_Regioes_BR_por_Ano.xlsx\'\n\n## Fluxo temporal 1 ano em 1 ano:\n\n\ndf = pd.read_excel(file_name, sheet_name=\'prevalencias\', header=[1,2])\n\n\nstacked = df.stack()\nstacked.reset_index(inplace=True)\n\n\nstacked_keys = stacked.keys()\n\nKeys_dict = {\'level_0\':\'ANO\', \'Ano\':\'REGIAO\', \'REGIAO\':\'Prevalencias\'}\n\nstacked = stacked.rename(columns=Keys_dict)\n\nstacked.set_index(\'REGIAO\', inplace=True)\n\n\nKeys_dict_index = {\'Centro-Oeste\': \'Centro Oeste\'}\n\nstacked = stacked.rename(index=Keys_dict_index)\n\n# Filtrando apenas os anos acima de 2006:\nstacked = stacked[stacked[\'ANO\'] >= 2007]\n\n\nstacked[\'Prevalencias_relativas_%\'] = stacked[\'Prevalencias\']/np.sum(stacked[\'Prevalencias\'])*100\n\n\nSHP_path = r\'c:\\Doutorado\\Tese\\SHP\\Estados_do_Brasil\\Brasil_UTF_8.shp\'\n\nSHP = gpd.read_file(SHP_path)\n\nSHP.head()\n\n\nSHP.set_index(\'REGIAO\', inplace=True)\n\n\nSHP_joined = SHP.join(stacked)\n\nSHP_joined = SHP_joined[SHP_joined[\'ANO\'] >=2007]\n\n\nSHP_joined = SHP_joined.to_crs({\'init\': \'epsg:4326\'}) ## WGS-84\n\nMinx, Miny, Maxx, Maxy = SHP_joined.total_bounds\n\nLatitude_central = (Miny+ Maxy) /2.\n\nLongitude_central = (Minx + Maxx) /2.\n\n\nAnos = np.unique(SHP_joined[\'ANO\'])\n\nYears = []\nfor Ano in Anos:\n    if Ano == np.nan:\n        None\n    elif str(Ano) == \'nan\':\n        None\n    else:\n        Years.append(Ano)\n\nYears = np.array(Years,np.int16) \n\n\n###### ------------------------------------------#############\n\n\n\n\nfig, Ax = plt.subplots(nrows=4,ncols=3, sharex=\'col\', sharey=\'row\',\n                       )\nfig.suptitle(\'Preval\xc3\xaancia da Hepatite-A por Regi\xc3\xa3o\', fontsize=16)\n\n# definindo Vmin e Vmax para garantir range entre todos os subplots:\n    # para ajuste local por subplot, deletar Vmin e Vmax.\n    # ex: https://gis.stackexchange.com/questions/273273/reducing-space-in-geopandas-and-matplotlib-pyplots-subplots\nVmin = SHP_joined[\'Prevalencias_relativas_%\'].min()\nVmax = SHP_joined[\'Prevalencias_relativas_%\'].max()\n\n\nfor i in range(len(Years)):\n    Ano = Years[i]\n    print(Ano)\n\n    Axes = Ax.ravel()[i]\n\n\n    SHP_joined[SHP_joined[\'ANO\']==Ano].plot(ax=Axes,\n                                            column=\'Prevalencias_relativas_%\', \n                                            legend=False,\n                                            cmap=\'viridis\',\n                                            vmin=Vmin, vmax=Vmax,\n                                            label=str(Ano))\n\n\n    Axes.set_aspect(\'equal\')\n    Axes.set_title(str(Ano), fontsize=8)\n    Axes.grid()\n\n    scale_bar_geopandas(Axes, SHP_joined, length=100000)\n\n\nAxes11 = Ax.ravel()[11] \nAxes11.set_aspect(\'equal\')\nAxes11.grid()\n\ncax = fig.add_axes([0.9, 0.17, 0.02, 0.65])\nsm = plt.cm.ScalarMappable(cmap=\'viridis\', norm=plt.Normalize(vmin=Vmin, vmax=Vmax))\nsm._A = []\ncbar = fig.colorbar(sm, cax=cax)\ncbar.ax.set_title(\'Prevalencia\\n relativa (%)\')\n\n\n#im = plt.gca().get_children()[0]\n#cax = fig.add_axes([0.90,0.1,0.03,0.8]) \n#fig.colorbar(im, cax=cax)\n\n\nfig.subplots_adjust(top=0.855,\n                    bottom=0.065,\n                    left=1.21e-17,\n                    right=0.850,\n                    hspace=0.5,\n                    wspace=0.005)\n\n\nscale_bar_geopandas(Axes11, SHP_joined, length=100000)\nplt.show()`\n
Run Code Online (Sandbox Code Playgroud)\n

Diz*_*ahi 6

您的问题是创建轴的方式,作为“普通”matplotlib 轴而不是配备投影的轴。您可以传递其他参数来plt.subplots()使用subplot_kws=参数,然后将其传递给每个单独的Axes对象。

以下内容改编自您提供的答案scale_bar(),并逐字使用了该功能

import cartopy.crs as ccrs
from math import floor
import matplotlib.pyplot as plt
from matplotlib import patheffects


def scale_bar(ax, proj, length, location=(0.5, 0.05), linewidth=3,
              units='km', m_per_unit=1000):
    """
    http://stackoverflow.com/a/35705477/1072212
    (...)
    """
    (...)


fig, axs = plt.subplots(nrows=4, ncols=3, sharex='col', sharey='row',
                        subplot_kw={'projection': ccrs.Mercator()})  # <--- Here is the missing piece
fig.suptitle('Cyprus')
for ax in axs.flatten():
    ax.set_extent([31, 35.5, 34, 36], ccrs.Geodetic())
    ax.coastlines(resolution='10m')
    scale_bar(ax, ccrs.Mercator(), 100)
plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述