With matplotlib, how can I create a 2D histogram with polar projection and a symlog r-axis?
<p>I have been having trouble creating polar histograms with symlog axis. However this only breaks when there are negative r-values. What can I do to fix this?</p>

<p>I've included a minimal example which displays 5 plots. Plot 4 is the one which does not work (middle row right.) Plot 5 is to show it working with positive numbers. </p>

<p>Here's the output:</p>

<p><a href="http://i.stack.imgur.com/We4MX.png" rel="nofollow"><img src="http://i.stack.imgur.com/We4MX.png" alt="enter image description here"></a>    </p>

<p>Here's the code: </p>

<pre><code>import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.scale import SymmetricalLogTransform


MIN_BINS = 500
MAX_BINS = 1000
# utility function for making bins of correct size
def get_bins(min_val, max_val, scaling):
    w = 1 + max(MIN_BINS, min(MAX_BINS, abs(min_val - max_val) + 1))

    if scaling == 'log':
        return np.logspace(np.log10(min_val), np.log10(max_val), w)
    elif scaling == 'symlog':
        tr = SymmetricalLogTransform(base=10, linthresh=1, linscale=1)

        ss = tr.transform([min_val, max_val])

        ls = tr.inverted().transform(np.linspace(*ss, num=w))
        return ls
    else:# linear
        return np.linspace(min_val, max_val, w)




TESTS = [1,2,3,4,5]

plt.figure(figsize=(12,18))
plot_pos = 320
for TEST in TESTS:
    plot_pos += 1

    if TEST == 1:
        NEG = True
        YSCALE = 'linear'
        PROJECTION = None

    if TEST == 2:
        NEG = True
        YSCALE = 'symlog'
        PROJECTION = None


    if TEST == 3:
        NEG = True
        YSCALE = 'linear'
        PROJECTION = 'polar'

    # This is what I want to work
    if TEST == 4:
        NEG = True
        YSCALE = 'symlog'
        PROJECTION = 'polar'

    # However, remove the negative numbers and it seems to work
    if TEST == 5:
        NEG = False
        YSCALE = 'symlog'
        PROJECTION = 'polar'



    sample_size = 100000
    xs = np.pi * np.linspace(0.0, 2.0, sample_size)
    ys = 20 * np.random.random(sample_size)

    if NEG:
        ys -= 10

    ax = plt.subplot(plot_pos, projection=PROJECTION)

    ax.set_title('Neg/Scale/Proj.:%s,%s,%s' % (NEG, YSCALE, PROJECTION))

    min_y = np.min(ys)
    max_y = np.max(ys)
    min_x = np.min(xs)
    max_x = np.max(xs)

    x_bins = get_bins(min_x, max_x, 'linear')
    y_bins = get_bins(min_y, max_y, YSCALE)

    hist, xedges, yedges = np.histogram2d(
        xs,
        ys,
        bins=[x_bins, y_bins]
    )

    X, Y = np.meshgrid(xedges, yedges)

    ax.pcolormesh(
        X, Y,
        hist.T,
        cmap=cm.gray_r,
    )

    if PROJECTION == 'polar':
        ax.set_rscale(YSCALE)

        ax.set_rmax(max_y)
        ax.set_rmin(min_y)
    else:
        ax.set_ylim([min_y, max_y])

        ax.set_yscale(YSCALE)

    ax.grid(True)

plt.savefig('polar_example.png')
</code></pre>

<p>This might be a bug in matplotlib, unfortunately polar plots have multiple <a href="https://github.com/matplotlib/matplotlib/issues/7130" rel="nofollow">scaling issues</a> and <a href="https://github.com/matplotlib/matplotlib/issues/7120#issuecomment-247460462" rel="nofollow">might have to go through some major revisions in the future</a>.</p>

<p>I suspect that the issue is this, for your problematic fourth <code>polar</code>-<code>symlog</code> axes:</p>

<pre><code>&gt;&gt;&gt; ax.get_rmin()
-9.9998049982336408

&gt;&gt;&gt; ax.get_rmax()
9.9999564676741315
</code></pre>

<p>Negative radii are present since <code>symlog</code> is prepared to handle them. However, matplotlib had some issues plotting these values, and <a href="https://github.com/matplotlib/matplotlib/pull/4699" rel="nofollow">corresponding behaviour even changed in the past</a>. I think the only problem now is that the negative radial limits passed in during the call to <code>ax.set_rmin()</code> are interpreted as reflected positive values. Here's your test when I change the radial case to</p>

<pre><code>if PROJECTION == 'polar':
    ax.set_rscale(YSCALE)

    ax.set_rmax(max_y)
    ax.set_rmin(max(0,min_y)) # change here
</code></pre>

<p><a href="http://i.stack.imgur.com/u9eXR.png" rel="nofollow"><img src="http://i.stack.imgur.com/u9eXR.png" alt="fixed result"></a></p>

python matplotlib plot polar-coordinates