为了账号安全,请及时绑定邮箱和手机立即绑定

周末就能动手的五个开源GIS项目助力城市规划

如果你是城市规划师,正在找开源GIS工具来改进你城市规划的工作流程吗?或者你是一名GIS爱好者,对城市发展有兴趣并且愿意做出贡献?

如果你和其他很多规划师一样,你可能考虑过创建工具来自动化常见城市分析任务,但不知道从哪里开始。

那么,这里有5个项目们,包括从初学者到高级的开源GIS项目,你试着建一建。这些项目使用免费、开源的工具,并能为你提供解决实际城市规划问题的实用方法。

记得:最棒的项目是解决真正的难题。这些项目里,每个都应对实际的挑战,城市规划师遇到的挑战,既实用又有教育意义。

1) 步行评分计算器(入门级)

想知道不同社区的步行方便程度如何吗?这个工具会根据配套设施的便利性、道路连接性以及人行设施来评估步行得分。

你需要的工具:
- OSMnx(用于街道网络)
- GeoPandas(用于空间)
- OpenStreetMap 数据(免费获取的地理数据)

    import osmnx as ox  
    import geopandas as gpd  
    import pandas as pd  
    from shapely.geometry import Point, box  
    def calculate_walkability_score(location, radius=1000):  
     """  
     计算某个地点基于以下因素的步行评分:  
     - 步行距离内的设施数量  
     - 街道网络密度  
     - 交叉点密度  
     """  
     # 下载街道网络并获取设施  
     G = ox.graph_from_point(location, dist=radius, network_type='walk')  

     # 从 OSM 获取设施  
     amenities = ox.geometries_from_point(  
     location,   
     tags={'amenity': True},  
     dist=radius  
     )  

     # 计算指标  
     area = radius * radius * 3.14159 / 1000000 # km²  

     # 街道密度 (km/km²)  
     edge_lengths = ox.utils_graph.get_route_edge_attributes(G, 'length')  
     street_density = sum(edge_lengths) / 1000 / area  

     # 交叉点密度  
     nodes, edges = ox.graph_to_gdfs(G)  
     intersection_density = len(nodes[nodes.street_count > 1]) / area  

     # 设施评分  
     amenity_score = len(amenities) / area  

     # 计算最终评分(加权平均)  
     walkability_score = (  
     0.4 * normalize(street_density) +  
     0.4 * normalize(intersection_density) +  
     0.2 * normalize(amenity_score)  
     )  

     return walkability_score, {  
     'street_density': street_density,  
     'intersection_density': intersection_density,  
     'amenities_per_sqkm': amenity_score  
     }  
    def normalize(value, min_val=0, max_val=100):  
     """  
     将值归一化到 0-100 的区间内  
     """  
     return min(100, max(0, (value - min_val) / (max_val - min_val) * 100))

这个工具提供了一个衡量邻里步行便利性的量化指标。你可以添加更多因素,比如人行道、街道宽度或当地的人口特征,来让工具更全面。

2) 绿色空间分析工具(初级)

城市生活的质量至关重要。此工具分析各社区公园和绿地的分布及可达性。

所需工具或库:
- GeoPandas(用于空间分析的库)
- OpenStreetMap 地图数据
- Folium(用于创建交互式地图的库)

    import geopandas as gpd  
    import folium  
    from shapely.ops import unary_union  
    import numpy as np  
    def analyze_green_spaces(city_boundary, population_data):  
     """  
     分析绿地的分布和可达性  
     """  
     # 从OSM加载绿地数据  
     green_spaces = ox.geometries_from_place(  
     city_boundary,  
     tags={'leisure': ['park', 'garden'], 'landuse': ['grass', 'forest']}  
     )  

     # 为每个社区计算指标  
     results = []  
     for idx, neighborhood in population_data.iterrows():  
     # 计算绿地面积  
     neighborhood_green = gpd.clip(green_spaces, neighborhood.geometry)  
     green_area = neighborhood_green.area.sum()  

     # 计算可达性(即人口中在绿地400米范围内的比例)  
     buffer = neighborhood_green.geometry.buffer(400)  
     accessible_area = unary_union(buffer)  
     accessibility = (  
     neighborhood.geometry.intersection(accessible_area).area /  
     neighborhood.geometry.area  
     ) * 100  

     results.append({  
     'neighborhood': neighborhood.name,  
     'green_space_area': green_area,  
     'green_space_per_capita': green_area / neighborhood.population,  
     'accessibility_score': accessibility  
     })  

     return pd.DataFrame(results)  
    def create_green_space_map(analysis_results, city_geometry):  
     """创建绿地分析的交互式地图"""  
     m = folium.Map(location=city_geometry.centroid.coords[0], zoom_start=12)  

     # 添加分段填充图层  
     folium.Choropleth(  
     data=analysis_results,  
     columns=['neighborhood', 'green_space_per_capita'],  
     key_on='feature.properties.neighborhood',  
     fill_color='YlOrRd',  
     legend_name='人均绿地面积(平方米)'  
     ).add_to(m)  

     return m

