Измените проекцию поставщика плиток в боке в EPSG: 3857 («веб-меркатор») на мой источник в EPSG: 4326 - PullRequest
0 голосов
/ 10 января 2020

Я могу использовать Bokeh для построения глифов из географического pandas кадра данных на карте Google с помощью функции gmap () .

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

Это дает мне:

enter image description here

Однако, когда я строю график, используя Carto в качестве поставщика , как описано здесь , в осях возникает ошибка:

    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

Так что он расположен неправильно на карте, где можно увидеть красный круг:

introducir la descripción de la imagen aquí

Похоже, карта в EPSG : 3857 ("web mercator"), в то время как мой источник, вероятно, находится в 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...

1 Ответ

1 голос
/ 27 января 2020

Вы должны перепроектировать свои данные из EPSG: 4326 в EPSG: 3857

Вот решение с некоторыми данными Geo JSON:


# 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)

enter image description here

...