Matplotlib imshow zoom function? - python

I have several (27) images represented in 2D arrays that I am viewing with imshow(). I need to zoom in on the exact same spot in every image. I know I can manually zoom, but this is tedious and not precise enough. Is there a way to programmatically specify a specific section of the image to show instead of the entire thing?

You could use plt.xlim and plt.ylim to set the region to be plotted:
import matplotlib.pyplot as plt
import numpy as np
data=np.arange(9).reshape((3,3))
plt.imshow(data)
plt.xlim(0.5, 1.5)
plt.ylim(0.5,1.5)
plt.show()

If you do not need the rest of your image, you can define a function that crop the image at the coordinates you want and then display the cropped image.
Note: here 'x' and 'y' are the visual x and y (horizontal axis and vertical axis on the image, respectively), meaning that it is inverted compared to the real x (row) and y (column) of the NumPy array.
import scipy as sp
import numpy as np
import matplotlib.pyplot as plt
def crop(image, x1, x2, y1, y2):
"""
Return the cropped image at the x1, x2, y1, y2 coordinates
"""
if x2 == -1:
x2=image.shape[1]-1
if y2 == -1:
y2=image.shape[0]-1
mask = np.zeros(image.shape)
mask[y1:y2+1, x1:x2+1]=1
m = mask>0
return image[m].reshape((y2+1-y1, x2+1-x1))
image = sp.lena()
image_cropped = crop(image, 240, 290, 255, 272)
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax1.imshow(image)
ax2.imshow(image_cropped)
plt.show()

Related

matplotlib plot_surface 3D depth values

I used the following code to get the 3D depth projection of the shown 2 images. I need the max and minimum depth values, and the x and y coordinates of these max and min depth values.
Is there a function/method from which I can get this information? Even if it will be using a library other than matplotlib.
import cv2
import numpy as np
import math
import scipy.ndimage as ndimage
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
image2=cv2.imread('D:/Post_Grad/STDF/iPython_notebooks/2228.jpg')
image2 = image2[:,:,1] # get the first channel
rows, cols = image2.shape
x, y= np.meshgrid(range(cols), range(rows)[::-1])
blurred = ndimage.gaussian_filter(image2,(5, 5))
fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(221)
ax.imshow(image2, cmap='gray')
ax = fig.add_subplot(222, projection='3d')
ax.elev= 5
f1=ax.plot_surface(x,y,image2, cmap=cm.jet)
ax = fig.add_subplot(223)
ax.imshow(blurred, cmap='gray')
ax = fig.add_subplot(224, projection='3d')
ax.elev= 5
f2=ax.plot_surface(x,y,blurred, cmap=cm.jet)
plt.show()
max depth and min depth are just maximum and minimum pixel values of image. And you can easily find the values via np.max(image2),np.min(image2) etc..
Also coordinates can be found via a simple function
def getCoord(image,val):
coords = []
for i in range(image.shape[0]):
for j in range(image.shape[1]):
if image[i][j] == val:
coords.append([i,j])
return coords
so getCoord(image2,np.max(image2)) will return all highest pixel coordinates in image2 (it can be more than 1) , getCoord(blurred,np.min(blurred)) will return all lowest pixel coordinates in blurred etc..

How would you plot this 3D visualization in Python?

I want to take an image and represent the dimensions of the image as spatial coordinates and the pixel values as the 3rd dimension represented by height. Here is an example of what I would like to do.
How would you do this with matplotlib or plotly?
Assuming the image is in HWC format, is gray-scale (i.e. C=1) and is a numpy array, something along the lines of:
import matplotlib.pyplot as plt
import numpy as np
img = np.random.uniform(size=(10,10,1))
X = np.arange(0, img.shape[1])
Y = np.arange(0, img.shape[0])
X, Y = np.meshgrid(X, Y)
Z = img.squeeze()
# Plot the surface.
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z)
Inspired by: this.
Hope this helps!

