10000 RuntimeError when saving PDFs via parallel processes (not threads!) · Issue #13723 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content
RuntimeError when saving PDFs via parallel processes (not threads!) #13723
Closed
@marcotama

Description

@marcotama

Bug report

Bug summary

When storing multiple PDFs using parallel processes (not threads!) a RuntimeError occurs. This happens regardless of the library used for parallelization, i.e. concurrent, multiprocessing or joblib. The error is either RuntimeError: In set_text: could not load glyph (generated by the code below) or RuntimeError: In load_char: Could not load charcode (which I can't seem to reproduce yet, but maybe you have a better idea of the link behind the two).

Code for reproduction

from multiprocessing import Pool
from joblib import Parallel, delayed
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed

def model_handler(n):
    import matplotlib.pyplot as plt
    fig_out = plt.figure(figsize=(1, 1))
    axes = fig_out.add_subplot(1,1,1)
    axes.scatter(range(1000), range(1000))
    fig_out.savefig('dummyfig{}.pdf'.format(n), format='pdf')
    plt.close()
    return n

n_jobs = 2
n_workers = 2

print('List comprehension (serial)...                           ', end='')
try:
    [model_handler(j) for j in range(n_jobs)]
    print('SUCCESS')
except:
    print('FAILURE')

print('Parallel processes via multiprocessing package...        ', end='')
try:
    Pool(processes=n_workers).map(model_handler, range(n_jobs))
    print('SUCCESS')
except:
    print('FAILURE')

print('Parallel processes via joblib package (loky backend)...  ', end='')
try:
    Parallel(n_jobs=n_workers, backend='loky')(delayed(model_handler)(i) for i in range(n_jobs))
    print('SUCCESS')
except:
    print('FAILURE')

print('Parallel threads via joblib package...                   ', end='')
try:
    Parallel(n_jobs=n_workers, backend='threading')(delayed(model_handler)(i) for i in range(n_jobs))
    print('SUCCESS')
except:
    print('FAILURE')

print('Parallel processes via joblib package...                 ', end='')
try:
    Parallel(n_jobs=n_workers, backend='multiprocessing')(delayed(model_handler)(i) for i in range(n_jobs))
    print('SUCCESS')
except:
    print('FAILURE')

print('Parallel threads via concurrent.futures package...       ', end='')
with ThreadPoolExecutor(max_workers=n_workers) as pool:
    futures = [pool.submit(model_handler, i) for i in range(n_jobs)]
    exceptions = [x.exception() for x in as_completed(futures)]
if all(exception is None for exception in exceptions):
    print('SUCCESS')
else:
    print('FAILURE')

print('Parallel processes via concurrent.futures package...     ', end='')
with ProcessPoolExecutor(max_workers=n_workers) as pool:
    futures = [pool.submit(model_handler, i) for i in range(n_jobs)]
    exceptions = [x.exception() for x in as_completed(futures)]
if all(exception is None for exception in exceptions):
    print('SUCCESS')
else:
    print('FAILURE')

Actual outcome

List comprehension (serial)...                           SUCCESS
Parallel processes via multiprocessing package...        FAILURE
Parallel processes via joblib package (loky backend)...  SUCCESS
Parallel threads via joblib package...                   SUCCESS
Parallel processes via joblib package...                 FAILURE
Parallel threads via concurrent.futures package...       SUCCESS
Parallel processes via concurrent.futures package...     FAILURE

Traceback

"""
Traceback (most recent call last):
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/multiprocessing/pool.py", line 121, in worker
    result = (True, func(*args, **kwds))
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/multiprocessing/pool.py", line 44, in mapstar
    return list(map(*args))
  File "<ipython-input-16-c44ed7855af1>", line 13, in model_handler
    fig_out.savefig('dummyfig{}.pdf'.format(n), format='pdf')
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/figure.py", line 2035, in savefig
    self.canvas.print_figure(fname, **kwargs)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/backend_bases.py", line 2263, in print_figure
    **kwargs)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/backends/backend_pdf.py", line 2586, in print_pdf
    self.figure.draw(renderer)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/figure.py", line 1475, in draw
    renderer, self, artists, self.suppressComposite)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/image.py", line 141, in _draw_list_compositing_images
    a.draw(renderer)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 2607, in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/image.py", line 141, in _draw_list_compositing_images
    a.draw(renderer)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/axis.py", line 1192, in draw
    renderer)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/axis.py", line 1130, in _get_tick_bboxes
    extent = tick.label1.get_window_extent(renderer)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/text.py", line 922, in get_window_extent
    bbox, info, descent = self._get_layout(self._renderer)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/text.py", line 300, in _get_layout
    ismath=False)
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/matplotlib/backends/backend_pdf.py", line 2164, in get_text_width_height_descent
    font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
RuntimeError: In set_text: could not load glyph
"""
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/site-packages/IPython/core/interactiveshell.py", line 3267, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-18-426f53ccd8fe>", line 3, in <module>
    Pool(processes=n_workers).map(model_handler, range(n_jobs))
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/multiprocessing/pool.py", line 268, in map
    return self._map_async(func, iterable, mapstar, chunksize).get()
  File "/Users/marcotama/anaconda3/envs/py37/lib/python3.7/multiprocessing/pool.py", line 657, in get
    raise self._value
RuntimeError: In set_text: could not load glyph

Expected outcome

The code should simply succeed. Notice that the loky backend of joblib succeeds even though it uses parallel processes. I am not sure why this is.

Matplotlib version

  • Operating system: MacOS High Sierra (10.13.6)
  • Matplotlib version: 2.2.2
  • Matplotlib backend (print(matplotlib.get_backend())): module://backend_interagg
  • Python version: 3.7.2
  • Jupyter version (if applicable): N/A
  • Other libraries: joblib==0.12.2

All packages were installed via pip inside a conda environment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0