Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plot semi transparent contour plot over image file using matplotlib

I'd like to plot a transparent contour plot over an image file in matplotlib/pyplot.

Here's what I got so far...

I have a 600x600 pixel square image file test.png that looks like so:

enter image description here

I would like to plot a contour plot over this image (having the image file be 'below' and a semi-transparent version of the contour plot overlaid) using matplotlib and pyplot. As a bonus, the image would be automatically scaled to fit within the current plotting boundaries. My example plotting script is as follows:

from matplotlib import pyplot
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
from matplotlib.colors import BoundaryNorm
from matplotlib.ticker import MaxNLocator
from pylab import *
import numpy as np
import random

# ----------------------------- #

dx, dy = 500.0, 500.0
y, x = np.mgrid[slice(-2500.0, 2500.0 + dy, dy),slice(-2500.0, 2500.0 + dx, dx)]

z = []
for i in x:
    z.append([])
    for j in y:
        z[-1].append(random.uniform(80.0,100.0))

# ----------------------------- #

plot_aspect = 1.2
plot_height = 10.0
plot_width = int(plot_height*plot_aspect)

# ----------------------------- #

pyplot.figure(figsize=(plot_width, plot_height), dpi=100)
pyplot.subplots_adjust(left=0.10, right=1.00, top=0.90, bottom=0.06, hspace=0.30)
subplot1 = pyplot.subplot(111)

# ----------------------------- #

cbar_max = 100.0
cbar_min = 80.0
cbar_step = 1.0
cbar_num_colors = 200
cbar_num_format = "%d"

# ----------

levels = MaxNLocator(nbins=cbar_num_colors).tick_values(cbar_min, cbar_max)
cmap = pyplot.get_cmap('jet')
norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)
pp = pyplot.contourf(x,y,z,levels=levels,cmap=cmap)
cbar = pyplot.colorbar(pp, orientation='vertical', ticks=np.arange(cbar_min, cbar_max+cbar_step, cbar_step), format=cbar_num_format)
cbar.ax.set_ylabel('Color Scale [unit]', fontsize = 16, weight="bold")

# ----------

CS = pyplot.contour(x,y,z, alpha=0.5)

# ----------

majorLocator1   = MultipleLocator(500)
majorFormatter1 = FormatStrFormatter('%d')
minorLocator1   = MultipleLocator(250)

subplot1.xaxis.set_major_locator(majorLocator1)
subplot1.xaxis.set_major_formatter(majorFormatter1)
subplot1.xaxis.set_minor_locator(minorLocator1)

pyplot.xticks(fontsize = 16)
pyplot.xlim(-2500.0,2500.0)

# ----------

majorLocator2   = MultipleLocator(500)
majorFormatter2 = FormatStrFormatter('%d')
minorLocator2   = MultipleLocator(250)

subplot1.yaxis.set_major_locator(majorLocator2)
subplot1.yaxis.set_major_formatter(majorFormatter2)
subplot1.yaxis.set_minor_locator(minorLocator2)

pyplot.yticks(fontsize = 16)
pyplot.ylim(-2500.0,2500.0)

# ----------

subplot1.xaxis.grid()
subplot1.yaxis.grid()

# ----------

subplot1.axes.set_aspect('equal')

# ----------

pyplot.suptitle('Main Title', fontsize = 24, weight="bold")

# ----------

pyplot.xlabel('X [m]', fontsize=16, weight="bold")
pyplot.ylabel('Y [m]', fontsize=16, weight="bold")

# ----------

implot = subplot1.imshow( pyplot.imread('test.png') , interpolation='nearest', alpha=0.5)

# ----------
pyplot.show()
#pyplot.savefig("tmp.png", dpi=100)
pyplot.close()

...but I'm not getting the result I want... instead I just see the contour plot part. Something like:

enter image description here

What should I do in my code to get what I want?

like image 379
HotDogCannon Avatar asked Sep 18 '15 12:09

HotDogCannon


1 Answers

You basically need to do two things, set the extent of the image you want in the background. If you dont, the coordinates are assumed to be pixel coordinates, in this case 0 till 600 for both x and y. So adjust you imshow command to:

implot = subplot1.imshow(pyplot.imread(r'test.png'), interpolation='nearest', 
                         alpha=0.5, extent=[-2500.0,2500.0,-2500.0,2500.0])

If you want to stretch the image to the limits of the plot automatically, you can grab the extent with:

extent = subplot1.get_xlim()+ subplot1.get_ylim()

And pass it to imshow as extent=extent.

Since its the background image, setting the alpha to 0.5 makes it very faint, i would set it to 1.0.

Secondly, you set the alpha of the contour lines, but you probably also (or especially) want to set the alpha of the filled contours. And when you use alpha with filled contours, enabling anti-aliasing reduces artifacts. So change your contourf command to:

pp = pyplot.contourf(x,y,z,levels=levels,cmap=cmap, alpha=.5, antialiased=True)

And since you already create the subplot object yourself, i would advice also using it to do the plotting instead of the pyplot interface, which operates on the currently active axes.

So:

subplot1.contourf()
etc

Instead of:

pyplot.contourf()

With the two changes mentioned above, my result looks like:

enter image description here

like image 134
Rutger Kassies Avatar answered Nov 10 '22 13:11

Rutger Kassies