Repository: pandas-dev/pandas

Issue:
Compatibility with matplotlib 2.2

Three tests started failing on the python 2.7 build: https://travis-ci.org/pandas-dev/pandas/jobs/350035880, all related to FontManager and `functools_lru_cache`. 
See full output below:

<details>

```
=================================== FAILURES ===================================
________________________ TestDataFramePlots.test_table _________________________
[gw0] linux2 -- Python 2.7.14 /home/travis/miniconda3/envs/pandas/bin/python
self = <pandas.tests.plotting.test_frame.TestDataFramePlots object at 0x7f131e75a810>
    def test_table(self):
        df = DataFrame(np.random.rand(10, 3),
                       index=list(string.ascii_letters[:10]))
>       _check_plot_works(df.plot, table=True)
pandas/tests/plotting/test_frame.py:2467: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
pandas/tests/plotting/common.py:558: in _check_plot_works
    plt.savefig(path)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/pyplot.py:710: in savefig
    res = fig.savefig(*args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/figure.py:2035: in savefig
    self.canvas.print_figure(fname, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backend_bases.py:2261: in print_figure
    **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:511: in print_png
    FigureCanvasAgg.draw(self)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:431: in draw
    self.figure.draw(self.renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/artist.py:55: in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/figure.py:1475: in draw
    renderer, self, artists, self.suppressComposite)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/image.py:141: in _draw_list_compositing_images
    a.draw(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/artist.py:55: in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/axes/_base.py:2607: in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/image.py:141: in _draw_list_compositing_images
    a.draw(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/artist.py:55: in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:350: in draw
    self._update_positions(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:536: in _update_positions
    self._auto_set_font_size(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:494: in _auto_set_font_size
    size = cell.auto_set_font_size(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:95: in auto_set_font_size
    required = self.get_required_width(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:144: in get_required_width
    l, b, w, h = self.get_text_bounds(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:138: in get_text_bounds
    bbox = self._text.get_window_extent(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/text.py:922: in get_window_extent
    bbox, info, descent = self._get_layout(self._renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/text.py:300: in _get_layout
    ismath=False)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:239: in get_text_width_height_descent
    font = self._get_agg_font(prop)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:273: in _get_agg_font
    fname = findfont(prop)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/font_manager.py:1475: in findfont
    font = fontManager.findfont(prop, **kw)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/font_manager.py:1290: in findfont
    rc_params)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
args = (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f51cfd0>, 'ttf', None, True, True, ...)
kwds = {}
key = (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f51cfd0>, 'ttf', None, True, True, ...)
link = None
root = [[[[[[[...], [...], (...), '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/...e/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'], None, None]
result = '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'
oldroot = [[[[[[[...], [...], (...), '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/..., ...), '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf']
oldkey = (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f51cc10>, 'ttf', None, True, True, ...)
    def wrapper(*args, **kwds):
        # size limited caching that tracks accesses by recency
        key = make_key(args, kwds, typed) if kwds or typed else args
        with lock:
            link = cache_get(key)
            if link is not None:
                # record recent use of the key by moving it to the front of the list
                root, = nonlocal_root
                link_prev, link_next, key, result = link
                link_prev[NEXT] = link_next
                link_next[PREV] = link_prev
                last = root[PREV]
                last[NEXT] = root[PREV] = link
                link[PREV] = last
                link[NEXT] = root
                stats[HITS] += 1
                return result
        result = user_function(*args, **kwds)
        with lock:
            root, = nonlocal_root
            if key in cache:
                # getting here means that this same key was added to the
                # cache while the lock was released.  since the link
                # update is already done, we need only return the
                # computed result and update the count of misses.
                pass
            elif _len(cache) >= maxsize:
                # use the old root to store the new key and result
                oldroot = root
                oldroot[KEY] = key
                oldroot[RESULT] = result
                # empty the oldest link and make it the new root
                root = nonlocal_root[0] = oldroot[NEXT]
                oldkey = root[KEY]
                root[KEY] = root[RESULT] = None
                # now update the cache dictionary for the new links
>               del cache[oldkey]
E               KeyError: (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f51cc10>, 'ttf', None, True, True, (('DejaVu Serif', 'Bitstream Vera Serif', 'Computer Modern Roman', 'New Century Schoolbook', 'Century Schoolbook L', 'Utopia', 'ITC Bookman', 'Bookman', 'Nimbus Roman No9 L', 'Times New Roman', 'Times', 'Palatino', 'Charter', 'serif'), ('DejaVu Sans', 'Bitstream Vera Sans', 'Computer Modern Sans Serif', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid', 'Arial', 'Helvetica', 'Avant Garde', 'sans-serif'), ('Apple Chancery', 'Textile', 'Zapf Chancery', 'Sand', 'Script MT', 'Felipa', 'cursive'), ('Comic Sans MS', 'Chicago', 'Charcoal', 'ImpactWestern', 'Humor Sans', 'xkcd', 'fantasy'), ('DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Computer Modern Typewriter', 'Andale Mono', 'Nimbus Mono L', 'Courier New', 'Courier', 'Fixed', 'Terminal', 'monospace')))
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/backports/functools_lru_cache.py:156: KeyError
_________________ TestDataFramePlots.test_scatter_matrix_axis __________________
[gw0] linux2 -- Python 2.7.14 /home/travis/miniconda3/envs/pandas/bin/python
self = <pandas.tests.plotting.test_misc.TestDataFramePlots object at 0x7f1322b25a10>
    @td.skip_if_no_scipy
    def test_scatter_matrix_axis(self):
        scatter_matrix = plotting.scatter_matrix
    
        with tm.RNGContext(42):
            df = DataFrame(randn(100, 3))
    
        # we are plotting multiples on a sub-plot
        with tm.assert_produces_warning(UserWarning):
            axes = _check_plot_works(scatter_matrix, filterwarnings='always',
>                                    frame=df, range_padding=.1)
pandas/tests/plotting/test_misc.py:65: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
pandas/tests/plotting/common.py:558: in _check_plot_works
    plt.savefig(path)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/pyplot.py:710: in savefig
    res = fig.savefig(*args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/figure.py:2035: in savefig
    self.canvas.print_figure(fname, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backend_bases.py:2261: in print_figure
    **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:511: in print_png
    FigureCanvasAgg.draw(self)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:431: in draw
    self.figure.draw(self.renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/artist.py:55: in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/figure.py:1475: in draw
    renderer, self, artists, self.suppressComposite)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/image.py:141: in _draw_list_compositing_images
    a.draw(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/artist.py:55: in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/axes/_base.py:2607: in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/image.py:141: in _draw_list_compositing_images
    a.draw(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/artist.py:55: in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/axis.py:1189: in draw
    renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/axis.py:1127: in _get_tick_bboxes
    extent = tick.label1.get_window_extent(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/text.py:922: in get_window_extent
    bbox, info, descent = self._get_layout(self._renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/text.py:300: in _get_layout
    ismath=False)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:239: in get_text_width_height_descent
    font = self._get_agg_font(prop)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:273: in _get_agg_font
    fname = findfont(prop)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/font_manager.py:1475: in findfont
    font = fontManager.findfont(prop, **kw)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/font_manager.py:1290: in findfont
    rc_params)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
args = (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f1300fb5dd0>, 'ttf', None, True, True, ...)
kwds = {}
key = (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f1300fb5dd0>, 'ttf', None, True, True, ...)
link = None
root = [[[[[[[...], [...], (...), '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/...e/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'], None, None]
result = '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'
oldroot = [[[[[[[...], [...], (...), '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/..., ...), '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf']
oldkey = (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f51cc10>, 'ttf', None, True, True, ...)
    def wrapper(*args, **kwds):
        # size limited caching that tracks accesses by recency
        key = make_key(args, kwds, typed) if kwds or typed else args
        with lock:
            link = cache_get(key)
            if link is not None:
                # record recent use of the key by moving it to the front of the list
                root, = nonlocal_root
                link_prev, link_next, key, result = link
                link_prev[NEXT] = link_next
                link_next[PREV] = link_prev
                last = root[PREV]
                last[NEXT] = root[PREV] = link
                link[PREV] = last
                link[NEXT] = root
                stats[HITS] += 1
                return result
        result = user_function(*args, **kwds)
        with lock:
            root, = nonlocal_root
            if key in cache:
                # getting here means that this same key was added to the
                # cache while the lock was released.  since the link
                # update is already done, we need only return the
                # computed result and update the count of misses.
                pass
            elif _len(cache) >= maxsize:
                # use the old root to store the new key and result
                oldroot = root
                oldroot[KEY] = key
                oldroot[RESULT] = result
                # empty the oldest link and make it the new root
                root = nonlocal_root[0] = oldroot[NEXT]
                oldkey = root[KEY]
                root[KEY] = root[RESULT] = None
                # now update the cache dictionary for the new links
>               del cache[oldkey]
E               KeyError: (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f51cc10>, 'ttf', None, True, True, (('DejaVu Serif', 'Bitstream Vera Serif', 'Computer Modern Roman', 'New Century Schoolbook', 'Century Schoolbook L', 'Utopia', 'ITC Bookman', 'Bookman', 'Nimbus Roman No9 L', 'Times New Roman', 'Times', 'Palatino', 'Charter', 'serif'), ('DejaVu Sans', 'Bitstream Vera Sans', 'Computer Modern Sans Serif', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid', 'Arial', 'Helvetica', 'Avant Garde', 'sans-serif'), ('Apple Chancery', 'Textile', 'Zapf Chancery', 'Sand', 'Script MT', 'Felipa', 'cursive'), ('Comic Sans MS', 'Chicago', 'Charcoal', 'ImpactWestern', 'Humor Sans', 'xkcd', 'fantasy'), ('DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Computer Modern Typewriter', 'Andale Mono', 'Nimbus Mono L', 'Courier New', 'Courier', 'Fixed', 'Terminal', 'monospace')))
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/backports/functools_lru_cache.py:156: KeyError
__________________________ TestSeriesPlots.test_table __________________________
[gw0] linux2 -- Python 2.7.14 /home/travis/miniconda3/envs/pandas/bin/python
self = <pandas.tests.plotting.test_series.TestSeriesPlots object at 0x7f13006975d0>
    def test_table(self):
>       _check_plot_works(self.series.plot, table=True)
pandas/tests/plotting/test_series.py:796: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
pandas/tests/plotting/common.py:558: in _check_plot_works
    plt.savefig(path)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/pyplot.py:710: in savefig
    res = fig.savefig(*args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/figure.py:2035: in savefig
    self.canvas.print_figure(fname, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backend_bases.py:2261: in print_figure
    **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:511: in print_png
    FigureCanvasAgg.draw(self)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:431: in draw
    self.figure.draw(self.renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/artist.py:55: in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/figure.py:1475: in draw
    renderer, self, artists, self.suppressComposite)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/image.py:141: in _draw_list_compositing_images
    a.draw(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/artist.py:55: in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/axes/_base.py:2607: in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/image.py:141: in _draw_list_compositing_images
    a.draw(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/artist.py:55: in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:350: in draw
    self._update_positions(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:536: in _update_positions
    self._auto_set_font_size(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:494: in _auto_set_font_size
    size = cell.auto_set_font_size(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:95: in auto_set_font_size
    required = self.get_required_width(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:144: in get_required_width
    l, b, w, h = self.get_text_bounds(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/table.py:138: in get_text_bounds
    bbox = self._text.get_window_extent(renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/text.py:922: in get_window_extent
    bbox, info, descent = self._get_layout(self._renderer)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/text.py:300: in _get_layout
    ismath=False)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:239: in get_text_width_height_descent
    font = self._get_agg_font(prop)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py:273: in _get_agg_font
    fname = findfont(prop)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/font_manager.py:1475: in findfont
    font = fontManager.findfont(prop, **kw)
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/font_manager.py:1290: in findfont
    rc_params)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
args = (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f5d8b10>, 'ttf', None, True, True, ...)
kwds = {}
key = (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f5d8b10>, 'ttf', None, True, True, ...)
link = None
root = [[[[[[[...], [...], (...), '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/...e/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'], None, None]
result = '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf'
oldroot = [[[[[[[...], [...], (...), '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/..., ...), '/home/travis/miniconda3/envs/pandas/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf']
oldkey = (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f51cc10>, 'ttf', None, True, True, ...)
    def wrapper(*args, **kwds):
        # size limited caching that tracks accesses by recency
        key = make_key(args, kwds, typed) if kwds or typed else args
        with lock:
            link = cache_get(key)
            if link is not None:
                # record recent use of the key by moving it to the front of the list
                root, = nonlocal_root
                link_prev, link_next, key, result = link
                link_prev[NEXT] = link_next
                link_next[PREV] = link_prev
                last = root[PREV]
                last[NEXT] = root[PREV] = link
                link[PREV] = last
                link[NEXT] = root
                stats[HITS] += 1
                return result
        result = user_function(*args, **kwds)
        with lock:
            root, = nonlocal_root
            if key in cache:
                # getting here means that this same key was added to the
                # cache while the lock was released.  since the link
                # update is already done, we need only return the
                # computed result and update the count of misses.
                pass
            elif _len(cache) >= maxsize:
                # use the old root to store the new key and result
                oldroot = root
                oldroot[KEY] = key
                oldroot[RESULT] = result
                # empty the oldest link and make it the new root
                root = nonlocal_root[0] = oldroot[NEXT]
                oldkey = root[KEY]
                root[KEY] = root[RESULT] = None
                # now update the cache dictionary for the new links
>               del cache[oldkey]
E               KeyError: (<matplotlib.font_manager.FontManager object at 0x7f1337d66190>, <matplotlib.font_manager.FontProperties object at 0x7f131f51cc10>, 'ttf', None, True, True, (('DejaVu Serif', 'Bitstream Vera Serif', 'Computer Modern Roman', 'New Century Schoolbook', 'Century Schoolbook L', 'Utopia', 'ITC Bookman', 'Bookman', 'Nimbus Roman No9 L', 'Times New Roman', 'Times', 'Palatino', 'Charter', 'serif'), ('DejaVu Sans', 'Bitstream Vera Sans', 'Computer Modern Sans Serif', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid', 'Arial', 'Helvetica', 'Avant Garde', 'sans-serif'), ('Apple Chancery', 'Textile', 'Zapf Chancery', 'Sand', 'Script MT', 'Felipa', 'cursive'), ('Comic Sans MS', 'Chicago', 'Charcoal', 'ImpactWestern', 'Humor Sans', 'xkcd', 'fantasy'), ('DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Computer Modern Typewriter', 'Andale Mono', 'Nimbus Mono L', 'Courier New', 'Courier', 'Fixed', 'Terminal', 'monospace')))
../../../miniconda3/envs/pandas/lib/python2.7/site-packages/backports/functools_lru_cache.py:156: KeyError
```
</details>