3) 城市增长模式分析工具(中等)

使用历史上的卫星照片和建筑图,跟踪并可视化您的城市是怎样随着时间变化的。

准备工作:
- Rasterio(用于处理卫星图像)
- GeoPandas
- Microsoft Building Footprints(微软建筑轮廓数据,开源数据)
- Scikit-learn(用于数据分析中的模式识别)

    import rasterio  
    import geopandas as gpd  
    from sklearn.cluster import DBSCAN  
    import numpy as np  
    from datetime import datetime  
    def analyze_urban_growth(building_footprints, years_range):  
     """  
     根据建筑的建造日期来分析城市增长模式。  
     """  
     # 划分分析需要的时间段  
     gdf = gpd.read_file(building_footprints)  

     gdf['period'] = pd.cut(gdf['year_built'],   
     bins=years_range,  
     labels=[f'{y}-{y+10}' for y in years_range[:-1]])  

     # 分析增长模式  
     results = []  
     for period in gdf['period'].unique():  
     period_buildings = gdf[gdf['period'] == period]  

     # 计算密度聚类  
     coords = np.vstack(period_buildings.geometry.apply(  
     lambda x: [x.centroid.x, x.centroid.y]  
     ))  

     clustering = DBSCAN(eps=0.003, min_samples=5).fit(coords)  

     # 计算相关指标  
     results.append({  
     'period': period,  
     'new_buildings': len(period_buildings),  
     'total_area': period_buildings.geometry.area.sum(),  
     'growth_clusters': len(set(clustering.labels_)) - 1, # 将噪声排除在外  
     'avg_density': len(period_buildings) / period_buildings.unary_union.area  
     })  

     return pd.DataFrame(results)  
    def visualize_growth_patterns(analysis_results, city_boundary):  
     """创建城市增长的时间可视化图。"""  
     fig, ax = plt.subplots(figsize=(15, 10))  

     for idx, period in enumerate(analysis_results['period']):  
     period_buildings = analysis_results[analysis_results['period'] == period]  
     period_buildings.plot(  
     ax=ax,  
     color=plt.cm.viridis(idx / len(analysis_results)),  
     alpha=0.5,  
     label=period  
     )  

     plt.legend(title='时期:')  
     plt.title('随时间变化的城市增长模式')  
     return fig

4) 中级交通网络分析工具

所需工具:
- NetworkX(用于网络分析)
- OSMnx(用于交通网络数据)
- GTFS数据(公共交通时刻表信息)

    import networkx as nx  
    import osmnx as ox  
    import partridge as ptg  
    import shapely.ops as ops  
    def analyze_transit_coverage(city_boundary, gtfs_path):  
     """  
     分析城市公共交通覆盖和服务盲区  
     """  
     # 加载GTFS数据  
     feed = ptg.load_feed(gtfs_path)  

     # 创建公交网络  
     stops = feed.stops  
     stops_gdf = gpd.GeoDataFrame(  
     stops,  
     geometry=gpd.points_from_xy(stops.stop_lon, stops.stop_lat)  
     )  

     # 计算服务范围(500米步行距离)  
     stop_buffers = stops_gdf.geometry.buffer(500)  
     service_area = ops.unary_union(stop_buffers)  

     # 确定未覆盖的区域  
     city_area = gpd.read_file(city_boundary)  
     gaps = city_area.geometry.difference(service_area)  

     # 计算交通可达性  
     population_data = gpd.read_file('population_data.geojson')  

     results = {  
     'total_stops': len(stops),  
     '覆盖率百分比': (service_area.area / city_area.geometry.area) * 100,  
     '人口覆盖': calculate_population_served(  
     population_data,   
     service_area  
     ),  
     '服务盲区列表': gpd.GeoDataFrame(geometry=[gaps])  
     }  

     return results  
    def calculate_service_frequency(feed, stop_id):  
     """计算每个站点的平均服务频率"""  
     stop_times = feed.stop_times[feed.stop_times.stop_id == stop_id]  
     trips_per_day = len(stop_times.trip_id.unique())  
     return trips_per_day
