DaPhil
DaPhil

Reputation: 1599

Why does contourf (matplotlib) switch x and y coordinates?

I am trying to get contourf to plot my stuff right, but it seems to switch the x and y coordinates. In the example below, I show this by evaluating a 2d Gaussian function that has different widths in x and y directions. With the values given, the width in y direction should be larger. Here is the script:

from numpy import *
from matplotlib.pyplot import *

xMax = 50
xNum = 100
w0x = 10
w0y = 15

dx = xMax/xNum
xGrid = linspace(-xMax/2+dx/2, xMax/2-dx/2, xNum, endpoint=True)
yGrid = xGrid

Int = zeros((xNum, xNum))

for idX in range(xNum):
    for idY in range(xNum):
        Int[idX, idY] = exp(-((xGrid[idX]/w0x)**2 + (yGrid[idY]/(w0y))**2))

fig = figure(6)
clf()

ax = subplot(2,1,1)

X, Y = meshgrid(xGrid, yGrid)

contour(X, Y, Int, colors='k')
plot(array([-xMax, xMax])/2, array([0, 0]), '-b')
plot(array([0, 0]), array([-xMax, xMax])/2, '-r')
ax.set_aspect('equal')
xlabel("x")
ylabel("y")

subplot(2,1,2)

plot(xGrid, Int[:, int(xNum/2)], '-b', label='I(x, y=max/2)')
plot(xGrid, Int[int(xNum/2), :], '-r', label='I(x=max/2, y)')
ax.set_aspect('equal')
legend()
xlabel(r"x or y")
ylabel(r"I(x or y)")

The figure thrown out is this: enter image description here

On top the contour plot which has the larger width in x direction (not y). Below are slices shown, one across x direction (at constant y=0, blue), the other in y direction (at constant x=0, red). Here, everything seems fine, the y direction is broader than the x direction. So why would I have to transpose the array in order to have it plotted as I want? This seems unintuitive to me and not in agreement with the documentation.

Upvotes: 1

Views: 1808

Answers (1)

MB-F
MB-F

Reputation: 23647

It helps if you think of a 2D array's shape not as (x, y) but as (rows, columns), because that is how most math routines interpret them - including matplotlib's 2D plotting functions. Therefore, the first dimension is vertical (which you call y) and the second dimension is horizontal (which you call x).

Note that this convention is very prominent, even in numpy. The function np.vstack is supposed to concatenate arrays vertically works along the first dimension and np.hstack works horizontally on the second dimension.

To illustrate the point:

import numpy as np
import matplotlib.pyplot as plt

a = np.array([[0, 0, 1, 0, 0],
              [0, 1, 1, 1, 0],
              [1, 1, 1, 1, 1]])

a[:, 2] = 2  # set column

print(a)

plt.imshow(a)
plt.contour(a, colors='k')

This prints

[[0 0 2 0 0]
 [0 1 2 1 0]
 [1 1 2 1 1]]

and consistently plots

enter image description here

According to your convention that an array is (x, y) the command a[:, 2] = 2 should have assigned to the third row, but numpy and matplotlib both agree that it was the column :)

You can of course use your own convention how to interpret the dimensions of your arrays, but in the long run it will be more consistent to treat them as (y, x).

Upvotes: 1

Related Questions