2

I want to make a plot of 2D data where the values are determined from bilinear interpolation. As an initial test, I decided to just use the example from the wikipedia page: http://en.wikipedia.org/wiki/File:Bilininterp.png

However, in general, I would need this to work for any set of data, so a solution that works just for this special, specific case is not useful. A slightly more complex example is in the data below, commented out as "Another example".

Here are the few tries that I've made so far, with comments that mention why it doesn't work:

import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.pyplot as plt
from scipy.interpolate import griddata

# http://en.wikipedia.org/wiki/File:Bilininterp.png
xi = np.array([0.0, 1.0])
yi = np.array([0.0, 1.0])
zi = np.array([[0.0, 1.0], [1.0, 0.5]])

# Another example
#xi = np.array([0.0, 0.25, 1.0])
#yi = np.array([0.0, 0.75, 1.0])
#zi = np.array([[0.0, 0.5, 1.0], [0.5, 0.7, 0.5], [1.0, 1.0, 1.0]])

# I want 20 "levels" to be shown
contour_breaks = 20
ticks = np.linspace(zi.min(), zi.max(), contour_breaks, endpoint=True)

# Attempt #1 (contour does not use bilinear interpolation)
fig = plt.figure()
axes = fig.add_subplot(111, aspect='equal')
axes.contour(xi, yi, zi, ticks[1:-1], colors='k')
fill = axes.contourf(xi, yi, zi, ticks, cmap=cm.jet)
fig.colorbar(fill, ticks=ticks)

# Attempt 2 (colors are weird for imshow -- they don't seem to be jet.  I can't
#            make it use ticks to make constant color zones/levels.  The contour
#            lines are the same as before (no bilinear).  Also, you cannot input
#            xi and yi, so the data would have to be interpolated to a regular
#            grid - see the second set of example data above for an example
#            where the data isn't regularly spaced)
fig = plt.figure()
axes = fig.add_subplot(111, aspect='equal')
axes.contour(xi, yi, zi, ticks[1:-1], colors='k')
fill = axes.imshow(zi, interpolation='bilinear', cmap=cm.jet,
                   extent=(0.,1.,0.,1.))
fig.colorbar(fill, ticks=ticks)

# Attempt 3 (griddata doens't do bilinear interpolation)
fig = plt.figure()
axes = fig.add_subplot(111, aspect='equal')
xi1, yi1 = np.meshgrid(xi, yi)
xi1 = xi1.flatten()
yi1 = yi1.flatten()
zi1 = zi.flatten()
xi2 = np.linspace(0., 1., 100)
yi2 = np.linspace(0., 1., 100)
zi2 = griddata((xi1, yi1), zi1, (xi2[None,:], yi2[:,None]), method='linear')
axes.contour(xi2, yi2, zi2, ticks[1:-1], colors='k')
fill = axes.contourf(xi2, yi2, zi2, ticks, cmap=cm.jet)
fig.colorbar(fill, ticks=ticks)

# Show the plots
plt.show()
Scott B
  • 2,542
  • 7
  • 30
  • 44
  • What is your question? – tacaswell Sep 11 '13 at 21:13
  • also, I think 'linear' interpolation on 2D data is bilinear. – tacaswell Sep 11 '13 at 21:14
  • I originally thought that linear interpolation on 2D would be bilinear as well. But bilinear is not, actually, linear since it is result of multiplying two linear functions. If you look at the plots, the results are not correct (no the same as the linked images from wikipedia, which I've confirmed are correct). My question is how to make this plot correctly. – Scott B Sep 11 '13 at 21:52
  • try `map_coordinates` http://stackoverflow.com/questions/15057970/scipy-map-coordinates-bilinear-interpolation-compared-to-interp-and-idl-interpol – tacaswell Sep 11 '13 at 23:19
  • http://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.interpolation.map_coordinates.html – tacaswell Sep 11 '13 at 23:22

1 Answers1

2

This one seems to work.

import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.pyplot as plt
from scipy.interpolate import interp2d

# http://en.wikipedia.org/wiki/File:Bilininterp.png
xi = np.array([0.0, 1.0])
yi = np.array([0.0, 1.0])
zi = np.array([[0.0, 1.0], [1.0, 0.5]])

# Another example
xi = np.array([0.0, 0.25, 1.0])
yi = np.array([0.0, 0.75, 1.0])
zi = np.array([[0.0, 0.5, 1.0], [0.5, 0.7, 0.5], [1.0, 1.0, 1.0]])

# I want 20 "levels" to be shown
contour_breaks = 20
ticks = np.linspace(zi.min(), zi.max(), contour_breaks, endpoint=True)

# Attempt 4 (interp2d does to correct bilinear interpolation)
fig = plt.figure()
axes = fig.add_subplot(111, aspect='equal')
f = interp2d(xi, yi, zi, kind='linear')
xi2 = np.linspace(0., 1., 100)
yi2 = np.linspace(0., 1., 100)
zi2 = f(xi2, yi2)
axes.contour(xi2, yi2, zi2, ticks[1:-1], colors='k')
fill = axes.contourf(xi2, yi2, zi2, ticks, cmap=cm.jet)
fig.colorbar(fill, ticks=ticks)

# Show the plots
plt.show()
Scott B
  • 2,542
  • 7
  • 30
  • 44
  • what is the purpose of ticks[1:-1] there? is it equivalent to level? – Azam Jan 21 '22 at 04:50
  • The ticks are a list, so this excludes the first and last point, which are the minimum and maximum points in the Z direction. The 4th parameters to the contour function is where to draw the levels out, so there is no reason to draw them at the min and max points. – Scott B Jan 22 '22 at 00:24