highlight regions of no data in a Python imshow plot - python

I am producing an imshow plot in Python.
In the final plot, I have strips/columns of data, between which there is no data at all - kind of like a barcode.
At the moment, where I have no data, I have just set all values to zero. The color of these regions of no data is therefore whatever colour represents zero in my colorbar - green in my case.
What I really want is for these columns/strips just to be white, and to make to really clear that these are regions of NO data.
I realise that I could change the colorbar so that the zero is white, but I really want to distinguish the regions of no data from any zeros that might be in the data.
Thank you.

try setting those values to np.nan ( or float('nan')); you may also want to pass interpolation='nearest' to imshow as an argument.

Related

Why is part of my contour plot showing white?

I am using Python's matplotlib.pyplot.contourf to create a contour plot of my data with a color bar. I have done this successfully countless times, even with other layers of the same variable. However, when the values get small (on the order of 1E-12), parts of the contour show up white. The white color does not show up in the color bar either. Does anyone know what causes this and how to fix this? The faulty contour is attached below.
a1 = plt.contourf(np.linspace(1,24,24),np.linspace(1,20,20),np.transpose(data[:,:,15]))
plt.colorbar(a1)
plt.show()
tl;dr
Given the new information, matplotlib couldn't set the right number of levels (see parameters in the documentation) for your data leaving data unplotted. To fix that you need to tell matplotlib to extend the limits with either plt.contourf(..., extend="max") or plt.contourf(..., extend="both")
Extensive answer
There are a few reasons why contourf() is showing white zones with a colormap that doesn't include white.
NaN values
NaN values are never plotted.
Masked data
If you mask data before plotting, it won't appear in the plot. But you should know if you masked your data.
Although, you may have unnoticed mask your data if you use something like Tick locator = LogLocator().
Matplotlib couldn't set the right levels for your data
Sometimes matplotlib doesn't set the right levels, leaving some of your data without plotting.
To fix that you can user plt.contourf(..., extend=EXTENDS) where EXTENDS can be "neither", "both", "min", "max"
Coarse grid
contourf plots whitespace over finite data. Past answers do not correct
One remark, white section in the plot can also occur if the X and Y vectors data points are not equally spaced. In that case best to use function tricontourf().
I was facing the same problem recently, when there was data available even higher/lower than the levels I have set. So, the plt.contourf fills the contours exclusively given by you, and it neglects any other higher or lower values present in your data.
I solved this by adding a key word argument extend="both", which for your case would be something like this:
a1 = plt.contourf(np.linspace(1,24,24),np.linspace(1,20,20),np.transpose(data[:,:,15]), extend="both")
or in general form:
a1 = plt.contourf(x,y,variable[:,:,15],extend="both")
By doing this, you're instructing the module to plot the higher(/lower) values according to the highest(/lowest) filled contour.
If you want only to extend in the lower or higher range, you can change the keyword argument to
extend="min" or extend ="max"

masking an imshow, or imshow with RGBA

A dataframe, which should be considered a matrix, contains values 0, 1, 2.
With imshow, I get a nice image. I can use a cmap with 3 discrete colors.
I want to highlight few rows, so visually I want to have those rows with alpha=1 and the other with alpha=0.1 .
Should I create the image myself, creating a matrix with RGBA entries?
Is there a more straight-forward way?
With Kind Regards,
Oren
I found a nice way to do that with Layer Images.
https://matplotlib.org/gallery/images_contours_and_fields/layer_images.html#sphx-glr-gallery-images-contours-and-fields-layer-images-py
Apparently I can imshow the matrix with the intended highlighted colors. And on top of that, add a imshow with values that are either the same, where I want to highlight, or white otherwise. I then make sure to have alpha=0.5 for example, for the second imshow.

Set colorbar range for an mlab surface

I've looked around on the internet but I haven't found a solution.
I'm plotting different surfaces in the same figure with mlab.pipeline.surface(mesh). I'd like to plot them with the same colorbar.
In this figure the right part of the surfaces is at the same temerature, but since the colorbar range is different for each surface the color is different.
I think there should be something like matplotlib.tricontourf(...,levels=...) to fix the colorbar range.
How can I set the colorbar range using mlab?
You can take a look at the built-in documentation of mlab. From help(mlab.pipeline.surface):
:vmax: vmax is used to scale the colormap.
If None, the max of the data will be used
:vmin: vmin is used to scale the colormap.
If None, the min of the data will be used
In other words, you need to compute the global minimum and global maximum of your data across every dataset, and set the same extrema for every surface of yours. Note that you can do the exact same (with the exact same keywords even) with matplotlib's 3d plotting methods.
Tangential note: your use case might also benefit from some transparency, since your surfaces are likely to overlap one another which might hinder the visualization. The two keywords that come to mind are opacity and perhaps (albeit less likely) transparent:
:opacity: The overall opacity of the vtk object. Must be a float.
Default: 1.0
:transparent: make the opacity of the actor depend on the
scalar.

