<h3 dir="auto">Bug report</h3>
<p dir="auto"><strong>Bug summary</strong></p>
<p dir="auto">Some colorbar labels are printed twice when I use a colorbar with LogNorm and small ranges of numbers after setting the ticks manually with set_ticks().</p>
<p dir="auto">See figure below: By setting the minor_thresholds to something low, the double ticklabel at 20000 disappears, so it could have something to do with the minor formatter in LogFormatterSciNotation?</p>
<p dir="auto">I think it could be related to other issues that have been posted: <a href="https://github.com/matplotlib/matplotlib/issues/12488" data-hovercard-type="issue" data-hovercard-url="/matplotlib/matplotlib/issues/12488/hovercard">#12488</a> <a href="https://github.com/matplotlib/matplotlib/issues/12503" data-hovercard-type="issue" data-hovercard-url="/matplotlib/matplotlib/issues/12503/hovercard">#12503</a></p>
<p dir="auto"><strong>Code for reproduction</strong></p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.ticker as ticker

fig, ax = plt.subplots()
pcm = ax.imshow([[10000, 25000]], norm=mcolors.LogNorm())
cb = fig.colorbar(pcm)
# cb.formatter.minor_thresholds = [0,0] # deactivates minor ticks labels?
cb.formatter = ticker.EngFormatter()
cb.set_ticks([10000,20000,25000])"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>
<span class="pl-k">import</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">pyplot</span> <span class="pl-k">as</span> <span class="pl-s1">plt</span>
<span class="pl-k">import</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">colors</span> <span class="pl-k">as</span> <span class="pl-s1">mcolors</span>
<span class="pl-k">import</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">ticker</span> <span class="pl-k">as</span> <span class="pl-s1">ticker</span>

