set color limits in python colormap - matplotlib

I need to display data from a 2D matrix in a gray colormap, but I need to define it in such a gray scale that white and black are not the colors for the min and max values of the matrix, in order to not saturate the image. What I need is a gray scale colormap with gray levels between 20% and 70%, with at least 20% difference between the levels of gray. Any suggestions?
I'm using the imshow task form matplotlib.
Thanks a lot!

Did you solve your problem?
I guess this is what you want, try this:
all code in pylab mode:
a = np.arange(100).reshape(10,10)
#here is the image with white and black end
imshow(a,cmap=mat.cm.binary)
colorbar()
#we extract only the 0.2-->0.7 part of original colormap and make a new one
#so that the white and black end are removed
rgba_array = mat.cm.binary(np.linspace(0,1,num=10,endpoint=True))
extract_rgba_array_255 = rgba_array[2:8,0:3]
imshow(a,cmap=mat.colors.ListedColormap(extract_rgba_array_255))
colorbar()

You could do this either by creating a custom color map with colors your prefer, or by using the vmin, vmax keywords in imshow to force a larger range on the colorbar than you want to use in your plot.

Related

overlapping constrained 3d subplots

What knobs must I tweak to prevent these problems:
overlapping axes labels
overlapping plots with cropped axes labels
I'm using matplotlib 3.5.1 with the PGF backend. Some solutions for older versions no longer work.
fig, axes = plt.subplots\
(2, 3, constrained_layout=True, subplot_kw=dict(projection="3d"))
#it = np.nditer(axes, flags=["refs_ok","multi_index"])
#for ax in it:
# # Plot the surfaces, add row and column title annotations.
# pass
width = 150 * 0.8 * mm
height = width * 0.65
fig.set_size_inches(width, height)
fig.savefig("something.pgf", dpi=300)
plt.close(fig)
Getting rid of the constrained layout and using plt.subplots_adjust(wspace=<value>, hspace=<value>) worked for me
from matplotlib import pyplot as plt
fig, axes = plt.subplots(nrows=2, ncols=3, subplot_kw=dict(projection="3d"))
plt.subplots_adjust(wspace=0.5,hspace=0.5)
labels_x, labels_y, labels_z = [['x-axis']*3]*2, [['y-axis']*3]*2, [['z-axis']*3]*2
for i in range(len(axes)):
for j in range(len(axes[i])):
axes[i,j].set_xlabel(labels_x[i][j])
axes[i,j].set_ylabel(labels_y[i][j])
axes[i,j].set_zlabel(labels_z[i][j])
plt.show()
While both tight and constrained layouts can be used with 3d projection (mplot3d) it seems that constrained layout does not understand how to pad 3d tick labels, leading to overlapping or trimmed labels. Both layout managers adjust subplot padding and axes size given a fixed figure size. Neither can fit the figure size to the contents. To do so with tight layout, extrapolate the desired figure size from the current figure tight bbox over multiple iterations. When using the constrained layout manager, sum the axes tight bboxes and padding to determine any extraneous space. Tight layout adjusts subplotpars (axes size and figure padding) and supports "h_pad" and "w_pad" parameters. Constrained layout adjusts axes size and supports "wspace", "hspace", "w_pad", and "h_pad" parameters. The tight layout squeezes subplots into a tight group which is then centered in the available space. The constrained layout distributes subplots evenly across all available space. Regardless of the layout manager, if the ticks overlap or are clustered too tightly, switch the tick locator to "MaxNLocator" for some smaller "n".
The root problem is that the 3d projection tick labels are empty until a full canvas draw. The "_draw_disabled" draw performed by the constrained layout manager isn't sufficient to trigger the tick labels. If you trace the axes tight bbox you'll notice they don't include the labels until after a call to "fig.canvas.draw", before then the tick labels are just "Text(0, 0, '')". Be sure to include this call after sizing the figure and then the layout will be constrained as expected. Given a fixed figure width, set the height based on aesthetics or sum the axes tight bboxes with padding to determine the minimum possible height.

Seaborn Heatmap Colorbar Location