5) 高级城市热岛现象分析器(高级版)

利用卫星图像、土地使用数据资料和温度测量来识别并分析城市热岛现象。

你需要的东西:
— Rasterio(用于卫星图像)
— Earth Engine Python API(用于Landsat数据)
— GeoPandas
— Scikit-learn(进行空间分析)

    import ee  
    import rasterio  
    import numpy as np  
    from sklearn.ensemble import RandomForestRegressor  
    def calculate_temperature_stats(landsat_collection, boundary):,  
     """计算来自Landsat影像的温度统计"""  
     # 转换为摄氏度并计算统计量  
     temp_image = landsat_collection.mean() \  
     .multiply(0.00341802).add(149.0) \  
     .subtract(273.15) # 转换为摄氏度  

     return temp_image.reduceRegion(  
     reducer=ee.Reducer.percentile([10, 50, 90]),  
     geometry=boundary,  
     scale=30  
     )  
    def identify_heat_hotspots(temp_data, threshold):,  
     """确定显著更高温度的区域"""  
     # 使用局部Moran's I来识别集群  
     weights = pysal.lib.weights.Queen.from_dataframe(temp_data)  
     moran_loc = pysal.explore.esda.moran.Moran_Local(  
     temp_data.temperature,  
     weights  
     )  

     # 确定显著热点  
     hotspots = temp_data[  
     (moran_loc.p_sim < 0.05) &   
     (temp_data.temperature > temp_data.temperature.quantile(threshold))  
     ]  

     return hotspots  
    def analyze_heat_islands(city_boundary, date_range):  
     """使用Landsat数据和土地利用数据来分析城市热岛效应"""  
     # 初始化地球引擎服务  
     ee.Initialize()  

     # 加载Landsat地表温度数据  
     landsat = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') \  
     .filterBounds(city_boundary) \  
     .filterDate(date_range[0], date_range[1]) \  
     .select('ST_B10') # 地表温度波段  

     # 加载土地利用数据  
     landuse = gpd.read_file('landuse.geojson')  

     # 计算温度统计  
     temp_stats = calculate_temperature_stats(landsat, city_boundary)  

     # 分析土地利用与温度的关系  
     heat_analysis = analyze_heat_patterns(temp_stats, landuse)  

     # 识别热点区域  
     hotspots = identify_heat_hotspots(temp_stats, threshold=0.9)  

     return {  
     'temperature_stats': temp_stats,  
     'heat_analysis': heat_analysis,  
     'hotspots': hotspots  
     }  
    def calculate_temperature_stats(landsat_collection, boundary):  
     """计算来自Landsat影像的温度统计"""  
     # 转换为摄氏度并计算统计量  
     temp_image = landsat_collection.mean() \  
     .multiply(0.00341802).add(149.0) \  
     .subtract(273.15) # 转换为摄氏度  

     return temp_image.reduceRegion(  
     reducer=ee.Reducer.percentile([10, 50, 90]),  
     geometry=boundary,  
     scale=30  
     )  
    def identify_heat_hotspots(temp_data, threshold):  
     """确定显著更高温度的区域"""  
     # 使用局部Moran's I来识别集群  
     weights = pysal.lib.weights.Queen.from_dataframe(temp_data)  
     moran_loc = pysal.explore.esda.moran.Moran_Local(  
     temp_data.temperature,  
     weights  
     )  

     # 确定显著热点  
     hotspots = temp_data[  
     (moran_loc.p_sim < 0.05) &   
     (temp_data.temperature > temp_data.temperature.quantile(threshold))  
     ]  

     return hotspots

每个项目都使用开源工具和公开数据,非常适合周末做的小项目,这些项目都可逐渐发展成为大型项目。它们解决真实的都市规划问题,同时教会大家实用的地理信息系统 (GIS) 和编程技巧。

想把这些项目继续推进下去吗?可以考虑以下几点:
- 用Streamlit或Dash添加交互式的网页界面
- 引入更多数据来源,如人口普查数据或本地调查
- 使用Python的报表库自动生成报告
- 添加机器学习模型来进行预测分析
- 把你的改进贡献给开源社区吧!

记住,这些项目只是一个开始。你可以根据你城市的具体需求和难题来调整它们。编程愉快!

免费关注我,获取新文章更新通知。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消