【问题标题】:Change projection of tile provider in bokeh in EPSG:3857 ("web mercator") to my source's in EPSG:4326将 EPSG:3857(“web 墨卡托”)中散景中的瓷砖提供者的投影更改为我在 EPSG:4326 中的来源
【发布时间】:2020-01-10 16:23:49
【问题描述】:

我可以使用 Bokeh 在 Google Map using the gmap() function 上绘制 geopandas 数据框中的字形。

from bokeh.io import output_notebook, show, output_file
from bokeh.plotting import figure
from bokeh.models import GeoJSONDataSource, LinearColorMapper, ColorBar
from bokeh.palettes import brewer#Input GeoJSON source that contains features for plotting.

import json

from bokeh.models import ColumnDataSource, GMapOptions
from bokeh.plotting import gmap

def make_dataset(df, candidate):
    #df_copy = df.copy()
    df_copy = get_df(candidate)
    merged_json = json.loads(df_copy.to_json())#Convert to String like object.
    json_data = json.dumps(merged_json)
    geosource = GeoJSONDataSource(geojson = json_data)
    return geosource

def make_plot(candidate):
    src = make_dataset(df,candidate)
    #Input GeoJSON source that contains features for plotting.    
    p = figure(title = 'Results of candidate X', plot_height = 600 , plot_width = 950, toolbar_location = None)

    map_options = GMapOptions(lat=42, lng=44, map_type="roadmap", zoom=7)

    p = gmap("my-key", map_options, title="Austin")
    p.xgrid.grid_line_color = None
    p.ygrid.grid_line_color = None#Add patch renderer to figure. 
    p.patches('xs','ys', source = src,fill_color = {'field' :'results', 'transform' : color_mapper},
              line_color = 'black', line_width = 0.25, fill_alpha = 1)#Specify figure layout.
    p.add_layout(color_bar, 'below')#Display figure inline in Jupyter Notebook.
    output_notebook()#Display figure.
    return p

它给了我:

但是,当我使用 Carto 作为提供者 as explained here 进行绘图时,轴出现错误:

    tile_provider = get_provider(Vendors.CARTODBPOSITRON)

    # range bounds supplied in web mercator coordinates
    p = figure(x_range=(-2000000, 6000000), y_range=(-1000000, 7000000))#, x_axis_type="mercator", y_axis_type="mercator")
    p.add_tile(tile_provider)
    p.xgrid.grid_line_color = None
    p.ygrid.grid_line_color = None#Add patch renderer to figure. 
    p.patches('xs','ys', source = src,fill_color = {'field' :'results', 'transform' : color_mapper},
              line_color = 'black', line_width = 0.25, fill_alpha = 1)#Specify figure layout.
    p.add_layout(color_bar, 'below')#Display figure inline in Jupyter Notebook.
    output_notebook()#Display figure.
    return p

所以它在地图上的位置不对,可以看到红圈:

看起来地图在 EPSG:3857(“网络墨卡托”)中,而我的来源可能在 EPSG:4326 中。我该怎么做才能正确绘制它?

这是我数据的前几行:

    id  parent_id common_id common_name  has_children  shape_type_id  \
64  70140      69935         3        63-3         False              4   
65  70141      69935         2        63-2         False              4   
66  70142      69935         5        63-5         False              4   
67  70143      69935         6        63-6         False              4   
68  70144      69935         8        63-8         False              4   

   shape_type_name    value color  title_location results  \
64        Precinct  No Data  None  Precinct: 63-3   65.16   
65        Precinct  No Data  None  Precinct: 63-2   57.11   
66        Precinct  No Data  None  Precinct: 63-5   54.33   
67        Precinct  No Data  None  Precinct: 63-6   59.15   
68        Precinct  No Data  None  Precinct: 63-8   61.86   

                                             turnout  \
64  {'pct': 46.38, 'count': 686.0, 'eligible': 1479}   
65   {'pct': 49.62, 'count': 394.0, 'eligible': 794}   
66  {'pct': 58.26, 'count': 624.0, 'eligible': 1071}   
67   {'pct': 57.54, 'count': 492.0, 'eligible': 855}   
68   {'pct': 50.75, 'count': 506.0, 'eligible': 997}   

                                             geometry  
