Search code examples
pythonmatplotlibalignmentscatter-plotimshow

Aligning two combined plots - Matplotlib


I'm currently working in a plot in which I show to datas combined. I plot them with the following code:

plt.figure()

# Data 1
data = plt.cm.binary(data1)
data[..., 3] = 1.0 * (data1 > 0.0)
fig = plt.imshow(data, interpolation='nearest', cmap='binary', vmin=0, vmax=1, extent=(-4, 4, -4, 4))

# Plotting just the nonzero values of data2
x = numpy.linspace(-4, 4, 11)
y = numpy.linspace(-4, 4, 11)
data2_x = numpy.nonzero(data2)[0]
data2_y = numpy.nonzero(data2)[1]

pts = plt.scatter(x[data2_x], y[data2_y], marker='s', c=data2[data2_x, data2_y])

And this gives me this plot:

enter image description here

As can be seen in the image, my background and foreground squares are not aligned.

Both of then have the same dimension (20 x 20). I would like to have a way, if its possible, to align center with center, or corner with corner, but to have some kind of alignment.

In some grid cells it seems that I have right bottom corner alignment, in others left bottom corner alignment and in others no alignment at all, with degrades the visualization.

Any help would be appreciated.

Thank you.


Solution

  • As tcaswell says, your problem may be easiest to solve by defining the extent keyword for imshow.

    If you give the extent keyword, the outermost pixel edges will be at the extents. For example:

    import matplotlib.pyplot as plt
    import numpy as np
    
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.imshow(np.random.random((8, 10)), extent=(2, 6, -1, 1), interpolation='nearest', aspect='auto')
    

    enter image description here

    Now it is easy to calculate the center of each pixel. In X direction:

    • interpixel distance is (6-2) / 10 = 0.4 pixels
    • center of the leftmost pixel is half a pixel away from the left edge, 2 + .4/2 = 2.2

    Similarly, the Y centers are at -.875 + n * 0.25.

    So, by tuning the extent you can get your pixel centers wherever you want them.


    An example with 20x20 data:

    import matplotlib.pyplot as plt
    import numpy
    
    # create the data to be shown with "scatter"
    yvec, xvec = np.meshgrid(np.linspace(-4.75, 4.75, 20), np.linspace(-4.75, 4.75, 20))
    sc_data = random.random((20,20))
    
    # create the data to be shown with "imshow" (20 pixels)
    im_data = random.random((20,20))
    
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.imshow(im_data, extent=[-5,5,-5,5], interpolation='nearest', cmap=plt.cm.gray)
    ax.scatter(xvec, yvec, 100*sc_data)
    

    enter image description here

    Notice that here the inter-pixel distance is the same for both scatter (if you have a look at xvec, all pixels are 0.5 units apart) and imshow (as the image is stretched from -5 to +5 and has 20 pixels, the pixels are .5 units apart).