接下来,开始记录使用matplotlib这个号称python使用最广泛的图形库,所遇到的种种神坑。
一、 画节点图:
1. 画节点和箭头
查阅api文档,觉得annotate
类封装的不错。
import matplotlib.pyplot as plt
from matplotlib.text import OffsetFrom
bbox_args = dict(boxstyle="round", fc="0.8")
arrow_args = dict(arrowstyle="->")
an1 = plt.annotate('Drag me 1', xy=(.5, .7), xycoords='data',
# xytext=(.5, .7), textcoords='data',
ha="center", va="center",
bbox=bbox_args,
# arrowprops=arrow_args
)
an2 = plt.annotate('Drag me 2', xy=(.5, .5), xycoords=an1,
xytext=(.5, .3), textcoords='axes fraction',
va="center", ha="left",
bbox=bbox_args,
arrowprops=dict(patchB=an1.get_bbox_patch(),
connectionstyle="arc3,rad=0.2",
**arrow_args))
an1.draggable()
an2.draggable()
官方demo不仅实现了两个节点相连,而且可以鼠标拖动,简直完美。

但是问题来了,因为需要画双向箭头,原方法是先画node1,然后画node2+箭头。如果想画node1 指向node2的箭头,由于画node1的时候,node2还未知,因此无法直接画。那么可以在画出node1,node2->node1的时候,再单独画一个箭头使得node1->node2。但是matplotlib的
annotate
类的坐标系规则,搞得晕头转向。搞了好久,结果都是在其他位置又新加了一个node1,指向了node2。直到...
2. 画双向箭头
直到顿悟,可以先单独画两个节点,然后画两个节点之间的箭头。
# -*- coding: UTF-8 -*-
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.lines import Line2D
from matplotlib.patches import Rectangle
fig, ax = plt.subplots(figsize=(10,10))
node_pos = [(1, 0), (0, 1), (2,1), (1,2)]
bbox_args = dict(boxstyle="round", fc="0.8")
arrow_args = dict(arrowstyle="->")
an1 = plt.annotate(s="Test 1\n(node1,node2)\n(node3,node4,node5)\n\n\n", xy=node_pos[0], xycoords="data",
va="center", ha="center",
bbox=dict(boxstyle="round", fc="w", facecolor='green'))
an2 = plt.annotate(s="Test 2\n(node1,node2)", xy=node_pos[1], xycoords="data",
va="center", ha="center",
bbox=dict(boxstyle="round", fc="w", facecolor='green'))
arrow1 = plt.annotate('', xy=(0, 0), xycoords=an1,
xytext=(0, 0), textcoords=an2, # an1 -> an2
size=20, ha="center", va="center",
bbox=bbox_args,
arrowprops=dict(patchA=an2,
patchB=an1,
connectionstyle="arc3,rad=0.2",
#color='red',
#linewidth=5,
**arrow_args))
arrow2 = plt.annotate('', xy=(0, 0), xycoords=an2,
xytext=(0, 0), textcoords=an1, # an1 -> an2
size=20, ha="center", va="center",
bbox=bbox_args,
arrowprops=dict(patchA=an1,
patchB=an2,
connectionstyle="arc3,rad=0.2",
#color='red',
#linewidth=5,
**arrow_args))
这里的坐标系设置以及arrowprops
的设置比较麻烦,搞了好久。主要参数意义参考官方api如下:
patchA, patchB: None, Patch, optional (default: None)
Head and tail patch respectively. matplotlib.patch.Patch instance.
xycoords : str, Artist, Transform, callable or tuple, optional
The coordinate system that xy is given in. The following types of values are supported:

参考:
- Gallery — Matplotlib 3.0.3 documentation
https://matplotlib.org/gallery/index.html - Python数据可视化分析 matplotlib教程_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
https://www.bilibili.com/video/av6989413/
3. 实现鼠标交互
见下一节
网友评论