Plotly:如何绘制箭头线(有向图)?

Posted

技术标签:

【中文标题】Plotly:如何绘制箭头线(有向图)?【英文标题】:Plotly: How to plot arrow line (directed graph)? 【发布时间】:2022-01-13 10:10:01 【问题描述】:

我想在节点之间绘制一条箭头线来指示路线的方向。我找不到这样做的内置函数。有什么方法可以完成这项工作吗?

我的代码:

import plotly.graph_objects as go
import plotly.io as pio
import plotly

lon1 = [113.076843, 113.154191, 113.737213, 113.842405, 114.244183 ]
lat1 = [23.10993, 23.218533, 23.047626, 22.987975, 22.601581 ]

lon2 = [113.364738, 113.664108, 113.661705,114.244183]
lat2 = [22.997112, 22.878038, 22.869216, 22.601581]

lon_trip1 = lon1
lat_trip1 = lat1

lon_trip2 = lon2
lat_trip2 = lat2

fig = go.Figure()
fig.add_trace(go.Scattermapbox(
    mode="markers+lines",
    lon=lon_trip1,
    lat=lat_trip1,
    name="trip1", marker='size': 10))

fig.add_trace(
    go.Scattermapbox(
        mode="markers+lines",
        lon=lon_trip2,
        lat=lat_trip2,
        name="trip2",
        marker='size': 10))

fig.update_layout(
    margin='l': 113, 't': 24, 'b': 22, 'r': 115,
    mapbox=dict(style='carto-positron',
                center=go.layout.mapbox.Center(lon=113.664, lat=22.878),
                pitch=0,
                zoom=8)
)


pio.write_image(fig,'C:/Users/Jie/Desktop/plot.png',width=1980, height=1080)
#plotly.offline.plot(fig, filename='C:/Users/user/Desktop/plot' + '.html')
fig.show()

另外,我想在真实世界地图上进一步添加networkx图。是否可以使用 plotly 将地图图层添加到原始 networkx 图中?

完整代码在这里: Plot Networkx graph on a real world map

【问题讨论】:

【参考方案1】: 您可以将 geojson 图层添加到 ma​​pbox 人物 这种方法会在每条线段的中间创建一个标记以显示行进方向 使用高中三角学旋转标记以计算行进角度 具有基于 cmets 的扩展解决方案。现在可以使用place 参数请求放置。图片显示beyond选项包括center、end、beyond

代码


import plotly.graph_objects as go
import plotly.express as px
import plotly.io as pio
import plotly
import math
import shapely.geometry
from shapely.affinity import rotate as R, translate as T

lon1 = [113.076843, 113.154191, 113.737213, 113.842405, 114.244183]
lat1 = [23.10993, 23.218533, 23.047626, 22.987975, 22.601581]

lon2 = [113.364738, 113.664108, 113.661705, 114.244183]
lat2 = [22.997112, 22.878038, 22.869216, 22.601581]

lon_trip1 = lon1
lat_trip1 = lat1

lon_trip2 = lon2
lat_trip2 = lat2

fig = go.Figure()
fig.add_trace(
    go.Scattermapbox(
        mode="markers+lines",
        lon=lon_trip1,
        lat=lat_trip1,
        name="trip1",
        marker="size": 10,
    )
)

fig.add_trace(
    go.Scattermapbox(
        mode="markers+lines",
        lon=lon_trip2,
        lat=lat_trip2,
        name="trip2",
        marker="size": 10,
    )
)

# create a mapbox layer that are arrows that show direction between sequence of lat / lon pairs
def direction(lat1, lon1, marker=None, color="yellow", place="center"):
    # default marker is a left pointing arrow, centred as 0,0
    # it may be necessary to adjust sizing
    if marker is None:
        m = R(shapely.geometry.Polygon([(0, 0), (0, 1), (0.5, 0.5)]), 0)
        m = shapely.affinity.scale(m, xfact=0.05, yfact=0.05)  # size appropriately
        m = T(m, -m.centroid.x, -m.centroid.y)
    else:
        m = marker

    def place_marker(m, x1, x0, y1, y0, place=place):
        theta = math.atan2(x1 - x0, y1 - y0)
        if place == "center":
            p = dict(
                xoff=(y1 - y0) / 2 + y0,
                yoff=(x1 - x0) / 2 + x0,
            )
        elif place == "end":
            p = dict(xoff=y1, yoff=x1)
        elif place == "beyond":
            H = .05
            p = dict(xoff=y1 + math.cos(theta)*H, yoff=x1 + math.sin(theta)*H)
        return T(R(m, theta, use_radians=True), **p)

    return 
        # list of geometries rotated based on direction and centred on line between pairs of points
        "source": shapely.geometry.MultiPolygon(
            [
                place_marker(m, x1, x0, y1, y0)
                for x0, x1, y0, y1 in zip(lat1, lat1[1:], lon1, lon1[1:])
            ]
        ).__geo_interface__,
        "type": "fill",
        "color": color,
        "below":"traces"
    


fig.update_layout(
    margin="l": 113, "t": 24, "b": 22, "r": 115,
    mapbox=dict(
        style="carto-positron",
        center=go.layout.mapbox.Center(lon=113.664, lat=22.878),
        pitch=0,
        zoom=8,
        layers=[
            direction(t.lat, t.lon, marker=None, color=c, place="beyond")
            for t, c in zip(fig.data, px.colors.qualitative.Plotly)
        ],
    ),
)

【讨论】:

感谢您的帮助。是否可以将箭头定位在行尾而不是中间,就像普通的箭头线一样? 是的 - 已更新以提供这种灵活性。 由于某种原因,我的机器无法安装 geopandas。刚找到这个直接画图的方法:community.plotly.com/t/…不知道行不行。 plotly.com/python/map-configuration mapbox 和 geo 使用起来完全不同......你的机器上安装了吗?我已经删除了对 geopandas 的依赖 亲爱的 Rob 非常感谢。这好多了。如何调整箭头以使其不与节点重叠,即(将箭头移到节点前面而不在它上面)?我在节点上显示了数字,如果它们重叠,将被覆盖。

以上是关于Plotly:如何绘制箭头线(有向图)?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 plotly.graph_objects 绘制 3D 线?

如何根据不同的dataFrame部分绘制(plotly.express)多条线

如何在 PyVis 上绘制有向边

如何使用 plotly express(XYXY 格式数据)在同一图表上绘制多条线?

数据结构与算法之图

如何在 R 中的 bar-line Plotly 对象中绘制连续线?