Scatter plot and contour plot with same colors

Is it possible to force plt.scatter into the same color levels as plt.contourf and plt.contour? For example, I have code that makes a plot like this:
to make the first subplot, I use
cs=m[0].scatter(xs,ys,c=obsData,cmap=plt.cm.jet)
m.colorbar(cs)
To make the second subplot, I use
cs2=m[1].contourf(x,y,areaData,cmap=cs.cmap)
And for each subsequent subplot, I use
m[ind].contourf(x,y,areaData,cmap=cs.cmap,levels=cs2.levels
where areaData is recalculated within a loop.
My question is, how can I force the first subplot to have the same colors as the other subplots? I am looking for an equivalent to the levels=cs2.levels keyword argument.
As you noted in a comment, your scatter and contour data are not directly related, but you want to display them on the same colormap.
I suggest setting a common colour span that contains both sets of data. Since obsData refers to the scatter points and areaData to the contours, I'd set
vmin,vmax = (fun(np.concatenate([obsData,areaData])) for fun in (np.min,np.max))
to determine the span of the collected data set (obviously, to be generalized for multiple input data sets). These can be passed to scatter and contourf to set the limits of the colour mapping:
cs = m[0].scatter(xs,ys,c=obsData,cmap=plt.cm.viridis,vmin=vmin,vmax=vmax)
cs2 = m[1].contourf(x,y,areaData,cmap=cs.cmap,vmin=vmin,vmax=vmax)
Some manual increase of the span might be in order to obtain a pretty result.
Note that I changed the colormap to viridis. If you really want to fairly represent your data, this should be your first step.

How do I convert (or scale) axis values and redefine the tick frequency in matplotlib?

I am displaying a jpg image (I rotate this by 90 degrees, if this is relevant) and of course
the axes display the pixel coordinates. I would like to convert the axis so that instead of displaying the pixel number, it will display my unit of choice - be it radians, degrees, or in my case an astronomical coordinate. I know the conversion from pixel to (eg) degree. Here is a snippet of what my code looks like currently:
import matplotlib.pyplot as plt
import Image
import matplotlib
thumb = Image.open(self.image)
thumb = thumb.rotate(90)
dpi = plt.rcParams['figure.dpi']
figsize = thumb.size[0]/dpi, thumb.size[1]/dpi
fig = plt.figure(figsize=figsize)
plt.imshow(thumb, origin='lower',aspect='equal')
plt.show()
...so following on from this, can I take each value that matplotlib would print on the axis, and change/replace it with a string to output instead? I would want to do this for a specific coordinate format - eg, rather than an angle of 10.44 (degrees), I would like it to read 10 26' 24'' (ie, degrees, arcmins, arcsecs)
Finally on this theme, I'd want control over the tick frequency, on the plot. Matplotlib might print the axis value every 50 pixels, but I'd really want it every (for example) degree.
It sounds like I would like to define some kind of array with the pixel values and their converted values (degrees etc) that I want to be displayed, having control over the sampling frequency over the range xmin/xmax range.
Are there any matplotlib experts on Stack Overflow? If so, thanks very much in advance for your help! To make this a more learning experience, I'd really appreciate being prodded in the direction of tutorials etc on this kind of matplotlib problem. I've found myself getting very confused with axes, axis, figures, artists etc!
Cheers,
Dave
It looks like you're dealing with the matplotlib.pyplot interface, which means that you'll be able to bypass most of the dealing with artists, axes, and the like. You can control the values and labels of the tick marks by using the matplotlib.pyplot.xticks command, as follows:
tick_locs = [list of locations where you want your tick marks placed]
tick_lbls = [list of corresponding labels for each of the tick marks]
plt.xticks(tick_locs, tick_lbls)
For your particular example, you'll have to compute what the tick marks are relative to the units (i.e. pixels) of your original plot (since you're using imshow) - you said you know how to do this, though.
I haven't dealt with images much, but you may be able to use a different plotting method (e.g. pcolor) that allows you to supply x and y information. That may give you a few more options for specifying the units of your image.
For tutorials, you would do well to look through the matplotlib gallery - find something you like, and read the code that produced it. One of the guys in our office recently bought a book on Python visualization - that may be worthwhile looking at.
The way that I generally think of all the various pieces is as follows:
A Figure is a container for all the Axes
An Axes is the space where what you draw (i.e. your plot) actually shows up
An Axis is the actual x and y axes
Artists? That's too deep in the interface for me: I've never had to worry about those yet, even though I rarely use the pyplot module in production plots.

Categories

Resources