将 EPSG:3857 ("web mercator") 散景中的图块提供者投影更改为 EPSG:4326 中我的来源
Change projection of tile provider in bokeh in EPSG:3857 ("web mercator") to my source's in EPSG:4326
我可以使用 Bokeh 在 Google 地图 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 ("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...
您必须将数据从 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)
我可以使用 Bokeh 在 Google 地图 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 ("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...
您必须将数据从 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)