python - 在 matplotlib 中旋转(自定义路径)标记时的尺寸失真
问题描述
我正在使用路径为使用 matplotlib 包的绘图定义自定义标记。此外,我需要能够旋转标记以显示方向。
我按照这个例子,标记旋转。但是,根据角度,标记的大小会发生变化。
这是我正在使用的代码:
import matplotlib.pyplot as plt
from matplotlib.path import Path
from matplotlib import transforms
import matplotlib.patches as patches
fig = plt.figure(figsize=(10, 5))
ax = fig.add_subplot(1, 1, 1)
ax.set_xlim(-10, 10)
ax.set_ylim(-4, 4)
colors = ax.set_prop_cycle(color = ['#993F00', '#0075DC'])
triangle = Path([[-1.,-1.], [1., -1.], [0., 2.], [0.,0.],], [Path.MOVETO, Path.LINETO, Path.LINETO,
Path.CLOSEPOLY,])
print("First Triangle:", triangle, type(triangle))
#patch1 = patches.PathPatch(triangle, facecolor='orange', lw=2)
line1, = ax.plot(0, 0, marker=triangle, markersize=50, alpha=0.5)
R = transforms.Affine2D().rotate_deg(45)
triangle = triangle.transformed(R)
#patch2 = patches.PathPatch(triangle, facecolor='blue', lw=2)
line2, = ax.plot(0, 0, marker=triangle, markersize=50, alpha=0.5)
print("\n transform R", R)
print("\ntriangle after transform", triangle, type(triangle))
#ax.add_patch(patch1)
#ax.add_patch(patch2)
plt.show()
注释掉的行将路径转换为补丁(顺便说一句,如果有人愿意解释补丁是什么与路径,我将不胜感激)以表明底层路径上的转换工作正常,它只是扭曲大小当你绘制它。
这是当前程序的输出:
谢谢!
解决方案
The problem is that the Path
that is taken as input for the marker is normalized to the box (-0.5, 0.5)x(-0.5, 0.5)
. This is often useful because it allows to plug in arbitrarily scaled paths and still get the same sized markers out.
However in this case it will lead to the tips of the triangles to share the same y coodinate (both times y=0.5 in the pre-transformed system).
The only solution I can come up with is to subclass matplotlib.markers.MarkerStyle
and replace the rescaling method with a method that does not change the path.
Now the problem is that plot
does not currently take MarkerStyle
instances as input for its marker
argument. Hence the below solution only works for scatter
.
import matplotlib.pyplot as plt
from matplotlib.path import Path
from matplotlib import transforms
from matplotlib.markers import MarkerStyle
class UnsizedMarker(MarkerStyle):
def _set_custom_marker(self, path):
self._transform = transforms.IdentityTransform()
self._path = path
fig = plt.figure(figsize=(10, 5))
ax = fig.add_subplot(1, 1, 1)
ax.set_xlim(-10, 10)
ax.set_ylim(-4, 4)
colors = ax.set_prop_cycle(color = ['#993F00', '#0075DC'])
triangle1 = Path([[-1.,-1.], [1., -1.], [0., 2.], [0.,0.],],
[Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY,])
m1 = UnsizedMarker(triangle1)
line1 = ax.scatter(0, 0, marker=m1, s=50**2, alpha=0.5)
R = transforms.Affine2D().rotate_deg(45)
triangle2 = triangle1.transformed(R)
m2 = UnsizedMarker(triangle2)
line2 = ax.scatter(0, 0, marker=m2, s=50**2, alpha=0.5)
plt.show()
Unrelated to that, the question also asks for what a Patch
is vs. a Path
.
A Path
is an object that stores vertices and their respective properties. It's main purpose, which makes this more useful than a simple container of two lists or coordinates, is that it has methods to calculate Bezier curves between points. A path by itself can however not be added to a figure.
A Patch
is a matplotlib artist, i.e. an object which can be drawn in a matplotlib figure. Matplotlib provides some useful patches like arrows, rectangles, circles etc. A PathPatch
is such a patch which creates a visualization of a Path
. It's hence the most obvious way to draw a path in a figure.
推荐阅读
- android - 预期配置 ':features:module_astronomie:debugCompileClasspath' 只包含一个文件,但是,它包含多个文件
- c - limits.h 的文本表示
- c++ - std::future:异步单个生产者 + 任意数量的消费者问题
- javascript - 受限路由 JWT
- flutter - Flutter appbar 和 bottomAppbar 在屏幕更改时刷新
- python - SQLAlchemy - 尽管没有插入,但插入重复键
- python - 我如何让我的机器人有一个介于 1 到 100 之间的随机输入
- facebook - 带有 certbot 证书的 Facebook Messenger 应用程序安全错误
- python - 为什么 Twitter API 的身份验证在 X 运行后停止工作
- c# - 重定向到页面 OnActionExecuting 方法 ASP.NET Core 5 MVC