pythonnumpymatplotlibimshow

imshow with x-axis as log scale is not equally-spaced


I am using pcolor to generate the following plot (code below). It has a colorbar in log scale and the x-values are in log-scale too. The problem is that the rectangles in this plot have different widths (I've put a red grid to show the rectangles better, suggestion of Trenton). Is there any way in which I can make sure the width of each rectangle is the same?

enter image description here

import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import numpy as np

# Generate Values
x_values = np.geomspace(start=1, stop=1e-2, num=6)
y_values = np.arange(start=0, stop=50, step=4, dtype=int)
x_grid, y_grid = np.meshgrid(x_values, y_values)
z_values = np.random.randn(len(y_values), len(x_values))


fig, ax = plt.subplots()
im = ax.pcolor(x_grid, y_grid, z_values, norm=matplotlib.colors.LogNorm(), ec='r', lw=2)
ax.set_xscale('log')
fig.colorbar(im)
plt.show()

Solution

  • You need to specify the bin edges. Probably a better way to do this in numpy, but the idea is simple - transform to log space, get the bin edges by linear interpolation, and then transform back to normal space.

    import matplotlib.pyplot as plt
    from matplotlib.colors import LogNorm
    import numpy as np
    
    # Generate Values
    x_values = np.geomspace(start=1, stop=1e-2, num=6)
    y_values = np.arange(start=0, stop=50, step=4, dtype=int)
    # edges?
    logx = np.log10(x_values)
    edgex = np.hstack((
        logx[:-1] - np.diff(logx) / 2,
        logx[-1] - np.diff(logx)[-1] / 2, logx[-1] + np.diff(logx)[-1] / 2))
    edgex = 10**edgex
    
    edgey = np.hstack((
        y_values[:-1] - np.diff(y_values) / 2,
        y_values[-1] - np.diff(y_values)[-1] / 2, y_values[-1] + np.diff(y_values)[-1] / 2))
    
    np.random.seed(12345)
    z_values = np.random.randn(len(y_values), len(x_values))
    
    fig, axs = plt.subplots(1, 2, layout='constrained')
    ax = axs[0]
    im = ax.pcolormesh(x_values, y_values, z_values, norm=LogNorm(), ec='r', lw=2)
    ax.set_xscale('log')
    ax.set_title('Linear gaps')
    ax.plot(x_values, 0 * x_values, 'dm')
    fig.colorbar(im)
    
    ax = axs[1]
    im = ax.pcolormesh(edgex, edgey, z_values, norm=LogNorm(), ec='r', lw=2)
    ax.plot(x_values, 0 * x_values, 'dm')
    ax.set_xscale('log')
    ax.set_title('Log gaps')
    fig.colorbar(im)
    

    enter image description here