64  POLYGON ((42.18180 42.18530, 42.18135 42.18593...  
65  POLYGON ((42.20938 42.20621, 42.21156 42.20706...  
66  POLYGON ((42.08429 42.20468, 42.08489 42.20464...  
67  POLYGON ((42.16270 42.16510, 42.16661 42.16577...  
68  POLYGON ((42.16270 42.16510, 42.16315 42.16640...

【问题讨论】:

  • 如果您的 CDS 中的坐标不是 web mercator,您必须将它们转换为 web mercator 以便 Bokeh 在这种情况下使用它们。我对此一无所知,但也许像 Cartopy 这样的工具可以进行转换,或者可能有维基百科或其他描述转换的页面..
  • @bigreddot 什么是 CDS?看来我的数据是一个很好的投影,according to wikipedia,是墨卡托。我添加了 geopandas 数据框的摘录
  • 我想我必须不同意。您在上面显示的数据只是普通的纬度/经度值。 Web 墨卡托以北/东的米表示(即像x_rangey_range 值)。对于瓦片供应商地图,仅理解网络墨卡托,您需要将数据转换为网络墨卡托,而不是“纬度/经度”值。

标签: python python-3.x bokeh projection cartodb


【解决方案1】:

您必须将数据从 EPSG:4326 重新投影到 EPSG:3857

这是一个包含一些 GeoJSON 数据的解决方案:


# requirements
# !pip install pandas numpy bokeh geopandas

import pandas as pd
import numpy as np


def lon_to_web_mercator(lon):
    k = 6378137
    return lon * (k * np.pi / 180.0)


def lat_to_web_mercator(lat):
    k = 6378137
    return np.log(np.tan((90 + lat) * np.pi / 360.0)) * k


def wgs84_to_web_mercator(df, lon="lon", lat="lat"):
    """Converts decimal longitude/latitude to Web Mercator format"""
    k = 6378137
    df["x"] = df[lon] * (k * np.pi / 180.0)
    df["y"] = np.log(np.tan((90 + df[lat]) * np.pi / 360.0)) * k
    return df


BerlinWGS84 = [13.08835, 13.76116, 52.33826, 52.67551]

Berlin = x_range, y_range = ((lon_to_web_mercator(BerlinWGS84[0]), lon_to_web_mercator(BerlinWGS84[1])),
                             (lat_to_web_mercator(BerlinWGS84[2]), lat_to_web_mercator(BerlinWGS84[3])))


# plot it
from bokeh.plotting import figure, show, output_notebook
from bokeh.tile_providers import get_provider, Vendors
output_notebook()

tile_provider = get_provider(Vendors.CARTODBPOSITRON)


# range bounds sgupplied in web mercator coordinates
p = figure(x_range=x_range, y_range=y_range,
           x_axis_type="mercator", y_axis_type="mercator")
p.add_tile(tile_provider)

show(p)


# geopandas

import geopandas as gpd
import requests


def remoteGeoJSONToGDF(url, display=False):
    # source: https://medium.com/@maptastik/remote-geojson-to-geodataframe-19c3c1282a64
    """Import remote GeoJSON to a GeoDataFrame
    Keyword arguments:
    url -- URL to GeoJSON resource on web
    display -- Displays geometries upon loading (default: False)
    """
    r = requests.get(url)
    data = r.json()
    gdf = gpd.GeoDataFrame.from_features(data['features'])
    if display:
        gdf.plot()
    return gdf


url = 'https://gist.githubusercontent.com/sabman/96730f5949576e7793a3f79eb390f90c/raw/7ffcf34239175cafcc9a63382e6beacd0cab9fa9/BerlinFeatures.geojson'
gdf = remoteGeoJSONToGDF(url)

gdf.plot()

# make sure initial projection is defined
gdf.crs = {'init': 'epsg:4326'}
gdf_webmerc = gdf.copy()
# reproject
gdf_webmerc = gdf['geometry'].to_crs(epsg=3857)
gdf_webmerc.plot()

from bokeh.models import GeoJSONDataSource
geo_source = GeoJSONDataSource(geojson=gdf_webmerc.to_json())

# let's plot and look
p.circle(x='x', y='y', size=15, alpha=0.7, source=geo_source)
show(p)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-12
    • 2011-11-26
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    相关资源
    最近更新 更多