making square axes plot with log2 scales in matplotlib


Question

I'd like to make a square axis scatter plot with matplotlib. Normally using set_scale("log") works great, but it limits me to log10. I'd like to make the plot in log2. I saw the solution here: How to produce an exponentially scaled axis?

but it is quite complicated and does not work if you have 0 values in your arrays, which I do. I'd like to simply ignore those like other numpy functions do.

For example:

log2scatter(data1, data2)

where data1 and data2 contain 0s should have a logarithmic scale on the x and y axis, with logarithmic spaced ticks. Just like log10, except log2...

Thanks.

1
20
5/23/2017 11:46:52 AM

Just specify basex=2 or basey=2.

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.set_xscale('log', basex=2)
ax.set_yscale('log', basey=2)

ax.plot(range(1024))
plt.show()

enter image description here

For the zero-crossing behavior, what you're referring to is a "Symmetric Log" plot (a.k.a. "symlog"). For whatever it's worth, data isn't filtered out, it's just a linear plot near 0 and a log plot everywhere else. It's the scale that changes, not the data.

Normally you'd just do ax.set_xscale('symlog', basex=2) but using a non-10 base appears to be buggy at the moment for symlog plots.

Edit: Heh! The bug appears to be due to a classic mistake: using a mutable default argument.
I've filed a bug report, but if you feel like fixing it, you'll need to make a minor edit to lib/matplotlib/ticker.py, around line 1376, in the __init__ method of SymmetricalLogLocator.

Instead of

def __init__(self, transform, subs=[1.0]):
    self._transform = transform
    self._subs = subs
    ...

Change it to something similar to:

def __init__(self, transform, subs=None):
    self._transform = transform
    if subs is None:
        self._subs = [1.0]
    else:
        self._subs = subs
    ....

With that change made, it behaves as expected...

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
ax.set_xscale('symlog', basex=2)
ax.set_yscale('symlog', basey=2)

x = np.arange(-1024, 1024)
ax.plot(x, x)

plt.show()

enter image description here

40
1/17/2012 12:32:51 AM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon