遍历行时如何为“底图"子图设置固定大小? [英] How to set fixed size for 'basemap' subplot when iterating through rows?

查看:79
本文介绍了遍历行时如何为“底图"子图设置固定大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请原谅我,因为这是我第一次参加Python项目".

Please forgive me as this is my first go at a Python 'Project'.

快速概述:我正在尝试通过迭代包含活动细分阶段边界的GeoJSON文件的GeoPandas数据框来生成地图(MatPlotLib图),以显示每个细分阶段中各个地块的建设进度.通常,我们通常是在GIS中手动完成此操作,但我认为在自动化部分或全部过程方面会有所作为.我还尝试在不使用ESRI的python功能的情况下执行此操作,并且由于ESRI可以在相当大的范围内移动,因此更希望保持这种方式以确保将来使用的稳定性.

A quick overview: I am trying to produce maps (MatPlotLib figures) by iterating through a GeoPandas dataframe of a GeoJSON file containing the boundaries of active subdivision phases in order to show the progress of construction of the individual lots in each subdivision phase. We normally did this manually in GIS, but I figured I'd take a stab at automating some, or all, of the process. I am also attempting to do this without using ESRI's python functionality and would prefer to keep it that way for stability for future use as ESRI can move around quite a bit.

我能够遍历地理数据框并生成缩放到细分阶段边界范围的地图(图),但是,它将背景航拍图像底图裁剪到细分阶段的最小装订框我一直在设置数字的缩放".

I am able to iterate through the geodataframe and produce a map (figure) that is zoomed to the extent of the subdivision phase boundary, however, it is clipping the background aerial imagery basemap to the minimum binding box of the subdivision phase that I have been using to set the 'zoom' of the figure.

我要生产的产品的例子.这是在ArcGIS Pro中完成的:

Example of what I am aiming to produce. This was made in ArcGIS Pro:

我可以用Python制作的内容:"

What I am able to make in Python:

我无法将底图设置为可填充标准横向字母页面的恒定大小,而仍无法正确放大到细分阶段的范围.我的输出jpeg大小正确,但是航空影像底图被连续裁剪到细分相边界的程度,在图形周围留有大边框.

I am unable to get the basemap to be a constant size that fills a standard landscape letter page whilst still being correctly zoomed in to the extent of the subdivision phase. My output jpeg is sized correctly, but the aerial imagery basemap is continuously croppped to the extent of the subdivision phase boundary leaving large borders around the figure.

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)无效.

I have tried using figsize=(11, 8.5) in various places around the code to no effect.

任何输入将不胜感激.请让我知道是否需要更改/澄清.

Any input would be greatly appreciated. Please let me know if there is anything that needs to be changed/clarified.

如果有人熟悉Python中的街道等标签线特征,还有没有一种方法可以像在第一张图片中看到的那样在Python中标记街道?

Also, if anyone is familiar with labelling line features, such as streets, in Python, is there a way of labelling streets in Python in a manner similar to what is seen in the first image?

推荐答案

如果要有一个固定的区域(例如,将边界框扩展10m),则必须设置 xlim ylim 扩展.您要同时明确指定边界框.

If you want to have a fixed area which, say, extends the bounding box by 10m, you have to set xlim and ylim extended. You are explicitly specifying both to bounding box.

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

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

Furthermore, to remove white boundaries around your plot, you can set bbox_inches to tight in saving.

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

这篇关于遍历行时如何为“底图"子图设置固定大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