The cbar_kws argument of seaborn.heatmap accepts the parameters that fig.colobar accepts.
Is there a way to adjust the placement of the colorbar, simply to adjust the location to the left (especially when the correlation matrix is adjusted to have only a lower triangle).
I can adjust the labels by overriding the tick labels. As of now I still have to adjust the upper-right borders in post-processing, but it would make things much easier if I didn't have to edit the color bar as well.
heatmap accepts a cbar_ax argument; if you want to specify the position of the colorbar, the best thing to do is to set up the figure how you want it and then pass the specific axes.
You can also move axes around after plotting through normal matplotlib commands.

How to plot images of different size at the same resolution?

A collection of images are plotted as follow:
figure(num=None, figsize=(16, 14), dpi=300)
k=1
for i in range(1,10):
for j in range(1,6):
subplot(9,5,k,xticks=[],yticks=[])
imshow(rgb_chromosomes[k-1],interpolation='nearest')
k=k+1
It is visible that from a image to an other, pixels are not the same size.
How to fix that issue?
Use interpolation= 'bilinear' and subsample the result with regular spacing (say take every other four pixel, this depends on the final pixel size you want) and form a tiny image. Then magnify this tiny image with 'nearest' interpolation.
You can also keep the 'nearest' setting for the first interpolation, but the result will look ugly.
so, from image to image are the pixels different sizes? From context, I am guessing that these are all snippets from the same image/imaging conditions and you want the scale to be the same in all of them.
Something like:
fig, ax_lst = plt.subplots(9, 6) # better way to set up your axes
for k, ax in enumerate(ax_lst.ravel()):
ax.imshow(rgb_chromosomes[k], interpolation='none')
ax.set_xlim([0, max_image_width])
ax.set_ylim([0, max_image_height])
ax.set_frame_on(False)

Alpha Channel in gnuplot palette

Is there a way to define an alpha channel in a palette in either gnuplot or matplotlib?
I'm trying to combine two scalar fields into one plot and so far came up with nothing.
There is a way to set line colors with an alpha channel in the development version (4.7) of gnuplot. You can set the alpha channel as the high bits of an RGB color specification. For example,
plot x lc rgb '#AAAAAAAA'
draws a translucent gray line.
However, I'm not sure there is a way to do this for a palette.

Matplotlib difference between two images

I have images (4000x2000 pixels) that are derived from the same image, but with subtle differences in less than 1% of the pixels. I'd like to plot the two images side-by-side and highlight the regions of the array's that are different (by highlight I mean I want the pixels that differ to jump out, but still display the color that matches their value. I've been using rectangles that are unfilled to outline the edges of such pixels so far. I can do this very nicely in small images (~50x50) with:
fig=figure(figsize=(20,15))
ax1=fig.add_subplot(1,2,1)
imshow(image1,interpolation='nearest',origin='lower left')
colorbar()
ax2=fig.add_subplot(122,sharex=ax1, sharey=ax1)
imshow(image2,interpolation='nearest',origin='lower left')
colorbar()
#now show differences
Xspots=im1!=im2
Xx,Xy=nonzero(Xspots)
for x,y in zip(Xx,Xy):
rect=Rectangle((y-.5,x-.5),1,1,color='w',fill=False,ec='w')
ax1.add_patch(rect)
ax2.add_patch(rect)
However this doesn't work so well when the image is very large. Strange things happen, for example when I zoom in the patch disappears. Also, this way sucks because it takes forever to load things when I zoom in/out.
I feel like there must be a better way to do this, maybe one where there is only one patch that determines where all of the things are, rather than a whole bunch of patches. I could do a scatter plot on top of the imshow image, but I don't know how to fix it so that the points will stay exactly the size of the pixel when I zoom in/out.
Any ideas?
I would try something with the alpha channel:
import copy
N, M = 20, 40
test_data = np.random.rand(N, M)
mark_mask = np.random.rand(N, M) < .01 # mask 1%
# this is redundant in this case, but in general you need it
my_norm = matplotlib.colors.Normalize(vmin=0, vmax=1)
# grab a copy of the color map
my_cmap = copy.copy(cm.get_cmap('cubehelix'))
c_data= my_cmap(my_norm(test_data))
c_data[:, :, 3] = .5 # make everything half alpha
c_data[mark_mask, 3] = 1 # reset the marked pixels as full opacity
# plot it
figure()
imshow(c_data, interpolation='none')
No idea if this will work with your data or not.