我试图绘制一些点(通过geopandas),发现添加它们会变得越来越慢,直到每个点只需要几百秒甚至更长的时间。这很难用,而且绝对不正常。
我的猜测是,每次将新数据添加到图中时,matplotlib 都会重新绘制所有内容,这由 cProfile 支持:
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
143915 479.433 0.003 479.602 0.003 collections.py:352(draw)
137549 0.238 0.000 478.297 0.003 collections.py:1014(draw)
...
事实证明,寻找解决这个问题的方法很困难。我不知道为什么图书馆会在没有显示任何内容的情况下重绘每次更改。有一些建议使用静态后端并切换到非交互模式。然而,使用相应的配置对性能没有任何影响,因为该库默认使用静态后端和非交互模式。
单步查看源代码,我发现根本没有考虑交互模式,或者可以有条件地拦截对draw()的调用。有没有办法让 matplotlib 推迟绘图,直到所有数据都添加到图中并准备好显示为止?
这是重现该问题的脚本。让我们看看它是否有什么不同。
from pandas import DataFrame
from geopandas import GeoDataFrame, points_from_xy
from matplotlib import pyplot
def plot_point(figure, geodata):
geodata.plot(ax=figure.gca())
figure = pyplot.figure()
data = DataFrame({})
lat = 0
lon = 1
geodata = GeoDataFrame(data, geometry=points_from_xy([lon], [lat]))
for i in range(300):
print(i)
plot_point(figure, geodata)
某些后端可能会产生批量重画的副作用。 Agg 和大多数其他人使用的基本实现会尽可能重绘。 因此可以使用更保守的重绘策略
实现自定义后端并使用它。就我而言,以下内容就足够了:
from matplotlib.backend_bases import _Backend
from matplotlib.backends.backend_agg import FigureCanvasAgg, _BackendAgg
class FigureCanvasAggLazy(FigureCanvasAgg):
def draw_idle(self, *args, **kwargs):
pass # No intermediate draws needed if you are only saving to a file
@_Backend.export
class _BackendAggLazy(_BackendAgg):
FigureCanvas = FigureCanvasAggLazy