Next to that, we also have two other tests that are skipped for now: https://github.com/pandas-dev/pandas/pull/20013/files, both related to timedelta tick formatting

See also https://github.com/pandas-dev/pandas/pull/19702


Discussion:
Sorry I dropped the ball on this :/ Anyone have a chance to look into it? If not I'll try to find some time today.
Also the docs broke: https://travis-ci.org/pandas-dev/pandas/jobs/350447963 (we use the table functionality of matplotlib for the merging.rst examples)
And the sphinx doc build also seems broken:

```
Notebook error:
RuntimeError in style.ipynb:
Kernel died before replying to kernel_info
```

and then it stops writing pages. Not fully sure it is related to matplotlib though, but seems to coincide.

Resolving patch:
diff --git a/pandas/plotting/_compat.py b/pandas/plotting/_compat.py
--- a/pandas/plotting/_compat.py
+++ b/pandas/plotting/_compat.py
@@ -1,76 +1,31 @@
 # being a bit too dynamic
 # pylint: disable=E1101
 from __future__ import division
+import operator
 
 from distutils.version import LooseVersion
 
 
-def _mpl_le_1_2_1():
-    try:
-        import matplotlib as mpl
-        return (LooseVersion(mpl.__version__) <= LooseVersion('1.2.1') and
+def _mpl_version(version, op):
+    def inner():
+        try:
+            import matplotlib as mpl
+        except ImportError:
+            return False
+        return (op(LooseVersion(mpl.__version__), LooseVersion(version)) and
                 str(mpl.__version__)[0] != '0')
-    except ImportError:
-        return False
 
+    return inner
 
-def _mpl_ge_1_3_1():
-    try:
-        import matplotlib
-        # The or v[0] == '0' is because their versioneer is
-        # messed up on dev
-        return (LooseVersion(matplotlib.__version__) >=
-                LooseVersion('1.3.1') or
-                str(matplotlib.__version__)[0] == '0')
-    except ImportError:
-        return False
 
-
-def _mpl_ge_1_4_0():
-    try:
-        import matplotlib
-        return (LooseVersion(matplotlib.__version__) >= LooseVersion('1.4') or
-                str(matplotlib.__version__)[0] == '0')
-    except ImportError:
-        return False
-
-
-def _mpl_ge_1_5_0():
-    try:
-        import matplotlib
-        return (LooseVersion(matplotlib.__version__) >= LooseVersion('1.5') or
-                str(matplotlib.__version__)[0] == '0')
-    except ImportError:
-        return False
-
-
-def _mpl_ge_2_0_0():
-    try:
-        import matplotlib
-        return LooseVersion(matplotlib.__version__) >= LooseVersion('2.0')
-    except ImportError:
-        return False
-
-
-def _mpl_le_2_0_0():
-    try:
-        import matplotlib
-        return matplotlib.compare_versions('2.0.0', matplotlib.__version__)
-    except ImportError:
-        return False
-
-
-def _mpl_ge_2_0_1():
-    try:
-        import matplotlib
-        return LooseVersion(matplotlib.__version__) >= LooseVersion('2.0.1')
-    except ImportError:
-        return False
-
-
-def _mpl_ge_2_1_0():
-    try:
-        import matplotlib
-        return LooseVersion(matplotlib.__version__) >= LooseVersion('2.1')
-    except ImportError:
-        return False
+_mpl_ge_1_2_1 = _mpl_version('1.2.1', operator.ge)
+_mpl_le_1_2_1 = _mpl_version('1.2.1', operator.le)
+_mpl_ge_1_3_1 = _mpl_version('1.3.1', operator.ge)
+_mpl_ge_1_4_0 = _mpl_version('1.4.0', operator.ge)
+_mpl_ge_1_4_1 = _mpl_version('1.4.1', operator.ge)
+_mpl_ge_1_5_0 = _mpl_version('1.5.0', operator.ge)
+_mpl_ge_2_0_0 = _mpl_version('2.0.0', operator.ge)
+_mpl_le_2_0_0 = _mpl_version('2.0.0', operator.le)
+_mpl_ge_2_0_1 = _mpl_version('2.0.1', operator.ge)
+_mpl_ge_2_1_0 = _mpl_version('2.1.0', operator.ge)
+_mpl_ge_2_2_0 = _mpl_version('2.2.0', operator.ge)


Test patch:
diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py
--- a/pandas/tests/plotting/common.py
+++ b/pandas/tests/plotting/common.py
@@ -56,6 +56,7 @@ def setup_method(self, method):
         self.mpl_ge_1_5_0 = plotting._compat._mpl_ge_1_5_0()
         self.mpl_ge_2_0_0 = plotting._compat._mpl_ge_2_0_0()
         self.mpl_ge_2_0_1 = plotting._compat._mpl_ge_2_0_1()
+        self.mpl_ge_2_2_0 = plotting._compat._mpl_ge_2_2_0()
 
         if self.mpl_ge_1_4_0:
             self.bp_n_objects = 7
diff --git a/pandas/tests/plotting/test_datetimelike.py b/pandas/tests/plotting/test_datetimelike.py
--- a/pandas/tests/plotting/test_datetimelike.py
+++ b/pandas/tests/plotting/test_datetimelike.py
@@ -8,7 +8,7 @@
 
 import numpy as np
 from pandas import Index, Series, DataFrame, NaT
-from pandas.compat import is_platform_mac, PY3
+from pandas.compat import PY3
 from pandas.core.indexes.datetimes import date_range, bdate_range
 from pandas.core.indexes.timedeltas import timedelta_range
 from pandas.tseries.offsets import DateOffset
@@ -1357,13 +1357,13 @@ def test_plot_outofbounds_datetime(self):
         values = [datetime(1677, 1, 1, 12), datetime(1677, 1, 2, 12)]
         ax.plot(values)
 
-    @td.xfail_if_mpl_2_2
-    @pytest.mark.skip(
-        is_platform_mac(),
-        "skip on mac for precision display issue on older mpl")
     def test_format_timedelta_ticks_narrow(self):
 
-        if self.mpl_ge_2_0_0:
+        if self.mpl_ge_2_2_0:
+            expected_labels = (['-1 days 23:59:59.999999998'] +
+                               ['00:00:00.0000000{:0>2d}'.format(2 * i)
+                                for i in range(6)])
+        elif self.mpl_ge_2_0_0:
             expected_labels = [''] + [
                 '00:00:00.00000000{:d}'.format(2 * i)
                 for i in range(5)] + ['']
@@ -1382,10 +1382,6 @@ def test_format_timedelta_ticks_narrow(self):
         for l, l_expected in zip(labels, expected_labels):
             assert l.get_text() == l_expected
 
-    @td.xfail_if_mpl_2_2
-    @pytest.mark.skip(
-        is_platform_mac(),
-        "skip on mac for precision display issue on older mpl")
     def test_format_timedelta_ticks_wide(self):
 
         if self.mpl_ge_2_0_0:
@@ -1402,6 +1398,9 @@ def test_format_timedelta_ticks_wide(self):
                 '9 days 06:13:20',
                 ''
             ]
+            if self.mpl_ge_2_2_0:
+                expected_labels[0] = '-2 days 20:13:20'
+                expected_labels[-1] = '10 days 10:00:00'
         else:
             expected_labels = [
                 '00:00:00',