<span class="pl-s1">fig</span>, <span class="pl-s1">ax</span> <span class="pl-c1">=</span> <span class="pl-s1">plt</span>.<span class="pl-en">subplots</span>()
<span class="pl-s1">pcm</span> <span class="pl-c1">=</span> <span class="pl-s1">ax</span>.<span class="pl-en">imshow</span>([[<span class="pl-c1">10000</span>, <span class="pl-c1">25000</span>]], <span class="pl-s1">norm</span><span class="pl-c1">=</span><span class="pl-s1">mcolors</span>.<span class="pl-v">LogNorm</span>())
<span class="pl-s1">cb</span> <span class="pl-c1">=</span> <span class="pl-s1">fig</span>.<span class="pl-en">colorbar</span>(<span class="pl-s1">pcm</span>)
<span class="pl-c"># cb.formatter.minor_thresholds = [0,0] # deactivates minor ticks labels?</span>
<span class="pl-s1">cb</span>.<span class="pl-s1">formatter</span> <span class="pl-c1">=</span> <span class="pl-s1">ticker</span>.<span class="pl-v">EngFormatter</span>()
<span class="pl-s1">cb</span>.<span class="pl-en">set_ticks</span>([<span class="pl-c1">10000</span>,<span class="pl-c1">20000</span>,<span class="pl-c1">25000</span>])</pre></div>
<p dir="auto"><strong>Actual outcome</strong></p>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/18345456/50727465-8aaea000-111b-11e9-88f2-cc2cc7eb65af.png"><img src="https://user-images.githubusercontent.com/18345456/50727465-8aaea000-111b-11e9-88f2-cc2cc7eb65af.png" alt="image" style="max-width: 100%;"></a></p>
<p dir="auto"><strong>Expected outcome</strong></p>
<p dir="auto">There should be no double ticks.</p>
<p dir="auto"><strong>Matplotlib version</strong></p>
<ul dir="auto">
<li>Operating system: OSX</li>
<li>Matplotlib version: 3.0.2</li>
<li>Matplotlib backend: Qt5Agg</li>
<li>Python version: 3.7</li>
<li>Jupyter version (if applicable): -</li>
<li>Other libraries: -<br>
I installed matplotlib via conda through the default channel.</li>
</ul>
<p dir="auto">Travis has been failing a lot lately, and I'm pretty sure the reason is baseline image reuse + parallel tests. I believe pytest parallelizes across extension and baseline image, so when a test writes to the same baseline more than once, there's a high possibility that one figure will be saved on top of another while it's trying to verify that it was correct.</p>
<p dir="auto">For example, the <code class="notranslate">step_linestyle</code> image has been failing a lot recently, which you can try out with:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ py.test test_axes.py -k linestyle -n 8
...
...
________________________________________________ test_step_linestyle[1-step_linestyle-svg] _________________________________________________
[gw7] linux -- Python 3.5.2 /home/elliott/code/conda/envs/mpl35/bin/python
expected = '/home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle-expected_svg.png'
actual = '/home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle_svg.png'
tol = 0, in_decorator = True

    def compare_images(expected, actual, tol, in_decorator=False):
        &quot;&quot;&quot;
        Compare two &quot;image&quot; files checking differences within a tolerance.
    
        The two given filenames may point to files which are convertible to
        PNG via the `.converter` dictionary. The underlying RMS is calculated
        with the `.calculate_rms` function.
    
        Parameters
        ----------
        expected : str
            The filename of the expected image.
        actual :str
            The filename of the actual image.
        tol : float
            The tolerance (a color value difference, where 255 is the
            maximal difference).  The test fails if the average pixel
            difference is greater than this value.
        in_decorator : bool
            If called from image_comparison decorator, this should be
            True. (default=False)
    
        Example
        -------
        img1 = &quot;./baseline/plot.png&quot;
        img2 = &quot;./output/plot.png&quot;
        compare_images( img1, img2, 0.001 ):
    
        &quot;&quot;&quot;
        if not os.path.exists(actual):
            msg = &quot;Output image %s does not exist.&quot; % actual
            raise Exception(msg)
    
        if os.stat(actual).st_size == 0:
            msg = &quot;Output image file %s is empty.&quot; % actual
            raise Exception(msg)
    
        verify(actual)
    
        # Convert the image to png
        extension = expected.split('.')[-1]
    
        if not os.path.exists(expected):
            raise IOError('Baseline image %r does not exist.' % expected)
    
        if extension != 'png':
            actual = convert(actual, False)
            expected = convert(expected, True)
    
        # open the image files and remove the alpha channel (if it exists)
        expectedImage = _png.read_png_int(expected)
&gt;       actualImage = _png.read_png_int(actual)
E       SystemError: &lt;built-in function read_png_int&gt; returned NULL without setting an error"><pre class="notranslate"><code class="notranslate">$ py.test test_axes.py -k linestyle -n 8
...
...
________________________________________________ test_step_linestyle[1-step_linestyle-svg] _________________________________________________
[gw7] linux -- Python 3.5.2 /home/elliott/code/conda/envs/mpl35/bin/python
expected = '/home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle-expected_svg.png'
actual = '/home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle_svg.png'
tol = 0, in_decorator = True

    def compare_images(expected, actual, tol, in_decorator=False):
        """
        Compare two "image" files checking differences within a tolerance.
    
        The two given filenames may point to files which are convertible to
        PNG via the `.converter` dictionary. The underlying RMS is calculated
        with the `.calculate_rms` function.
    
        Parameters
        ----------
        expected : str
            The filename of the expected image.
        actual :str
            The filename of the actual image.
        tol : float
            The tolerance (a color value difference, where 255 is the
            maximal difference).  The test fails if the average pixel
            difference is greater than this value.
        in_decorator : bool
            If called from image_comparison decorator, this should be
            True. (default=False)
    
        Example
        -------
        img1 = "./baseline/plot.png"
        img2 = "./output/plot.png"
        compare_images( img1, img2, 0.001 ):
    
        """
        if not os.path.exists(actual):
            msg = "Output image %s does not exist." % actual
            raise Exception(msg)
    
        if os.stat(actual).st_size == 0:
            msg = "Output image file %s is empty." % actual
            raise Exception(msg)
    
        verify(actual)
    
        # Convert the image to png
        extension = expected.split('.')[-1]
    
        if not os.path.exists(expected):
            raise IOError('Baseline image %r does not exist.' % expected)
    
        if extension != 'png':
            actual = convert(actual, False)
            expected = convert(expected, True)
    
        # open the image files and remove the alpha channel (if it exists)
        expectedImage = _png.read_png_int(expected)