How to plot only some cells with certain values of an array and others not with matplotlib.pyplot?

I have an image that consists of float values and another one that consist only of ones and zeros. I want to plot the second image over the first one, but I only want to plot the ones from the second image. The zeros shall not be plotted.
Ì have tried the following code and I also changed the alpha of y to 1. The problem is, that either the red windows of y are changed from x (alpha of y = 0.5), or one can not even see the plots of x (alpha of y=1).
import matplotlib.pyplot as plt
import numpy as np
x = np.random.random(size=(20,20))
y = np.random.randint(2, size=(20,20))
fig = plt.figure()
plt.imshow(x, cmap="Greys", alpha = 0.5)
plt.imshow(y, cmap="Reds", alpha = 0.5)
plt.show()
How can I only plot the ones of y?
UPDATE:
Thank you for your answers! But this is not want I am looking for. I will explain again:
The result should be something like: x as background and every position, where y is 1, should be colored pure red.
Following the approach in this answer linked by #ImportanceOfBeingEarnest, the exact solution in your case would look like below. Here, np.ma.masked_where will mask your y array at places where it is 0. The resulting array will only contain 1.
EDIT: The problem of overlaying seems to stem from the choice of cmap. If you don't specify the cmap for the y, you can clearly see below that indeed only 1's are plotted and overlaid on the top of x. In order to have a discrete color (red in your case), you can create a custom color map
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import colors
x = np.random.random(size=(20,20))
y = np.random.randint(2, size=(20,20))
y_new =np.ma.masked_where(y==0, y)
cmap = colors.ListedColormap(['red'])
fig = plt.figure()
plt.imshow(x, cmap="Greys", alpha = 0.5)
plt.imshow(y_new, cmap=cmap, alpha=1)
plt.show()
We can inverse "The result should be [..] x as background and every position, where y is 1, should be colored pure red.", namely to just plot x, masked by y and set the background to red.
import matplotlib.pyplot as plt
import numpy as np
y = np.random.randint(2, size=(20,20))
x = np.random.random(size=(20,20))
X = np.ma.array(x, mask=y)
fig = plt.figure()
plt.imshow(X, cmap="Greys")
plt.gca().set_facecolor("red")
plt.show()
There are of course related Q&As like
Matplotlib imshow: how to apply a mask on the matrix or
How can I plot NaN values as a special color with imshow in matplotlib?
and there is also an example on the matplotlib page: Image masked

How to save a greyscale matplotlib plot to numpy array

