Skip to content Skip to sidebar Skip to footer

Matplotlib And Apect Ratio Of Geographical-data Plots

I process geographical information and present the results using matplotlib. All input is lattitude/longitude [degree]. I convert into x/y [meter] for my calculations. And I prese

Solution 1:

It seems I found the solution. And I found it here: How can I set the aspect ratio in matplotlib?

import math
import matplotlib.pyplot as plt
import numpy as np

w=1/math.cos(math.radians(60.0))
plt_area=[0,w,59.5,60.5] #square area

a=np.zeros(shape=(300,300))

fig = plt.figure()
ax = fig.add_subplot(111)

ax.imshow(a)

plt.grid(False)
ax.axis(plt_area)
fig   = plt.gcf()
fig.set_size_inches(8,8)
ax.set_aspect(w)
fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)

plt.show()

Solution 2:

In matplotlib I usually change the figure size like this:

import matplotlib.pyplot as plt

plt.clf()
fig     = plt.figure()
fig_p   = plt.gcf()
fig_p.set_size_inches(8, 8)    # x, y

However this sets the dimensions for the figure outer dimensions, not the plot area. You can change the plot area relative to the figure size given in ratios of the total figure size lengths of x and y respectively:

fig.subplots_adjust(left=0.1, right=0.9, bottom=0.1, top=0.9)

As long as the the relative ratios stay symmetrically the aspect ratio should be the same for the plot are.

Example 1:

plt.clf()
fig     = plt.figure()
fig_p   = plt.gcf()
fig_p.set_size_inches(5, 5)    # x, y for figure canvas# Relative distance ratio between origin of the figure and max extend of canvas
fig.subplots_adjust(left=0.2, right=0.8, bottom=0.2, top=0.8)

ax1   = fig.add_subplot(111)
xdata = [rand()*10 for i in xrange(100)]
ydata = [rand()*1  for i in xrange(100)]
ax1.plot(xdata, ydata, '.b', )
ax1.set_xlabel('Very Large X-Label', size=30)
plt.savefig('squareplot.png', dpi=96)

$.subplot_adjust$ overwrites the default space between figure size and plot extend

Example 2:

fig.subplots_adjust(left=0.0, right=1.0, bottom=0.0, top=1.0)

Plot area fills the figure size completely:

No spacing between figure size and plot area

Solution 3:

Don't try to fix this by fiddling fig.set_size_inches() or fig.subplots_adjust() or by changing your data; instead use a Mercator projection.

You can get a quick and dirty Mercator projection by using an aspect ratio of the reciprocal of the cosine of the mean latitude of your data. This is "pretty good" for data contained in about 1 degree of latitude, which is about 100 km. (You have to decide if, for your application, this is "good enough". If it isn't, you really have to consider some serious geographical projection libraries...)

Example:

from math import cos, radians
import matplotlib.pyplot as plt
import numpy as np

# Helsinki 60.1708 N, 24.9375 E# Helsinki (lng, lat)
hels = [24.9375, 60.1708]
# a point 100 km directly north of Helsinki
pt_N = [24.9375, 61.0701]
# a point 100 km east of Helsinki along its parallel
pt_E = [26.7455, 60.1708]

coords = np.array([pt_N, hels, pt_E])

plt.figure()
plt.plot(coords[:,0], coords[:,1])# either of these will estimate the "central latitude" of your data# 1) do the plot, then average the limits of the y-axis    
central_latitude = sum(plt.axes().get_ylim())/2.
# 2) actually average the latitudes in your data
central_latitude = np.average(coords, 0)[1]

# calculate the aspect ratio that will approximate a # Mercator projection at this central latitude 
mercator_aspect_ratio = 1/cos(radians(central_latitude))

# set the aspect ratio of the axes to that
plt.axes().set_aspect(mercator_aspect_ratio)

plt.show()

I picked Helsinki for the example since at that latitude the aspect ratio is almost 2... because two degrees of longitude is the about same distance as one degree of latitude.

To really see this work: a) run the above, b) resize the window. Then comment out the call to set_aspect() and do the same. In the first case, the correct aspect ratio is maintained, in the latter you get nonsensical stretching.

The points 100km north and east of Helsinki were calculated/confirmed by the EXCELLENT page calculating distances between lat/lng points at Movable Type Scripts

Post a Comment for "Matplotlib And Apect Ratio Of Geographical-data Plots"