我正在尝试在卫星视图地图上以可视化方式显示风向和强度。使用Python,但是我想这个问题不是平台特定的。
下面是Matlab过去制作的风图的屏幕截图:
这有可能在情节上吗?我试图研究注释,但无法在地图上使用它们。
我尝试了以下操作,但添加注释后,地图停止工作:
import plotly.graph_objects as go
fig = go.Figure(go.Scattermapbox(
mode = "lines",
lon = [10, 20],
lat = [10,20],
marker = {'size': 10}))
fig.add_annotation(
x = [10,],
y = [10],
xref = "x", yref = "y",
axref = "x", ayref = "y",
ax = [20],
ay = [20],
text = "",
showarrow = True
)
fig.update_layout(
margin ={'l':0,'t':0,'b':0,'r':0},
mapbox = {
'center': {'lon': 10, 'lat': 10},
'style': "stamen-terrain",
'center': {'lon': 10, 'lat': 10},
'zoom': 3})
fig.show()
答案 0 :(得分:1)
还要在可绘制的Mapbox中绘制箭头。
我正在使用与@guidout答案类似的方法来手动构建箭头,但使用的是单个geojson图层(这避免了使用多条迹线的性能问题)。
我正在使用geojson MultiLineString层。
geojson MultiLineString具有以下格式(来自Wikipedia):
{
"type": "MultiLineString",
"coordinates": [
[[10, 10], [20, 20], [10, 40]], <-- each of this can be used to draw an arrow
[[40, 40], [30, 30], [40, 20], [30, 10]]
]
}
代码:
function rotate(a, theta) {
return [a[0]*Math.cos(theta) - a[1]*Math.sin(theta), a[0]*Math.sin(theta) + a[1]*Math.cos(theta)];
}
function createArrow(a, b) {
// a: source point
// b: destination point
var angle = Math.atan2(a[1]-b[1], a[0]-b[0]);
var v = [b[0]-a[0], b[1]-a[1]] // get direction vector
var m = Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2)) // module
var u = [v[0]/m, v[1]/m] // get unitary vector in the direction
var k = 0.2 // how far to place the arrow end
var newb = [b[0]-u[0]*k, b[1]-u[1]*k] // place the arrow end a bit before the destination
var s1 = rotate([0.02, 0.02], angle) // "sides" of the arrow. Applied to a base vector in left direction <--, and rotated to match the correct angle
var s2 = rotate([0.02, -0.02], angle)
return [a, newb, [newb[0]+s1[0], newb[1]+s1[1]], newb, [newb[0]+s2[0], newb[1]+s2[1]]]
}
//...
var arrows = sourceDestinationPairs.map(x => createArrow(x[0], x[1]));
var mapboxLayer = {
'sourcetype': 'geojson',
'source': {
"type": "MultiLineString",
"coordinates": arrows
},
'below': '', 'type': 'line',
'color': 'grey', 'opacity': 1,
'line': {'width': 2}
}
layout.mapbox.layers.push(mapboxLayer)
// ...
Plotly.plot('mapDiv', data, layout)
缺点:
答案 1 :(得分:0)
据我所知,我在地图上找不到实现此目标的箭头示例。我在这个方向上经验不足。我将以无法控制它为例进行说明。
import plotly.graph_objects as go
fig = go.Figure(go.Scattermapbox(
mode = "lines",
lon = [10, 20],
lat = [10,20],
marker = {'size': 10}))
fig.add_annotation(
x = 10,
y = 10,
xref = "x",
yref = "y",
axref = "x",
ayref = "y",
ax = 3,
ay = 3,
text = "sample arrow",
font=dict(
family='Courier New, monospace',
size=20,
color='red'
),
showarrow = True,
align='center',
arrowhead=2,
arrowsize=2,
arrowwidth=2,
arrowcolor='blue'
)
fig.update_layout(
margin ={'l':0,'t':0,'b':0,'r':0},
mapbox = {
'center': {'lon': 10, 'lat': 10},
'style': "stamen-terrain",
'center': {'lon': 10, 'lat': 10},
'zoom': 3})
fig.show()
答案 2 :(得分:0)
不可能将箭头绘制为散点图框上的注释并保持箭头的3D位置。
我所做的是为每个箭头生成2条迹线。第一条迹线由起点和终点两点组成,而第二条迹线由[终点,tipA,tipB,终点)和填充的“自身”这四个点组成。
windField.windvectorList.forEach((item) =>{
this.TrackMapPlot_data.push({
type: "scattermapbox",
mode: "lines",
lat: [item.startlat, item.stoplat],
lon: [item.startlon, item.stoplon],
line: { color: "rgb(48,151,255)", width: 3}
});
this.TrackMapPlot_data.push({
type: "scattermapbox",
mode: "lines",
fill:"toself",
fillcolor: "rgb(48,151,255)",
lat: [item.stoplat, item.tipalat, item.tipblat, item.stoplat ],
lon: [item.stoplon, item.tipalon, item.tipblon, item.stoplon],
line: { color: "rgb(48,151,255)", width: 3}
})
});
要提出tipA和tipB并让箭头尖端也按我定义的箭头长度进行缩放:
def AddArrowTipsToWindVectors(wind_table: pd.DataFrame(), scale: float) -> pd.DataFrame():
#wind_table = wind_table.loc[:100, :]
# Make wind vectors
arrow_angle = 20
arrow_length = 0.2
wind_vectors = list()
wind_table['WindArrowTipALat'] = 0
wind_table['WindArrowTipALon'] = 0
wind_table['WindArrowTipBLat'] = 0
wind_table['WindArrowTipBLon'] = 0
for index, wind_row in wind_table.iterrows():
arrow_delta = math.asin(arrow_length*math.sin(math.radians(arrow_angle/2))/(1-arrow_length))
arrow_dist = wind_row['WindSpeed']*scale*(1-arrow_length)/math.cos(arrow_delta)
arrow_tip_A = GetTerminalLocFromDistAndHeading(wind_row['StationLat'], wind_row['StationLon'], arrow_dist, wind_row['WindDirection'] + math.degrees(arrow_delta))
wind_table.loc[index, 'WindArrowTipALat'] = arrow_tip_A[0]
wind_table.loc[index, 'WindArrowTipALon'] = arrow_tip_A[1]
arrow_tip_B = GetTerminalLocFromDistAndHeading(wind_row['StationLat'], wind_row['StationLon'], arrow_dist, wind_row['WindDirection'] - math.degrees(arrow_delta))
wind_table.loc[index, 'WindArrowTipBLat'] = arrow_tip_B[0]
wind_table.loc[index, 'WindArrowTipBLon'] = arrow_tip_B[1]
这不是一个很好的解决方案,但可以。 但是,plotly和mapbox存在一个大问题。不幸的是,当添加多个跟踪时,一切变得极其缓慢,如以下github链接所指出: https://github.com/plotly/plotly.js/issues/3227 https://github.com/plotly/plotly.js/issues/1535
问题不是单个轨迹中的点数,而是轨迹数。 这使我的应用程序无法使用。
AGM解决方案
角度Google Maps看起来效果很好。 https://angular-maps.com/guides/getting-started/ 这是显示我如何使用的代码段:
<agm-map
[clickableIcons]="false"
[disableDefaultUI]="true"
[latitude]="trackDetails.mapboxlat"
[longitude]="trackDetails.mapboxlon"
[mapTypeId]="'satellite'"
[zoom]="trackDetails.mapboxzoomsmall"
(mapClick)="onChoseLocation($event)"
>
<agm-polyline *ngFor="let windvector of windField.windvectorList"
[visible]="true" [strokeWeight]="2" [strokeColor]="'rgb(43,42,255)'">
<agm-polyline-point
[latitude]="windvector.startlat"
[longitude]="windvector.startlon">
</agm-polyline-point>
<agm-polyline-point
[latitude]="windvector.stoplat"
[longitude]="windvector.stoplon">
</agm-polyline-point>
<agm-icon-sequence
[fixedRotation]="false"
[scale]="1.5"
[path]="'FORWARD_OPEN_ARROW'"
[fillColor]="'rgb(43,42,255)'">
</agm-icon-sequence>
</agm-polyline>
</agm-map>