11

I was just wondering if this can be done. I have tried to set the bins explicitly using numpy logspace, and I have also tried to set the xscale to 'log'. Neither of these options work. Has anybody ever tried this?

I just want a 2d histogram with a log x-axis and a linear y-axis.

1
  • Please share your code. Commented Mar 20, 2015 at 20:31

1 Answer 1

19

The reason it's not working correctly is that plt.hist2d uses the pcolorfast method, which is much more efficient for large images, but doesn't support log axes.

To have a 2D histogram that works correctly on log axes, you'll need to make it yourself using np.histogram2d and ax.pcolor. However, it's only one extra line of code.

To start with, let's use exponentially spaced bins on a linear axis:

import numpy as np
import matplotlib.pyplot as plt

x, y = np.random.random((2, 1000))
x = 10**x

xbins = 10**np.linspace(0, 1, 10)
ybins = np.linspace(0, 1, 10)

fig, ax = plt.subplots()
ax.hist2d(x, y, bins=(xbins, ybins))

plt.show()

enter image description here

Okay, all well and good. Let's see what happens if we make the x-axis use a log scale:

import numpy as np
import matplotlib.pyplot as plt

x, y = np.random.random((2, 1000))
x = 10**x

xbins = 10**np.linspace(0, 1, 10)
ybins = np.linspace(0, 1, 10)

fig, ax = plt.subplots()
ax.hist2d(x, y, bins=(xbins, ybins))

ax.set_xscale('log') # <-- Only difference from previous example

plt.show()

enter image description here

Notice that the log scaling seems to have been applied, but the colored image (the histogram) isn't reflecting it. The bins should appear square! They're not because the artist created by pcolorfast doesn't support log axes.

To fix this, let's make the histogram using np.histogram2d (what plt.hist2d uses behind-the-scenes), and then plot it using pcolormesh (or pcolor), which does support log axes:

import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1977)

x, y = np.random.random((2, 1000))
x = 10**x

xbins = 10**np.linspace(0, 1, 10)
ybins = np.linspace(0, 1, 10)

counts, _, _ = np.histogram2d(x, y, bins=(xbins, ybins))

fig, ax = plt.subplots()
ax.pcolormesh(xbins, ybins, counts.T)

ax.set_xscale('log')

plt.show()

(Note that we have to transpose counts here, because pcolormesh expects the axes to be in the order of (Y, X).)

Now we get the result we'd expect:

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

NOTE: I just found that you have to transpose counts, otherwise X and Y axes will be flipped! (You can easily check by, say, adding y *= 0.3: the upper half of the plot should go black.) Just submitted an edit to fix it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.