8000 ENH: make error messages from exceeding agg cell block count clearer · matplotlib/matplotlib@2116856 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2116856

Browse files
tacaswellanntzer
andcommitted
ENH: make error messages from exceeding agg cell block count clearer
The error messages now provide better instruction on how to fix the problem. There are some paths we can not split (one with hatching, fills, or that claim they can not be simplified) so tell user that. If we could have otherwise split up the path if the chunksize is set to less than 100, which disables the feature, ask user to make it bigger or make the path simplification more aggressive. If the chunksize is bigger than the data, ask user to make it smaller or make the path simplification more aggressive. If the chunksize is smaller than the data, but still too big ask user to make it smaller or make the path simplification more aggressive. closes #19325 Co-authored-by: Antony Lee <anntzer.lee@gmail.com>
1 parent 285a01a commit 2116856

File tree

2 files changed

+132
-6
lines changed

2 files changed

+132
-6
lines changed

lib/matplotlib/backends/backend_agg.py

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,62 @@ def draw_path(self, gc, path, transform, rgbFace=None):
152152
try:
153153
self._renderer.draw_path(gc, p, transform, rgbFace)
154154
except OverflowError as err:
155-
raise OverflowError(
156-
"Exceeded cell block limit (set 'agg.path.chunksize' "
157-
"rcparam)") from err
155+
msg = ("Exceeded cell block limit in Agg.\n\n"
156+
"Please reduce "
157+
"the value of rcParams['agg.path.chunksize'] "
158+
f"(currently {nmax}) or increase the "
159+
"path simplification threshold"
160+
"(rcParams['path.simplify_threshold'] = "
161+
f"{mpl.rcParams['path.simplify_threshold']:.2f} "
162+
"by default and path.simplify_threshold "
163+
f"= {path.simplify_threshold:.2f} "
164+
"on the input)."
165+
)
166+
raise OverflowError(msg) from err
158167
else:
159168
try:
160169
self._renderer.draw_path(gc, path, transform, rgbFace)
161170
except OverflowError as err:
162-
raise OverflowError("Exceeded cell block limit (set "
163-
"'agg.path.chunksize' rcparam)") from err
171+
cant_chunk = ''
172+
if rgbFace is not None:
173+
cant_chunk += "- can not split filled path\n"
174+
if gc.get_hatch() is not None:
175+
cant_chunk += "- can not split hatched path\n"
176+
if not path.should_simplify:
177+
cant_chunk += "- path.should_simplify is False\n"
178+
if len(cant_chunk):
179+
msg = ("Exceeded cell block limit in Agg, however "
180+
"for the following reasons:\n\n"
181+
f"{cant_chunk}\n"
182+
"we can not automatically split up this path "
183+
"to draw.\n\n"
184+
"Please manually simplify your path.")
185+
186+
else:
187+
inc_threhold = (
188+
"or increase the "
189+
"path simplification threshold"
190+
"(rcParams['path.simplify_threshold'] = "
191+
f"{mpl.rcParams['path.simplify_threshold']} "
192+
"by default and path.simplify_threshold "
193+
f"= {path.simplify_threshold} "
194+
"on the input)."
195+
)
196+
if nmax > 100:
197+
msg = ("Exceeded cell block limit in Agg. Please "
198+
"reduce the value of "
199+
"rcParams['agg.path.chunksize'] "
200+
f"(currently {nmax}) "
201+
+ inc_threhold
202+
)
203+
else:
204+
msg = ("Exceeded cell block limit in Agg. Please set "
205+
"the value of rcParams['agg.path.chunksize'], "
206+
f"(currently {nmax}) to be greater than 100 "
207+
+ inc_threhold
208+
)
209+
210+
raise OverflowError(msg) from err
164211

165212
def draw_mathtext(self, gc, x, y, s, prop, angle):
166213
"""Draw mathtext using :mod:`matplotlib.mathtext`."""

