I am attempting to use matplotlib to plot some figures for a paper I am working on. I have two sets of data in 2D numpy arrays: An ascii hillshade raster which I can happily plot and tweak using:
import matplotlib.pyplot as pp import numpy as np hillshade = np.genfromtxt('hs.asc', delimiter=' ', skip_header=6)[:,:-1] pp.imshow(hillshade, vmin=0, vmax=255) pp.gray() pp.show()
Which gives:
And a second ascii raster which delineates properties of a river flowing across the landscape. This data can be plotted in the same manner as above, however values in the array which do not correspond to the river network are assigned a no data value of -9999. The aim is to have the no data values set to be transparent so the river values overlie the hillshade.
This is the river data, ideally every pixel represented here as 0 would be completely transparent.
Having done some research on this it seems I may be able to convert my data into an RGBA array and set the alpha values to only make the unwanted cells transparent. However, the values in the river array are floats and cannot be transformed (as the original values are the whole point of the figure) and I believe the imshow
function can only take unsigned integers if using the RGBA format.
Is there any way around this limitation? I had hoped I could simply create a tuple with the pixel value and the alpha value and plot them like that, but this does not seem possible.
I have also had a play with PIL
to attempt to create a PNG file of the river data with the no data value transparent, however this seems to automatically scale the pixel values to 0-255, thereby losing the values I need to preserve.
I would welcome any insight anyone has on this problem.
Just mask your "river" array.
e.g.
rivers = np.ma.masked_where(rivers == 0, rivers)
As a quick example of overlaying two plots in this manner:
import numpy as np import matplotlib.pyplot as plt import matplotlib.cm as cm # Generate some data... gray_data = np.arange(10000).reshape(100, 100) masked_data = np.random.random((100,100)) masked_data = np.ma.masked_where(masked_data < 0.9, masked_data) # Overlay the two images fig, ax = plt.subplots() ax.imshow(gray_data, cmap=cm.gray) ax.imshow(masked_data, cmap=cm.jet, interpolation='none') plt.show()
Also, on a side note, imshow
will happily accept floats for its RGBA format. It just expects everything to be in a range between 0 and 1.
An alternate way to do this with out using masked arrays is to set how the color map deals with clipping values below the minimum of clim
(shamelessly using Joe Kington's example):
import numpy as np import matplotlib.pyplot as plt import matplotlib.cm as cm # Generate some data... gray_data = np.arange(10000).reshape(100, 100) masked_data = np.random.random((100,100)) my_cmap = cm.jet my_cmap.set_under('k', alpha=0) # Overlay the two images fig, ax = plt.subplots() ax.imshow(gray_data, cmap=cm.gray) im = ax.imshow(masked_data, cmap=my_cmap, interpolation='none', clim=[0.9, 1]) plt.show()
There as also a set_over
for clipping off the top and a set_bad
for setting how the color map handles 'bad' values in the data.
An advantage of doing it this way is you can change your threshold by just adjusting clim
with im.set_clim([bot, top])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With