<h3 dir="auto">Bug summary</h3>
<p dir="auto">SageMath project uses matplotlib for graphics. We are recently upgrading matplotlib to version 3.6. In this effort, we encountered a failure in this command:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="plot(2*x+1,(x,0,5), ticks=[[0,1,e,pi,sqrt(20)],2], tick_formatter=&quot;latex&quot;)"><pre class="notranslate"><span class="pl-en">plot</span>(<span class="pl-c1">2</span><span class="pl-c1">*</span><span class="pl-s1">x</span><span class="pl-c1">+</span><span class="pl-c1">1</span>,(<span class="pl-s1">x</span>,<span class="pl-c1">0</span>,<span class="pl-c1">5</span>), <span class="pl-s1">ticks</span><span class="pl-c1">=</span>[[<span class="pl-c1">0</span>,<span class="pl-c1">1</span>,<span class="pl-s1">e</span>,<span class="pl-s1">pi</span>,<span class="pl-en">sqrt</span>(<span class="pl-c1">20</span>)],<span class="pl-c1">2</span>], <span class="pl-s1">tick_formatter</span><span class="pl-c1">=</span><span class="pl-s">"latex"</span>)</pre></div>
<p dir="auto">Here we use symbolic constants e, pi, sqrt(20) as major x-axis tick values. This worked very well up to now. But matplotlib version 3.6 fails this. I investigated the ultimate source of this failure.</p>
<p dir="auto">We set the major tick locator as <code class="notranslate">FixedLocator</code> with the above symbolic values, and the minor tick locator to <code class="notranslate">NullLocator</code>. When matplotlib renders the plot, it tries to update minor tick values and calls <code class="notranslate">matplotlib.axis.get_minorticklocs()</code>, which is</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="    def get_minorticklocs(self):
        &quot;&quot;&quot;Return this Axis' minor tick locations in data coordinates.&quot;&quot;&quot;
        # Remove minor ticks duplicating major ticks.
        minor_locs = np.asarray(self.minor.locator())
        if self.remove_overlapping_locs:
            major_locs = self.major.locator()
            transform = self._scale.get_transform()
            tr_minor_locs = transform.transform(minor_locs)
            tr_major_locs = transform.transform(major_locs)
            lo, hi = sorted(transform.transform(self.get_view_interval()))
            # Use the transformed view limits as scale.  1e-5 is the default
            # rtol for np.isclose.
            tol = (hi - lo) * 1e-5
            mask = np.isclose(tr_minor_locs[:, None], tr_major_locs[None, :],
                              atol=tol, rtol=0).any(axis=1)
            minor_locs = minor_locs[~mask]
        return minor_locs  "><pre class="notranslate">    <span class="pl-k">def</span> <span class="pl-en">get_minorticklocs</span>(<span class="pl-s1">self</span>):
        <span class="pl-s">"""Return this Axis' minor tick locations in data coordinates."""</span>
        <span class="pl-c"># Remove minor ticks duplicating major ticks.</span>
        <span class="pl-s1">minor_locs</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">asarray</span>(<span class="pl-s1">self</span>.<span class="pl-s1">minor</span>.<span class="pl-en">locator</span>())
        <span class="pl-k">if</span> <span class="pl-s1">self</span>.<span class="pl-s1">remove_overlapping_locs</span>:
            <span class="pl-s1">major_locs</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-s1">major</span>.<span class="pl-en">locator</span>()
            <span class="pl-s1">transform</span> <span class="pl-c1">=</span> <span class="pl-s1">self</span>.<span class="pl-s1">_scale</span>.<span class="pl-en">get_transform</span>()
            <span class="pl-s1">tr_minor_locs</span> <span class="pl-c1">=</span> <span class="pl-s1">transform</span>.<span class="pl-en">transform</span>(<span class="pl-s1">minor_locs</span>)
            <span class="pl-s1">tr_major_locs</span> <span class="pl-c1">=</span> <span class="pl-s1">transform</span>.<span class="pl-en">transform</span>(<span class="pl-s1">major_locs</span>)
            <span class="pl-s1">lo</span>, <span class="pl-s1">hi</span> <span class="pl-c1">=</span> <span class="pl-en">sorted</span>(<span class="pl-s1">transform</span>.<span class="pl-en">transform</span>(<span class="pl-s1">self</span>.<span class="pl-en">get_view_interval</span>()))
            <span class="pl-c"># Use the transformed view limits as scale.  1e-5 is the default</span>
            <span class="pl-c"># rtol for np.isclose.</span>
            <span class="pl-s1">tol</span> <span class="pl-c1">=</span> (<span class="pl-s1">hi</span> <span class="pl-c1">-</span> <span class="pl-s1">lo</span>) <span class="pl-c1">*</span> <span class="pl-c1">1e-5</span>
            <span class="pl-s1">mask</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">isclose</span>(<span class="pl-s1">tr_minor_locs</span>[:, <span class="pl-c1">None</span>], <span class="pl-s1">tr_major_locs</span>[<span class="pl-c1">None</span>, :],
                              <span class="pl-s1">atol</span><span class="pl-c1">=</span><span class="pl-s1">tol</span>, <span class="pl-s1">rtol</span><span class="pl-c1">=</span><span class="pl-c1">0</span>).<span class="pl-en">any</span>(<span class="pl-s1">axis</span><span class="pl-c1">=</span><span class="pl-c1">1</span>)
            <span class="pl-s1">minor_locs</span> <span class="pl-c1">=</span> <span class="pl-s1">minor_locs</span>[<span class="pl-c1">~</span><span class="pl-s1">mask</span>]
        <span class="pl-k">return</span> <span class="pl-s1">minor_locs</span>  </pre></div>