lib/matplotlib/tests/test_agg.py

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88

99
from matplotlib import (
1010
collections, path, pyplot as plt, transforms as mtransforms, rcParams)
11-
from matplotlib.image import imread
11+
from matplotlib.backends.backend_agg import RendererAgg
1212
from matplotlib.figure import Figure
13+
from matplotlib.image import imread
14+
from matplotlib.path import Path
1315
from matplotlib.testing.decorators import image_comparison
16+
from matplotlib.transforms import IdentityTransform
1417

1518

1619
def test_repeated_save_with_alpha():
@@ -251,3 +254,79 @@ def test_draw_path_collection_error_handling():
251254
ax.scatter([1], [1]).set_paths(path.Path([(0, 1), (2, 3)]))
252255
with pytest.raises(TypeError):
253256
fig.canvas.draw()
257+
258+
259+
@pytest.fixture
260+
def chunk_limit_setup():
261+
N = 100_000
262+
dpi = 500
263+
w = 5*dpi
264+
h = 6*dpi
265+
266+
# just fit in the width
267+
x = np.linspace(0, w, N)
268+
# and go top-to-bottom
269+
y = np.ones(N) * h
270+
y[::2] = 0
271+
272+
idt = IdentityTransform()
273+
# make a renderer
274+
ra = RendererAgg(w, h, dpi)
275+
# setup the minimal gc to draw a line
276+
gc = ra.new_gc()
277+
gc.set_linewidth(1)
278+
gc.set_foreground('r')
279+
# make a Path
280+
p = Path(np.vstack((x, y)).T)
281+
# effectively disable path simplification (but leaving it "on")
282+
p.simplify_threshold = 0
283+
284+
return ra, gc, p, idt
285+
286+
287+
def test_chunksize_hatch_fail(chunk_limit_setup):
288+
ra, gc, p, idt = chunk_limit_setup
289+
290+
gc.set_hatch('/')
291+
292+
with pytest.raises(OverflowError, match='hatched path'):
293+
ra.draw_path(gc, p, idt)
294+
295+
296+
def test_chunksize_rgbFace_fail(chunk_limit_setup):
297+
ra, gc, p, idt = chunk_limit_setup
298+
299+
with pytest.raises(OverflowError, match='filled path'):
300+
ra.draw_path(gc, p, idt, (1, 0, 0))
301+
302+
303+
def test_chunksize_no_simplify_fail(chunk_limit_setup):
304+
ra, gc, p, idt = chunk_limit_setup
305+
p.should_simplify = False
306+
with pytest.raises(OverflowError, match="should_simplify is False"):
307+
ra.draw_path(gc, p, idt)
308+
309+
310+
def test_chunksize_zero(chunk_limit_setup):
311+
ra, gc, p, idt = chunk_limit_setup
312+
# set to zero to disable, currently defaults to 0, but lets be sure
313+
rcParams['agg.path.chunksize'] = 0
314+
with pytest.raises(OverflowError, match='Please set'):
315+
ra.draw_path(gc, p, idt)
316+
317+
318+
def test_chunksize_too_big_to_chunk(chunk_limit_setup):
319+
ra, gc, p, idt = chunk_limit_setup
320+
# set big enough that we do not try to chunk
321+
rcParams['agg.path.chunksize'] = 1_000_000
322+
with pytest.raises(OverflowError, match='Please reduce'):
323+
ra.draw_path(gc, p, idt)
324+
325+
326+
def test_chunksize_toobig_chunks(chunk_limit_setup):
327+
ra, gc, p, idt = chunk_limit_setup
328+
# small enough we will try to chunk, but big enough we will fail
329+
# to render
330+
rcParams['agg.path.chunksize'] = 90_000
331+
with pytest.raises(OverflowError, match='Please reduce'):
332+
ra.draw_path(gc, p, idt)

0 commit comments

Comments
 (0)
0