For example, I plot a figure using matplotlib as follows:
plt.figure(figsize=(10,10))
plt.imshow(output_fig, zorder=0,cmap="gray")
plt.scatter(x,y,color='k')
if I use:
plt.savefig(figname,fotmat=figtype)
I will save it as a figure file. However, I want so save it to a matrix, or numpy array, such that each element saves the scale value of each pixel of the figure.
How can I do this?
I find solutions saving the RGB values. But I hope to save a greyscale figure.
Thank you all for helping me!
Once you have a ploted data (self contained example bellow):
import numpy as np
import matplotlib.pyplot as plt
from skimage import data, color
img = data.camera()
x = np.random.rand(100) * img.shape[1]
y = np.random.rand(100) * img.shape[0]
fig = plt.figure(figsize=(10,10))
plt.imshow(img,cmap="gray")
plt.scatter(x, y, color='k')
plt.ylim([img.shape[0], 0])
plt.xlim([0, img.shape[1]])
The underlying data can be recovered as array by using fig.canvas (the matplotlib's canvas). First trigger its drawing:
fig.canvas.draw()
Get the data as array:
width, height = fig.get_size_inches() * fig.get_dpi()
mplimage = np.fromstring(fig.canvas.tostring_rgb(), dtype='uint8').reshape(height, width, 3)
If you want your array to be the same shape as the original image you will have to play with figsize and dpi properties of plt.figure().
Last, matplotlib returns an RGB image, if you want it grayscale:
gray_image = color.rgb2gray(mplimage)

Is it possible to do additive blending with matplotlib?

When dealing with overlapping high density scatter or line plots of different colors it can be convenient to implement additive blending schemes, where the RGB colors of each marker add together to produce the final color in the canvas. This is a common operation in 2D and 3D render engines.
However, in Matplotlib I've only found support for alpha/opacity blending. Is there any roundabout way of doing it or am I stuck with rendering to bitmap and then blending them in some paint program?
Edit: Here's some example code and a manual solution.
This will produce two partially overlapping random distributions:
x1 = randn(1000)
y1 = randn(1000)
x2 = randn(1000) * 5
y2 = randn(1000)
scatter(x1,y1,c='b',edgecolors='none')
scatter(x2,y2,c='r',edgecolors='none')
This will produce in matplotlib the following:
As you can see, there are some overlapping blue points that are occluded by red points and we would like to see them. By using alpha/opacity blending in matplotlib, you can do:
scatter(x1,y1,c='b',edgecolors='none',alpha=0.5)
scatter(x2,y2,c='r',edgecolors='none',alpha=0.5)
Which will produce the following:
But what I really want is the following:
I can do it manually by rendering each plot independently to a bitmap:
xlim = plt.xlim()
ylim = plt.ylim()
scatter(x1,y1,c='b',edgecolors='none')
plt.xlim(xlim)
plt.ylim(ylim)
scatter(x2,y2,c='r',edgecolors='none')
plt.xlim(xlim)
plt.ylim(ylim)
plt.savefig(r'scatter_blue.png',transparent=True)
plt.savefig(r'scatter_red.png',transparent=True)
Which gives me the following images:
What you can do then is load them as independent layers in Paint.NET/PhotoShop/gimp and just additive blend them.
Now ideal would be to be able to do this programmatically in Matplotlib, since I'll be processing hundreds of these!
If you only need an image as the result, you can get the canvas buffer as a numpy array, and then do the blending, here is an example:
from matplotlib import pyplot as plt
import numpy as np
fig, ax = plt.subplots()
ax.scatter(x1,y1,c='b',edgecolors='none')
ax.set_xlim(-4, 4)
ax.set_ylim(-4, 4)
ax.patch.set_facecolor("none")
ax.patch.set_edgecolor("none")
fig.canvas.draw()
w, h = fig.canvas.get_width_height()
img = np.frombuffer(fig.canvas.buffer_rgba(), np.uint8).reshape(h, w, -1).copy()
ax.clear()
ax.scatter(x2,y2,c='r',edgecolors='none')
ax.set_xlim(-4, 4)
ax.set_ylim(-4, 4)
ax.patch.set_facecolor("none")
ax.patch.set_edgecolor("none")
fig.canvas.draw()
img2 = np.frombuffer(fig.canvas.buffer_rgba(), np.uint8).reshape(h, w, -1).copy()
img[img[:, :, -1] == 0] = 0
img2[img2[:, :, -1] == 0] = 0
fig.clf()
plt.imshow(np.maximum(img, img2))
plt.subplots_adjust(0, 0, 1, 1)
plt.axis("off")
plt.show()
the result:
This feature is now supported by my matplotlib backend https://github.com/anntzer/mplcairo (master only):
import matplotlib; matplotlib.use("module://mplcairo.qt")
from matplotlib import pyplot as plt
from mplcairo import operator_t
import numpy as np
x1 = np.random.randn(1000)
y1 = np.random.randn(1000)
x2 = np.random.randn(1000) * 5
y2 = np.random.randn(1000)
fig, ax = plt.subplots()
# The figure and axes background must be made transparent.
fig.patch.set(alpha=0)
ax.patch.set(alpha=0)
pc1 = ax.scatter(x1, y1, c='b', edgecolors='none')
pc2 = ax.scatter(x2, y2, c='r', edgecolors='none')
operator_t.ADD.patch_artist(pc2) # Use additive blending.
plt.show()

Categories

Resources