matplotlib - 控制线条集合的大小/大量的线条

Car*_*mer 7 python lines matplotlib

与前一个我的问题类似,我想控制使用matplotlib绘制的线条的capstyle.但是,我有非常多的行,并且除了行集合之外的任何绘图都需要太长时间.是否有任何变通方法以通用方式控制行集合中的行的capstyle(或者,绘制大量Line2D行的超快速方式).例如,我尝试过使用matplotlib rc设置:

import matplotlib as mpl
mpl.rcParams['lines.solid_capstyle'] = 'round'
mpl.rcParams['lines.solid_joinstyle'] = 'round'
Run Code Online (Sandbox Code Playgroud)

但这似乎没有任何影响.来自docstring collections.py:

这些类并不意味着像它们的单个元素一样灵活(例如,您可能无法选择所有的线条样式),但它们对于常见用例来说是快速的(例如,大量的实线选择)

这解释了为什么我似乎无法控制各种参数,但我仍然想要这样做!我已经看过AGG后端的代码了(_backend_agg.cpp不是我真的理解它),看来line_cap和line_join是由gc.cap和控制的gc.join,其中gc来自GCAgg类.有谁知道如何从Python控制这个?我在这里问正确的问题吗?也许这是控制这些参数的更简单方法?

非常感谢任何帮助......我非常渴望得到这个工作,所以即使是疯狂的黑客也欢迎!

谢谢,

卡森

小智 9

更新 @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()
Run Code Online (Sandbox Code Playgroud)

具有平滑线条的 png 输出示例 ,它似乎也可以很好地与 pdf 输出配合使用


ewc*_*wcz 5

由于您在问题中提到您不介意“肮脏”的解决方案,因此一种选择如下。

特定对象的“绘制过程”LineCollection由类( 的基础)中draw定义的方法处理。此方法通过语句创建(在 中定义)的实例。似乎正是这个对象控制了控制(property ) 的属性。因此,您可以创建子类,覆盖该属性,并将一个新方法注入到该类中,以便后续调用返回自定义实例:CollectionLineCollectionGraphicsContextBasebackend_bases.pygc = renderer.new_gc()capstyle_capstyleGraphicsContextBase_capstylenew_gcRendererBasenew_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')
Run Code Online (Sandbox Code Playgroud)

这产生: 在此处输入图片说明