You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何移除美国边界外的天气GeoJSON特征或避免生成该类数据

解决美国天气等值线地图的无数据区域阴影问题

问题描述

从现有DataFrame生成美国天气等值线并添加至Dash Mapbox地图时,生成的JSON文件会自动填充无数据区域以补全数组,导致地图上出现不需要的阴影区域。需求是移除天气JSON中与美国州边界(states_20m.geojson)不相交的数据,更优方案是直接在该GeoJSON边界范围内生成天气数据。

解决方案

方案一:直接在州边界内生成网格数据(更优)

从源头控制网格生成范围,只在美国州边界内部创建插值网格,避免生成边界外的无效数据。核心步骤:

  • 读取美国州边界GeoJSON,合并为统一的美国本土多边形边界
  • 生成覆盖原始数据经纬度范围的网格点,筛选出位于州边界内的点
  • 仅对边界内的网格点进行温度插值和平滑处理
  • 基于有效网格生成等值线GeoJSON

方案二:裁剪已生成的等值线GeoJSON

若已生成完整范围的等值线GeoJSON,可通过空间裁剪保留与州边界相交的部分:

  • 将等值线GeoJSON和州边界GeoJSON转换为GeoDataFrame
  • 使用空间交集操作,保留等值线中位于州边界内的部分
  • 将裁剪后的GeoDataFrame转换回JSON格式用于地图展示

修改后的完整代码

import pandas as pd
import plotly.express as px
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
import geojsoncontour
import json
import scipy as sp
import scipy.ndimage
import geopandas as gpd
from shapely.geometry import Point

##### 加载主数据并定义参数#####
path = r'date_data.csv'
df = pd.read_csv(path, index_col=[0])

col = 'Day_Temp'
temp_levels = [-20,0,10,20,32]
levels = temp_levels
unit = 'deg F'
colors = ['#f0ffff','#add8e6','#7bc8f6','#069af6','#0343df']

##### 加载州边界并创建统一的美国本土多边形#####
states_gdf = gpd.read_file('States_20m.geojson')
# 合并所有州的几何形状为一个统一多边形
us_boundary = states_gdf.unary_union

##### 在州边界内生成天气等值线#####
df_copy = df.copy()

x_orig = df_copy.long.values
y_orig = df_copy.lat.values
z_orig = df_copy[col].values

# 生成覆盖原始数据范围的网格点
x_arr = np.linspace(np.min(x_orig), np.max(x_orig), 2000)
y_arr = np.linspace(np.min(y_orig), np.max(y_orig), 2000)
x_mesh, y_mesh = np.meshgrid(x_arr, y_arr)

# 筛选位于美国边界内的网格点
grid_points = [Point(x, y) for x, y in zip(x_mesh.flatten(), y_mesh.flatten())]
grid_gdf = gpd.GeoDataFrame(geometry=grid_points, crs="EPSG:4326")
inside_points = grid_gdf[grid_gdf.geometry.within(us_boundary)]

# 提取有效点的经纬度和对应索引
x_valid = inside_points.geometry.x.values
y_valid = inside_points.geometry.y.values
valid_x_idx = np.array([np.where(x_arr == x)[0][0] for x in x_valid])
valid_y_idx = np.array([np.where(y_arr == y)[0][0] for y in y_valid])

# 对有效点进行温度插值
z_valid = griddata((x_orig, y_orig), z_orig, (x_valid, y_valid), method='linear')

# 重构网格,无效区域填充NaN
z_mesh = np.full(x_mesh.shape, np.nan)
z_mesh[valid_y_idx, valid_x_idx] = z_valid

# 平滑处理,忽略NaN区域
sigma = [5, 5]
z_mesh = sp.ndimage.filters.gaussian_filter(z_mesh, sigma, mode='constant', cval=np.nan)

# 创建等值线(自动忽略NaN区域)
contourf = plt.contourf(x_mesh, y_mesh, z_mesh, levels, alpha=0.9, colors=colors, 
                        linestyles='none')

# 转换为GeoJSON格式
geojson = geojsoncontour.contourf_to_geojson(
    contourf=contourf,
    min_angle_deg=3,
    ndigits=2,
    unit=unit,
    stroke_width=1,
    fill_opacity=0.3)
weather_json = json.loads(geojson)

##### 创建密度热力图示例数据#####
lats = [30,33,35,40]
lons = [-92,-94,-96,-100]
dat = [1000,2000,500,12500]
df_sample = pd.DataFrame(list(zip(lats,lons,dat)), columns = ['lat', 'lon', 'data'])

##### 构建Dash Mapbox地图#####
# 读取州边界JSON用于展示
with open('States_20m.geojson') as g:
    states_json = json.load(g)

fig = px.density_mapbox(
    df_sample,
    lat="lat",
    lon="lon",
    z="data",
    hover_data={
        "lat": True,
        "lon": True,
        "data": True,
    },
    center=dict(lat=38.5, lon=-96),
    zoom=3,
    radius=30,
    opacity=0.4,
    mapbox_style="carto-positron",
    color_continuous_scale=['rgb(0,0,0)',
                             'rgb(19,48,239)',
                             'rgb(115,249,253)',
                             'rgb(114,245,77)',
                             'rgb(254,251,84)',
                             'rgb(235,70,38)'],
    range_color = [0, 2000]
)

# 添加天气等值线图层
fig.update_layout(
    mapbox={
        "layers": [
            {
                "source": f,
                "line": {"width":1},
                "type":"fill",
                "color": f["properties"]["fill"],
                "opacity": 0.7,
            }
            for f in weather_json["features"]
        ],
    }
)

# 添加州边界图层
fig.update_layout(
    mapbox={
        "layers": [
            {
                "source": g,
                "line": {"width":1},
                "type":"line",
                "color": 'black',
                "opacity": 0.5,
            }
            for g in states_json["features"]
        ],
    }
)
    
fig.show()

关键说明

  1. 边界筛选:通过geopandas的空间判断功能,只保留美国本土范围内的网格点,从源头避免无效区域数据生成
  2. 插值与平滑:仅对有效点进行插值,平滑时使用mode='constant'填充NaN,确保无效区域不会被错误填充
  3. 等值线生成:matplotlib.contourf会自动忽略NaN区域,最终生成的等值线仅包含美国本土内的有效天气数据

内容的提问来源于stack exchange,提问作者Jkiefn1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:45:31