<p dir="auto">Note that <code class="notranslate">tr_minor_locs</code> is an empty numpy array and <code class="notranslate">tr_major_locs</code> contains our symbolic values. The line <code class="notranslate">mask = np.isclose(...)</code> raises an exception because it does not understand the symbolic values. This behavior is new due to code changes in <code class="notranslate">get_minorticklocs()</code> in matplotlib 3.6.</p>
<p dir="auto">Note that as the minor tick locator is <code class="notranslate">NullLocator</code>, that is, empty. <code class="notranslate">get_minorticklocs()</code> has nothing to do here. So by this change</p>
<div class="highlight highlight-source-diff notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="---    if self.remove_overlapping_locs:
+++    if len(minor_locs) and and self.remove_overlapping_locs:"><pre class="notranslate"><span class="pl-md">---    if self.remove_overlapping_locs:</span>
<span class="pl-mi1">+++    if len(minor_locs) and and self.remove_overlapping_locs:</span></pre></div>
<p dir="auto">matplotlib can save unnecessary computation, and our problem in SageMath will be solved. So please consider this.</p>
<h3 dir="auto">Code for reproduction</h3>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="Explained in Bug summary"><pre class="notranslate"><span class="pl-v">Explained</span> <span class="pl-c1">in</span> <span class="pl-v">Bug</span> <span class="pl-s1">summary</span></pre></div>
<h3 dir="auto">Actual outcome</h3>
<p dir="auto">Explained in Bug summary</p>
<h3 dir="auto">Expected outcome</h3>
<p dir="auto">Explained in Bug summary</p>
<h3 dir="auto">Additional information</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Operating system</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Matplotlib Version</h3>
<p dir="auto">3.6</p>
<h3 dir="auto">Matplotlib Backend</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Python version</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Jupyter version</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Installation</h3>
<p dir="auto"><em>No response</em></p>
<p dir="auto">Setting <code class="notranslate">mec='none'</code> removes the entire marker when exporting to PNG. See attached MWE and compare PDF and PNG output. May be related to <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="2531453" data-permission-text="Title is private" data-url="https://github.com/matplotlib/matplotlib/issues/621" data-hovercard-type="issue" data-hovercard-url="/matplotlib/matplotlib/issues/621/hovercard" href="https://github.com/matplotlib/matplotlib/issues/621">#621</a> and <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="46353486" data-permission-text="Title is private" data-url="https://github.com/matplotlib/matplotlib/issues/3687" data-hovercard-type="pull_request" data-hovercard-url="/matplotlib/matplotlib/pull/3687/hovercard" href="https://github.com/matplotlib/matplotlib/pull/3687">#3687</a></p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import numpy as np
from matplotlib import pyplot as plt
x = np.random.random(10)
y = np.random.random(10)

plt.clf()
plt.plot(x, y, 'o', mec='none')
plt.savefig('test.pdf')
plt.savefig('test.png')"><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">from</span> <span class="pl-s1">matplotlib</span> <span class="pl-k">import</span> <span class="pl-s1">pyplot</span> <span class="pl-k">as</span> <span class="pl-s1">plt</span>
<span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-s1">random</span>.<span class="pl-en">random</span>(<span class="pl-c1">10</span>)
<span class="pl-s1">y</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-s1">random</span>.<span class="pl-en">random</span>(<span class="pl-c1">10</span>)

<span class="pl-s1">plt</span>.<span class="pl-en">clf</span>()
<span class="pl-s1">plt</span>.<span class="pl-en">plot</span>(<span class="pl-s1">x</span>, <span class="pl-s1">y</span>, <span class="pl-s">'o'</span>, <span class="pl-s1">mec</span><span class="pl-c1">=</span><span class="pl-s">'none'</span>)
<span class="pl-s1">plt</span>.<span class="pl-en">savefig</span>(<span class="pl-s">'test.pdf'</span>)
<span class="pl-s1">plt</span>.<span class="pl-en">savefig</span>(<span class="pl-s">'test.png'</span>)</pre></div>