簡體   English   中英

使用 geopandas 和 matplotlib 繪制地圖

[英]Plotting a map using geopandas and matplotlib

我有來自英國伯明翰的 6 個坐標的小 csv。 我用 Pandas 讀取了 csv,然后將其轉換為 GeoPandas DataFrame,使用 Shapely Points 更改我的緯度和經度列。 我現在正在嘗試繪制我的 GeoDataframe,我能看到的只是點。 我如何同時表示伯明翰地圖? GeoPandas 上的良好文檔來源也將受到強烈贊賞。

from shapely.geometry import Point
import geopandas as gpd
import pandas as pd

df = pd.read_csv('SiteLocation.csv')
df['Coordinates'] = list(zip(df.LONG, df.LAT))
df['Coordinates'] = df['Coordinates'].apply(Point)
# Building the GeoDataframe 
geo_df = gpd.GeoDataFrame(df, geometry='Coordinates')
geo_df.plot()  

GeoPandas 文檔包含一個關於如何向地圖添加背景的示例 ( https://geopandas.readthedocs.io/en/latest/gallery/plotting_basemap_background.html ),下面有更詳細的解釋。


您將不得不處理tiles ,即通過網絡服務器提供的(png)圖像,其URL類似於

http://.../Z/X/Y.png ,其中 Z 是縮放級別, X 和 Y 標識圖塊

geopandas 的文檔展示了如何將圖塊設置為繪圖的背景,獲取正確的圖塊並完成所有其他困難的空間同步工作等......


安裝

假設 GeoPandas 已經安裝,你還需要contextily包。 如果你在 windows 下,你可能想看看如何安裝 Contextily?

用例

創建一個 python 腳本並定義上下文輔助函數

import contextily as ctx def add_basemap(ax, zoom, url='http://tile.stamen.com/terrain/tileZ/tileX/tileY.png'): xmin, xmax, ymin, ymax = ax.axis() basemap, extent = ctx.bounds2img(xmin, ymin, xmax, ymax, zoom=zoom, url=url) ax.imshow(basemap, extent=extent, interpolation='bilinear') # restore original x/y limits ax.axis((xmin, xmax, ymin, ymax))

和玩

import matplotlib.pyplot as plt from shapely.geometry import Point import geopandas as gpd import pandas as pd # Let's define our raw data, whose epsg is 4326 df = pd.DataFrame({ 'LAT' :[-22.266415, -20.684157], 'LONG' :[166.452764, 164.956089], }) df['coords'] = list(zip(df.LONG, df.LAT)) # ... turn them into geodataframe, and convert our # epsg into 3857, since web map tiles are typically # provided as such. geo_df = gpd.GeoDataFrame( df, crs ={'init': 'epsg:4326'}, geometry = df['coords'].apply(Point) ).to_crs(epsg=3857) # ... and make the plot ax = geo_df.plot( figsize= (5, 5), alpha = 1 ) add_basemap(ax, zoom=10) ax.set_axis_off() plt.title('Kaledonia : From Hienghène to Nouméa') plt.show()

在此處輸入圖片說明


注意:您可以使用zoom來為地圖找到合適的分辨率。 例如/即:

在此處輸入圖片說明

...這樣的決議暗中要求更改 x/y 限制。

試試df.unary_union 該函數將點聚合成單個幾何圖形。 Jupyter Notebook可以繪制它

只想添加有關縮放的用例,即根據新的xlimylim坐標更新底圖。 我想出的一個解決方案是:

  • 首先在可以檢測xlim_changedylim_changedax上設置回調
  • 一旦兩者都被檢測為更改,獲取新的plot_area調用ax.get_xlim()ax.get_ylim()
  • 然后清除ax並重新繪制底圖和任何其他數據

顯示首都的世界地圖示例。 當您放大地圖的分辨率時,您會注意到正在更新。

import geopandas as gpd
import matplotlib.pyplot as plt
import contextily as ctx


figsize = (12, 10)
osm_url = 'http://tile.stamen.com/terrain/{z}/{x}/{y}.png'
EPSG_OSM = 3857
EPSG_WGS84 = 4326

class MapTools:
    def __init__(self):
        self.cities = gpd.read_file(
            gpd.datasets.get_path('naturalearth_cities'))
        self.cities.crs = EPSG_WGS84
        self.cities = self.convert_to_osm(self.cities)

        self.fig, self.ax = plt.subplots(nrows=1, ncols=1, figsize=figsize)
        self.callbacks_connect()

        # get extent of the map for all cities
        self.cities.plot(ax=self.ax)
        self.plot_area = self.ax.axis()

    def convert_to_osm(self, df):
        return df.to_crs(epsg=EPSG_OSM)

    def callbacks_connect(self):
        self.zoomcallx = self.ax.callbacks.connect(
            'xlim_changed', self.on_limx_change)
        self.zoomcally = self.ax.callbacks.connect(
            'ylim_changed', self.on_limy_change)

        self.x_called = False
        self.y_called = False

    def callbacks_disconnect(self):
        self.ax.callbacks.disconnect(self.zoomcallx)
        self.ax.callbacks.disconnect(self.zoomcally)

    def on_limx_change(self, _):
        self.x_called = True
        if self.y_called:
            self.on_lim_change()

    def on_limy_change(self, _):
        self.y_called = True
        if self.x_called:
            self.on_lim_change()

    def on_lim_change(self):
        xlim = self.ax.get_xlim()
        ylim = self.ax.get_ylim()
        self.plot_area = (*xlim, *ylim)
        self.blit_map()

    def add_base_map_osm(self):
        if abs(self.plot_area[1] - self.plot_area[0]) < 100:
            zoom = 13

        else:
            zoom = 'auto'

        try:
            basemap, extent = ctx.bounds2img(
                self.plot_area[0], self.plot_area[2],
                self.plot_area[1], self.plot_area[3],
                zoom=zoom,
                url=osm_url,)
            self.ax.imshow(basemap, extent=extent, interpolation='bilinear')

        except Exception as e:
            print(f'unable to load map: {e}')

    def blit_map(self):
        self.ax.cla()
        self.callbacks_disconnect()
        cities = self.cities.cx[
            self.plot_area[0]:self.plot_area[1],
            self.plot_area[2]:self.plot_area[3]]
        cities.plot(ax=self.ax, color='red', markersize=3)

        print('*'*80)
        print(self.plot_area)
        print(f'{len(cities)} cities in plot area')

        self.add_base_map_osm()
        self.callbacks_connect()

    @staticmethod
    def show():
        plt.show()


def main():
    map_tools = MapTools()
    map_tools.show()

if __name__ == '__main__':
    main()

使用以下 pip 安裝在 Linux Python3.8 上運行

affine==2.3.0
attrs==19.3.0
autopep8==1.4.4
Cartopy==0.17.0
certifi==2019.11.28
chardet==3.0.4
Click==7.0
click-plugins==1.1.1
cligj==0.5.0
contextily==1.0rc2
cycler==0.10.0
descartes==1.1.0
Fiona==1.8.11
geographiclib==1.50
geopandas==0.6.2
geopy==1.20.0
idna==2.8
joblib==0.14.0
kiwisolver==1.1.0
matplotlib==3.1.2
mercantile==1.1.2
more-itertools==8.0.0
munch==2.5.0
numpy==1.17.4
packaging==19.2
pandas==0.25.3
Pillow==6.2.1
pluggy==0.13.1
py==1.8.0
pycodestyle==2.5.0
pyparsing==2.4.5
pyproj==2.4.1
pyshp==2.1.0
pytest==5.3.1
python-dateutil==2.8.1
pytz==2019.3
rasterio==1.1.1
requests==2.22.0
Rtree==0.9.1
Shapely==1.6.4.post2
six==1.13.0
snuggs==1.4.7
urllib3==1.25.7
wcwidth==0.1.7

請注意對contextily==1.0rc2特別要求

在 Windows 上,我使用 Conda (P3.7.3) 並且不要忘記設置用戶變量:

GDAL c:\\Users\\<username>\\Anaconda3\\envs\\<your environment>\\Library\\share\\gdal

PROJLIB c:\\Users\\<username>\\Anaconda3\\envs\\<your environment>\\Library\\share

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM