如何在matplotlib中正确绘制带有旋转矩形的图形棒?
How to draw graph stick with rotated rectangle properly in matplotlib?
我正在研究如何正确绘制以下内容。
假设我有两个节点,即 R^2 中的 2 个点,即 src=(x1,y1) 和 dst=(x2,y2)。
我想在它们之间画一个 edge/line,但是从一个方框开始。
这是我用 Tikz 创建的示例:
src 和 dest 是这些节点的中心。请注意,它们也可以处于不同的高度。问题是当我尝试构建盒子时(使用 patches.Rectangle),我必须旋转它然后它会改变它的大小。
提前致谢
如果您乐于为图形使用填充矩形并将旋转矩形作为棒,则可以用一条简单的线来模拟,该线与图形边缘的散点一样粗。
import matplotlib.pyplot as plt
import numpy as np
def plot_spec_line(src, dst, length=0.3, srctext="v", dsttext="w",
ax=None, color="k", textcolor="k"):
if not ax: ax=plt.gca()
lend=src+(dst-src)*length
ax.plot([src[0],lend[0]], [src[1],lend[1]], lw=24,solid_capstyle="butt", zorder=1, color=color )
ax.plot([src[0],dst[0]], [src[1],dst[1]], lw=2,solid_capstyle="butt", zorder=0, color=color)
ax.scatter([src[0],dst[0]], [src[1],dst[1]], s=24**2, marker="o", lw=2, edgecolors=color, c="w", zorder=2)
ax.text(src[0],src[1], srctext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor)
ax.text(dst[0],dst[1], dsttext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor)
s = np.array([1,1])
d = np.array([3,2])
plot_spec_line(s, d, length=0.3, srctext="v", dsttext="w")
s = np.array([1.5,0.9])
d = np.array([2.8,1.2])
plot_spec_line(s, d, length=0.2, srctext="a", dsttext="b", color="gray")
s = np.array([1,2])
d = np.array([2,1.9])
plot_spec_line(s, d, length=0.7, srctext="X", dsttext="Y", textcolor="limegreen", color="limegreen")
plt.margins(0.2)
plt.show()
要获得一个可以填充或不填充并且更重要的是有边的矩形,可以使用Rectangle
。
您可以 通过设置适当的转换。
然后使用等长宽比的图是有意义的,这样矩形和圆就不会倾斜。
import matplotlib.pyplot as plt
import matplotlib.transforms
import numpy as np
def plot_spec_line(src, dst, length=0.3, radius=0.1, srctext="v", dsttext="w",
ax=None, color="k", textcolor="k", reccolor="w", lw=1 ):
if not ax: ax=plt.gca()
lend=np.sqrt(np.sum(((dst-src)*length)**2))
s = dst-src
angle = np.rad2deg(np.arctan2(s[1],s[0]))
delta = np.array([0,radius])
tr = matplotlib.transforms.Affine2D().rotate_deg_around(src[0],src[1], angle)
t = tr + ax.transData
rec = plt.Rectangle(src-delta, width=lend, height=radius*2, ec=color,facecolor=reccolor, transform=t, linewidth=lw)
ax.add_patch(rec)
ax.plot([src[0],dst[0]], [src[1],dst[1]], lw=lw,solid_capstyle="butt", zorder=0, color=color)
circ1= plt.Circle(src, radius=radius, fill=True, facecolor="w", edgecolor=color, lw=lw)
circ2= plt.Circle(dst, radius=radius, fill=True, facecolor="w", edgecolor=color, lw=lw)
ax.add_patch(circ1)
ax.add_patch(circ2)
ax.text(src[0],src[1], srctext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor)
ax.text(dst[0],dst[1], dsttext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor)
s = np.array([1,1])
d = np.array([3,2])
plot_spec_line(s, d, length=0.3, srctext="v", dsttext="w", radius=0.06,
reccolor="plum", )
s = np.array([1.5,0.9])
d = np.array([2.8,1.2])
plot_spec_line(s, d, length=0.2, srctext="a", dsttext="b", color="gray", lw=2.5)
s = np.array([1,2])
d = np.array([2,1.9])
plot_spec_line(s, d, length=0.7, srctext="X", dsttext="Y", textcolor="limegreen",
reccolor="palegreen", color="limegreen")
plt.margins(0.2)
plt.gca().set_aspect("equal")
plt.show()
我正在研究如何正确绘制以下内容。
假设我有两个节点,即 R^2 中的 2 个点,即 src=(x1,y1) 和 dst=(x2,y2)。
我想在它们之间画一个 edge/line,但是从一个方框开始。
这是我用 Tikz 创建的示例:
src 和 dest 是这些节点的中心。请注意,它们也可以处于不同的高度。问题是当我尝试构建盒子时(使用 patches.Rectangle),我必须旋转它然后它会改变它的大小。
提前致谢
如果您乐于为图形使用填充矩形并将旋转矩形作为棒,则可以用一条简单的线来模拟,该线与图形边缘的散点一样粗。
import matplotlib.pyplot as plt
import numpy as np
def plot_spec_line(src, dst, length=0.3, srctext="v", dsttext="w",
ax=None, color="k", textcolor="k"):
if not ax: ax=plt.gca()
lend=src+(dst-src)*length
ax.plot([src[0],lend[0]], [src[1],lend[1]], lw=24,solid_capstyle="butt", zorder=1, color=color )
ax.plot([src[0],dst[0]], [src[1],dst[1]], lw=2,solid_capstyle="butt", zorder=0, color=color)
ax.scatter([src[0],dst[0]], [src[1],dst[1]], s=24**2, marker="o", lw=2, edgecolors=color, c="w", zorder=2)
ax.text(src[0],src[1], srctext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor)
ax.text(dst[0],dst[1], dsttext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor)
s = np.array([1,1])
d = np.array([3,2])
plot_spec_line(s, d, length=0.3, srctext="v", dsttext="w")
s = np.array([1.5,0.9])
d = np.array([2.8,1.2])
plot_spec_line(s, d, length=0.2, srctext="a", dsttext="b", color="gray")
s = np.array([1,2])
d = np.array([2,1.9])
plot_spec_line(s, d, length=0.7, srctext="X", dsttext="Y", textcolor="limegreen", color="limegreen")
plt.margins(0.2)
plt.show()
要获得一个可以填充或不填充并且更重要的是有边的矩形,可以使用
Rectangle
。
您可以 import matplotlib.pyplot as plt
import matplotlib.transforms
import numpy as np
def plot_spec_line(src, dst, length=0.3, radius=0.1, srctext="v", dsttext="w",
ax=None, color="k", textcolor="k", reccolor="w", lw=1 ):
if not ax: ax=plt.gca()
lend=np.sqrt(np.sum(((dst-src)*length)**2))
s = dst-src
angle = np.rad2deg(np.arctan2(s[1],s[0]))
delta = np.array([0,radius])
tr = matplotlib.transforms.Affine2D().rotate_deg_around(src[0],src[1], angle)
t = tr + ax.transData
rec = plt.Rectangle(src-delta, width=lend, height=radius*2, ec=color,facecolor=reccolor, transform=t, linewidth=lw)
ax.add_patch(rec)
ax.plot([src[0],dst[0]], [src[1],dst[1]], lw=lw,solid_capstyle="butt", zorder=0, color=color)
circ1= plt.Circle(src, radius=radius, fill=True, facecolor="w", edgecolor=color, lw=lw)
circ2= plt.Circle(dst, radius=radius, fill=True, facecolor="w", edgecolor=color, lw=lw)
ax.add_patch(circ1)
ax.add_patch(circ2)
ax.text(src[0],src[1], srctext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor)
ax.text(dst[0],dst[1], dsttext, fontsize=12, ha="center", va="center", zorder=3, color=textcolor)
s = np.array([1,1])
d = np.array([3,2])
plot_spec_line(s, d, length=0.3, srctext="v", dsttext="w", radius=0.06,
reccolor="plum", )
s = np.array([1.5,0.9])
d = np.array([2.8,1.2])
plot_spec_line(s, d, length=0.2, srctext="a", dsttext="b", color="gray", lw=2.5)
s = np.array([1,2])
d = np.array([2,1.9])
plot_spec_line(s, d, length=0.7, srctext="X", dsttext="Y", textcolor="limegreen",
reccolor="palegreen", color="limegreen")
plt.margins(0.2)
plt.gca().set_aspect("equal")
plt.show()