在 Plotly Density_Mapbox 上添加 GeoJSON 轮廓作为图层
Adding GeoJSON contours as layers on Plotly Density_Mapbox
我想在 plotly
density_mapbox
地图上添加天气等高线,但不确定必要的步骤。
首先,我创建了一个 matplotlib
等高线图来可视化数据。
然后,我使用 geojsoncontour
从上述 matplotlib
等高线图创建了一个 geojson
文件。
我现在想做的是在与 density_mapbox
.
相同的地图中绘制等高线
geojson
和包含数据的 .csv 文件可以找到 here.
关于 .csv 文件,'Rand_Data' 是进入 density_mapbox
绘图的数据,'Rain_in' 是用于生成轮廓的数据。
link 到数据:https://github.com/jkiefn1/Contours_and_plotly
正在创建 Mapbox:
# Create the static figure
fig = px.density_mapbox(df
,lat='lat'
,lon='long'
,z='Rand_Data'
,hover_data={
'lat':True # remove from hover data
,'long':True # remove from hover data
,col:True
}
,center=dict(lat=38.5, lon=-96)
,zoom=3
,radius=30
,opacity=0.5
,mapbox_style='open-street-map'
,color_continuous_scale='inferno'
)
fig.show()
创建 matplotlib 等高线图并生成 geojson 文件
# Load in the DataFrame
path = r'/Users/joe_kiefner/Desktop/Sample_Data.csv'
df = pd.read_csv(path, index_col=[0])
data = []
# Define rain levels to be contours in geojson
levels = [0.25,0.5,1,2.5,5,10]
colors = ['royalblue', 'cyan', 'lime', 'yellow', 'red']
vmin = 0
vmax = 1
cm = branca.colormap.LinearColormap(colors, vmin=vmin, vmax=vmax).to_step(len(levels))
x_orig = (df.long.values.tolist())
y_orig = (df.lat.values.tolist())
z_orig = np.asarray(df['Rain_in'].values.tolist())
x_arr = np.linspace(np.min(x_orig), np.max(x_orig), 500)
y_arr = np.linspace(np.min(y_orig), np.max(y_orig), 500)
x_mesh, y_mesh = np.meshgrid(x_arr, y_arr)
xscale = df.long.max() - df.long.min()
yscale = df.lat.max() - df.lat.min()
scale = np.array([xscale, yscale])
z_mesh = griddata((x_orig, y_orig), z_orig, (x_mesh, y_mesh), method='linear')
sigma = [5, 5]
z_mesh = sp.ndimage.filters.gaussian_filter(z_mesh, sigma, mode='nearest')
# Create the contour
contourf = plt.contourf(x_mesh, y_mesh, z_mesh, levels, alpha=0.9, colors=colors,
linestyles='none', vmin=vmin, vmax=vmax)
# Convert matplotlib contourf to geojson
geojson = geojsoncontour.contourf_to_geojson(
contourf=contourf,
min_angle_deg=3,
ndigits=2,
unit='in',
stroke_width=1,
fill_opacity=0.3)
d = json.loads(geojson)
len_features=len(d['features'])
if not data:
data.append(d)
else:
for i in range(len(d['features'])):
data[0]['features'].append(d['features'][i])
with open('/path/to/Sample.geojson', 'w') as f:
dump(geojson, f)
- 有两个核心选项
- 添加为图层https://plotly.com/python/mapbox-layers/
- 添加为等值线迹 https://plotly.com/python/mapbox-county-choropleth/
- layers-legend - 与 layers 选项相同,通过向图 [=38= 添加额外的痕迹来创建图例]
- 这两个选项都在下面编码。更改
OPTION
的值以在它们之间切换
- layers 表示没有图例或悬停文本
- choropleth 这些都存在,移动 colorbar 所以它不与图例重叠。更多美化图例和悬停文本需要...
import json, requests
import pandas as pd
import geopandas as gpd
import plotly.express as px
txt = requests.get(
"https://raw.githubusercontent.com/jkiefn1/Contours_and_plotly/main/Sample.geojson"
).text
js = json.loads(json.loads(txt))
df = pd.read_csv(
"https://raw.githubusercontent.com/jkiefn1/Contours_and_plotly/main/Sample_Data.csv"
)
col = "Rand_Data"
fig = px.density_mapbox(
df,
lat="lat",
lon="long",
z="Rand_Data",
hover_data={
"lat": True, # remove from hover data
"long": True, # remove from hover data
col: True,
},
center=dict(lat=38.5, lon=-96),
zoom=3,
radius=30,
opacity=0.5,
mapbox_style="open-street-map",
color_continuous_scale="inferno",
)
OPTION = "layers-legend"
if OPTION[0:6]=="layers":
fig.update_traces(legendgroup="weather").update_layout(
mapbox={
"layers": [
{
"source": f,
"type": "fill",
"color": f["properties"]["fill"],
"opacity": f["properties"]["fill-opacity"],
}
for f in js["features"]
],
}
)
if OPTION=="layers-legend":
# create a dummy figure to create a legend for the geojson
dfl = pd.DataFrame(js["features"])
dfl = pd.merge(
dfl["properties"].apply(pd.Series),
dfl["geometry"].apply(pd.Series)["coordinates"].apply(len).rename("len"),
left_index=True,
right_index=True,
)
figl = px.bar(
dfl.loc[dfl["len"].gt(0)],
color="title",
x="fill",
y="fill-opacity",
color_discrete_map={cm[0]: cm[1] for cm in dfl.loc[:, ["title", "fill"]].values},
).update_traces(visible="legendonly")
fig.add_traces(figl.data).update_layout(
xaxis={"visible": False}, yaxis={"visible": False}, coloraxis={"colorbar":{"y":.25}}
)
else:
gdf = gpd.GeoDataFrame.from_features(js)
gdf = gdf.loc[~gdf.geometry.is_empty]
cmap = {
list(d.values())[0]: list(d.values())[1]
for d in gdf.loc[:, ["title", "fill"]].apply(dict, axis=1).tolist()
}
fig2 = px.choropleth_mapbox(
gdf,
geojson=gdf.geometry,
locations=gdf.index,
color="title",
color_discrete_map=cmap,
opacity=.3
)
fig.add_traces(fig2.data).update_layout(coloraxis={"colorbar":{"y":.25}})
fig
层数
痕迹
我想在 plotly
density_mapbox
地图上添加天气等高线,但不确定必要的步骤。
首先,我创建了一个 matplotlib
等高线图来可视化数据。
然后,我使用 geojsoncontour
从上述 matplotlib
等高线图创建了一个 geojson
文件。
我现在想做的是在与 density_mapbox
.
geojson
和包含数据的 .csv 文件可以找到 here.
关于 .csv 文件,'Rand_Data' 是进入 density_mapbox
绘图的数据,'Rain_in' 是用于生成轮廓的数据。
link 到数据:https://github.com/jkiefn1/Contours_and_plotly
正在创建 Mapbox:
# Create the static figure
fig = px.density_mapbox(df
,lat='lat'
,lon='long'
,z='Rand_Data'
,hover_data={
'lat':True # remove from hover data
,'long':True # remove from hover data
,col:True
}
,center=dict(lat=38.5, lon=-96)
,zoom=3
,radius=30
,opacity=0.5
,mapbox_style='open-street-map'
,color_continuous_scale='inferno'
)
fig.show()
创建 matplotlib 等高线图并生成 geojson 文件
# Load in the DataFrame
path = r'/Users/joe_kiefner/Desktop/Sample_Data.csv'
df = pd.read_csv(path, index_col=[0])
data = []
# Define rain levels to be contours in geojson
levels = [0.25,0.5,1,2.5,5,10]
colors = ['royalblue', 'cyan', 'lime', 'yellow', 'red']
vmin = 0
vmax = 1
cm = branca.colormap.LinearColormap(colors, vmin=vmin, vmax=vmax).to_step(len(levels))
x_orig = (df.long.values.tolist())
y_orig = (df.lat.values.tolist())
z_orig = np.asarray(df['Rain_in'].values.tolist())
x_arr = np.linspace(np.min(x_orig), np.max(x_orig), 500)
y_arr = np.linspace(np.min(y_orig), np.max(y_orig), 500)
x_mesh, y_mesh = np.meshgrid(x_arr, y_arr)
xscale = df.long.max() - df.long.min()
yscale = df.lat.max() - df.lat.min()
scale = np.array([xscale, yscale])
z_mesh = griddata((x_orig, y_orig), z_orig, (x_mesh, y_mesh), method='linear')
sigma = [5, 5]
z_mesh = sp.ndimage.filters.gaussian_filter(z_mesh, sigma, mode='nearest')
# Create the contour
contourf = plt.contourf(x_mesh, y_mesh, z_mesh, levels, alpha=0.9, colors=colors,
linestyles='none', vmin=vmin, vmax=vmax)
# Convert matplotlib contourf to geojson
geojson = geojsoncontour.contourf_to_geojson(
contourf=contourf,
min_angle_deg=3,
ndigits=2,
unit='in',
stroke_width=1,
fill_opacity=0.3)
d = json.loads(geojson)
len_features=len(d['features'])
if not data:
data.append(d)
else:
for i in range(len(d['features'])):
data[0]['features'].append(d['features'][i])
with open('/path/to/Sample.geojson', 'w') as f:
dump(geojson, f)
- 有两个核心选项
- 添加为图层https://plotly.com/python/mapbox-layers/
- 添加为等值线迹 https://plotly.com/python/mapbox-county-choropleth/
- layers-legend - 与 layers 选项相同,通过向图 [=38= 添加额外的痕迹来创建图例]
- 这两个选项都在下面编码。更改
OPTION
的值以在它们之间切换 - layers 表示没有图例或悬停文本
- choropleth 这些都存在,移动 colorbar 所以它不与图例重叠。更多美化图例和悬停文本需要...
import json, requests
import pandas as pd
import geopandas as gpd
import plotly.express as px
txt = requests.get(
"https://raw.githubusercontent.com/jkiefn1/Contours_and_plotly/main/Sample.geojson"
).text
js = json.loads(json.loads(txt))
df = pd.read_csv(
"https://raw.githubusercontent.com/jkiefn1/Contours_and_plotly/main/Sample_Data.csv"
)
col = "Rand_Data"
fig = px.density_mapbox(
df,
lat="lat",
lon="long",
z="Rand_Data",
hover_data={
"lat": True, # remove from hover data
"long": True, # remove from hover data
col: True,
},
center=dict(lat=38.5, lon=-96),
zoom=3,
radius=30,
opacity=0.5,
mapbox_style="open-street-map",
color_continuous_scale="inferno",
)
OPTION = "layers-legend"
if OPTION[0:6]=="layers":
fig.update_traces(legendgroup="weather").update_layout(
mapbox={
"layers": [
{
"source": f,
"type": "fill",
"color": f["properties"]["fill"],
"opacity": f["properties"]["fill-opacity"],
}
for f in js["features"]
],
}
)
if OPTION=="layers-legend":
# create a dummy figure to create a legend for the geojson
dfl = pd.DataFrame(js["features"])
dfl = pd.merge(
dfl["properties"].apply(pd.Series),
dfl["geometry"].apply(pd.Series)["coordinates"].apply(len).rename("len"),
left_index=True,
right_index=True,
)
figl = px.bar(
dfl.loc[dfl["len"].gt(0)],
color="title",
x="fill",
y="fill-opacity",
color_discrete_map={cm[0]: cm[1] for cm in dfl.loc[:, ["title", "fill"]].values},
).update_traces(visible="legendonly")
fig.add_traces(figl.data).update_layout(
xaxis={"visible": False}, yaxis={"visible": False}, coloraxis={"colorbar":{"y":.25}}
)
else:
gdf = gpd.GeoDataFrame.from_features(js)
gdf = gdf.loc[~gdf.geometry.is_empty]
cmap = {
list(d.values())[0]: list(d.values())[1]
for d in gdf.loc[:, ["title", "fill"]].apply(dict, axis=1).tolist()
}
fig2 = px.choropleth_mapbox(
gdf,
geojson=gdf.geometry,
locations=gdf.index,
color="title",
color_discrete_map=cmap,
opacity=.3
)
fig.add_traces(fig2.data).update_layout(coloraxis={"colorbar":{"y":.25}})
fig