遍历行时如何为 'basemap' 子图设置固定大小?

How to set fixed size for 'basemap' subplot when iterating through rows?

请原谅我,因为这是我第一次参加 Python 'Project'。

快速概述:我正在尝试通过迭代包含活动细分阶段边界的 GeoJSON 文件的 GeoPandas 数据框来生成地图(MatPlotLib 图),以显示每个地段的建设进度细分阶段。我们通常在 GIS 中手动执行此操作,但我认为我会尝试将部分或全部过程自动化。我也尝试在不使用 ESRI 的 python 功能的情况下执行此操作,并且更愿意保持这种方式以确保将来使用的稳定性,因为 ESRI 可以移动很多。

我能够遍历地理数据框并生成缩放到细分阶段边界范围的地图(图形),但是,它正在将背景航空影像底图裁剪到细分的最小绑定框我一直用来设置图形 'zoom' 的阶段。

我打算制作的示例。这是在 ArcGIS Pro 中制作的:

我在 Python 中能做什么:

我无法使底图成为填充标准横向字母页面的恒定大小,同时仍正确放大到细分阶段的范围。我的输出 jpeg 大小正确,但航空图像底图被连续裁剪到细分相边界的范围,在图形周围留下大边界。

import geopandas as gpd # extension to Pandas to work with geodata
import urllib.request, json # download from the web
import os.path # work with the local file system
from shapely.geometry import Point # basic functions to work with vector geometries
import matplotlib as mpl # plotting
from matplotlib import pyplot as plt # some matplotlib convenience functions
import contextily as ctx # simple free basemaps
import csv # read .csv files
import time # time tracking for processes
from matplotlib.patches import Patch # build legend items
from matplotlib.lines import Line2D # build legend items
from matplotlib import figure # change size of figures

start_time = time.time() # Keep track of execution time

# Build Legend Elements
legend_elements = [Patch(facecolor='green', edgecolor='r', alpha=0.5, 
                         label='Completed Lots'),
                   Patch(facecolor='red', edgecolor='black', alpha=0.5, 
                         label='Lots Under Construction'),
                   Patch(facecolor='none', edgecolor='r',
                         label='Subdivision Boundary')]

for index, row in phases.iterrows():
    name = row['NAME']
    print(name)
    lots_complete_select = lots_complete[(lots_complete['SUBDIVISION'] == row['NAME'])]
    print('Completed Lots: ' + str(len(lots_complete_select)))
    lots_uc_select = lots_uc[(lots_uc['SUBDIVISION'] == row['NAME'])]
    print('Lots Under Construction: ' + str(len(lots_uc_select)))
    phase_select = phases[(phases['NAME'] == row['NAME'])]
    lots_select = lots[(lots['SUBDIVISION'] == row['NAME'])]
    print('Lots in subdivision: ' + str(len(lots_select)))
    
    minx, miny, maxx, maxy = (lots_select).total_bounds # Set zoom to lots for area of interest
    
    map_time = time.time()
    print('Building map...')
    fig, ax = plt.subplots() # Create a figure with multiple plots within it
    ax.set_aspect('equal')
    ax.axis('off') # Turn off axes

    ax.set_xlim(minx, maxx) # Apply x zoom level
    ax.set_ylim(miny, maxy) # Apply y zoom level
    
    streets.plot(ax=ax, linewidth=1.2, color='black') # Plot Streets
    
    lots_complete_select.plot(ax=ax, linewidth=0.5, color='green', edgecolor='red', alpha=0.5) # Plot completed lots
    
    lots_uc_select.plot(ax=ax, linewidth=0.5, color='red', edgecolor='black', alpha=0.5) # Plot U.C. lots
    
    lots.plot(ax=ax, linewidth=0.7, color='none', edgecolor='black') # Plot lot lines
    
    phase_select.plot(ax=ax, linewidth=4, color='none', edgecolor='black') # Plot Active Subdivision Phases
    phase_select.plot(ax=ax, linewidth=2, color='none', edgecolor='red') # Plot Active Subdivision Phases
    phase_select.plot(ax=ax, linewidth=1, color='none', edgecolor='white') # Plot Active Subdivision Phases
    
    ctx.add_basemap(ax, crs=streets.crs.to_string(), source=ctx.providers.Esri.WorldImagery, 
                    attribution='City of Pflugerville GIS Services') # Change basemap
        
    ax.set_title((name + ' Residential Construction'), fontsize=10, fontweight ="bold") # Set title
    
    ax.legend(handles=legend_elements, prop={'size': 6}, title='Legend', framealpha=1, fancybox=False, 
              edgecolor='black', loc='upper left') # Add legend
                
    plt.savefig(save_path + name + '.jpg', edgecolor='black', orientation='landscape', papertype='letter', 
                dpi=300) # Save map
        
    print('Map saved.')
    print('Done building map.')
    print("--- %s Seconds ---" % (time.time() - map_time) + '\n')

print('Done configuring maps.')
print("--- %s Minutes ---" % ((time.time() - start_time)/60))

我已经尝试在代码的各个地方使用 figsize=(11, 8.5) 但没有效果。

如有任何意见,我们将不胜感激。如果有什么需要 changed/clarified.

,请告诉我

此外,如果有人熟悉在 Python 中标记线特征(例如街道),是否有一种方法可以在 Python 中以类似于在第一张图片?

如果你想要一个固定的区域,比如说,将边界框扩展 10m,你必须设置 xlimylim extended。您明确指定了边界框。

margin = 10
ax.set_xlim(minx - margin, maxx + margin)
ax.set_ylim(miny - margin, maxy + margin)

此外,要删除绘图周围的白色边界,您可以在保存时将 bbox_inches 设置为 tight

plt.savefig(save_path + name + '.jpg', edgecolor='black', orientation='landscape', papertype='letter', 
                dpi=300, bbox_inches='tight') # Save map