&gt;       actualImage = _png.read_png_int(actual)
E       SystemError: &lt;built-in function read_png_int&gt; returned NULL without setting an error
</code></pre></div>
<p dir="auto">which failed reading the png-from-svg, but running again gets:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="________________________________________________ test_step_linestyle[0-step_linestyle-svg] _________________________________________________
[gw3] linux -- Python 3.5.2 /home/elliott/code/conda/envs/mpl35/bin/python
expected = '/home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle-expected.svg'
actual = '/home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle.svg'
tol = 0, in_decorator = True

    def compare_images(expected, actual, tol, in_decorator=False):
        &quot;&quot;&quot;
        Compare two &quot;image&quot; files checking differences within a tolerance.
    
        The two given filenames may point to files which are convertible to
        PNG via the `.converter` dictionary. The underlying RMS is calculated
        with the `.calculate_rms` function.
    
        Parameters
        ----------
        expected : str
            The filename of the expected image.
        actual :str
            The filename of the actual image.
        tol : float
            The tolerance (a color value difference, where 255 is the
            maximal difference).  The test fails if the average pixel
            difference is greater than this value.
        in_decorator : bool
            If called from image_comparison decorator, this should be
            True. (default=False)
    
        Example
        -------
        img1 = &quot;./baseline/plot.png&quot;
        img2 = &quot;./output/plot.png&quot;
        compare_images( img1, img2, 0.001 ):
    
        &quot;&quot;&quot;
        if not os.path.exists(actual):
            msg = &quot;Output image %s does not exist.&quot; % actual
            raise Exception(msg)
    
        if os.stat(actual).st_size == 0:
            msg = &quot;Output image file %s is empty.&quot; % actual
&gt;           raise Exception(msg)
E           Exception: Output image file /home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle.svg is empty."><pre class="notranslate"><code class="notranslate">________________________________________________ test_step_linestyle[0-step_linestyle-svg] _________________________________________________
[gw3] linux -- Python 3.5.2 /home/elliott/code/conda/envs/mpl35/bin/python
expected = '/home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle-expected.svg'
actual = '/home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle.svg'
tol = 0, in_decorator = True

    def compare_images(expected, actual, tol, in_decorator=False):
        """
        Compare two "image" files checking differences within a tolerance.
    
        The two given filenames may point to files which are convertible to
        PNG via the `.converter` dictionary. The underlying RMS is calculated
        with the `.calculate_rms` function.
    
        Parameters
        ----------
        expected : str
            The filename of the expected image.
        actual :str
            The filename of the actual image.
        tol : float
            The tolerance (a color value difference, where 255 is the
            maximal difference).  The test fails if the average pixel
            difference is greater than this value.
        in_decorator : bool
            If called from image_comparison decorator, this should be
            True. (default=False)
    
        Example
        -------
        img1 = "./baseline/plot.png"
        img2 = "./output/plot.png"
        compare_images( img1, img2, 0.001 ):
    
        """
        if not os.path.exists(actual):
            msg = "Output image %s does not exist." % actual
            raise Exception(msg)
    
        if os.stat(actual).st_size == 0:
            msg = "Output image file %s is empty." % actual
&gt;           raise Exception(msg)
E           Exception: Output image file /home/elliott/code/matplotlib/lib/matplotlib/tests/result_images/test_axes/step_linestyle.svg is empty.
</code></pre></div>
<p dir="auto">which points to a truncated svg.</p>
<p dir="auto">To fix this, we should be able to stop pytest from parallelizing across baseline images, but what if more than one test uses the same image? I haven't yet checked that case, but it's a possibility. Making some kind of lock-per-baseline-image seems like too much work. Should we start duplicating our baseline images if that's happening?</p>