与我的previous question类似,我想控制使用matplotlib绘制的线条的capstyle。但是,我有非常多的行,并且除了行集合之外的任何绘图都需要太长时间。是否有任何变通方法可以通用方式控制行集合中的行的capstyle(或者,绘制大量Line2D
行的超快速方式)。例如,我尝试过使用matplotlib rc设置:
import matplotlib as mpl
mpl.rcParams['lines.solid_capstyle'] = 'round'
mpl.rcParams['lines.solid_joinstyle'] = 'round'
但这似乎没有任何影响。来自collections.py
的文档字符串:
这些类并不意味着像它们的单个元素一样灵活(例如,您可能无法选择所有的线条样式),但它们对于常见用例来说是快速的(例如,大量的实线标记) )
哪个解释为什么我似乎无法控制各种参数,但我仍然想要这样做!我已经看了AGG后端的代码(_backend_agg.cpp
:不是我真的理解它),看来line_cap和line_join由gc.cap
和gc.join
控制,其中gc来自GCAgg
类。有谁知道如何从Python控制这个?我在这里问正确的问题吗?也许这是控制这些参数的更简单方法吗?
非常感谢任何帮助......我非常渴望得到这个工作,所以即使是疯狂的黑客也欢迎!
谢谢,
卡森
答案 0 :(得分:3)
由于您在提问中提到您不介意“脏”解决方案,因此一个选项如下。
特定LineCollection
的“绘制过程”由draw
类(Collection
的基础)中定义的LineCollection
方法处理。此方法通过语句GraphicsContextBase
创建backend_bases.py
的实例(在gc = renderer.new_gc()
中定义)。似乎正是这个对象控制着控制capstyle
(属性_capstyle
)的属性。因此,可以将GraphicsContextBase
子类化,覆盖_capstyle
属性,并将新的new_gc
方法注入RendererBase
类,以便后续调用new_gc
返回自定义实例:
借用@florisvb(假设Python3)的答案借用示例:
#!/usr/bin/env python
import types
import numpy as np
from matplotlib.backend_bases import GraphicsContextBase, RendererBase
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
class GC(GraphicsContextBase):
def __init__(self):
super().__init__()
self._capstyle = 'round'
def custom_new_gc(self):
return GC()
RendererBase.new_gc = types.MethodType(custom_new_gc, RendererBase)
#----------------------------------------------------------------------
np.random.seed(42)
x = np.random.random(10)
y = np.random.random(10)
points = np.array([x, y]).T.reshape((-1, 1, 2))
segments = np.concatenate([points[:-1], points[1:]], axis=1)
fig = plt.figure()
ax = fig.add_subplot(111)
linewidth = 10
lc = LineCollection(segments, linewidths=linewidth)
ax.add_collection(lc)
fig.savefig('fig.png')
答案 1 :(得分:2)
更新@ewcz 的答案,因为该线程仍然出现在搜索结果中。
现在可以使用 path_effects
而不是定义自己的 GraphicsContextBase。
例如
import numpy as np
import matplotlib.patheffects as path_effects
from matplotlib.collections import LineCollection
np.random.seed(42)
x = np.random.random(10)
y = np.random.random(10)
points = np.array([x, y]).T.reshape((-1, 1, 2))
segments = np.concatenate([points[:-1], points[1:]], axis=1)
fig = plt.figure()
ax = fig.add_subplot(111)
linewidth = 10
### Stroke redraws the segment passing kwargs down to the GC renderer
lc = LineCollection(segments, linewidths=linewidth,
path_effects=[path_effects.Stroke(capstyle="round")])
ax.add_collection(lc)
fig.show()
Example png output with smooth lines 它似乎也适用于 pdf 输出
答案 2 :(得分:1)
我正在努力解决同样的问题。我最终在我的线集合上绘制了一个散点图。它并不完美,但它可能适用于您的应用程序。有一些细微之处 - 下面是一个有效的例子。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x = np.random.random(10)
y = np.random.random(10)
z = np.arange(0,10)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
fig = plt.figure()
ax = fig.add_subplot(111)
linewidth = 10
cmap = plt.get_cmap('jet')
norm = plt.Normalize(np.min(z), np.max(z))
color = cmap(norm(z))
lc = LineCollection(segments, linewidths=linewidth, cmap=cmap, norm=norm)
lc.set_array(z)
lc.set_zorder(z.tolist())
ax.add_collection(lc)
ax.scatter(x,y,color=color,s=linewidth**2,edgecolor='none', zorder=(z+2).tolist())