Matplotlib - Aligning grids - python

I'm plotting histograms below the images using a Matplotlib.GridSpec as we can see on code below:
import imageio
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import gridspec
plt.close('all')
plt.style.use('ggplot')
img = imageio.imread('imageio:page.png')
y = np.bincount(img.ravel(), minlength=256)
y = y/np.sum(y)
x = np.arange(len(y))
fig = plt.figure(figsize=(6,8))
gs = gridspec.GridSpec(2, 1, height_ratios=[6,1], width_ratios=[1])
ax0 = plt.subplot(gs[0])
ax0.imshow(img, cmap='gray')
ax0.xaxis.set_visible(False)
ax0.yaxis.set_visible(False)
ax1 = plt.subplot(gs[1])
ax1.fill_between(x, y)
ax1.yaxis.set_visible(False)
ax1.set_xlim([0,255])
fig.tight_layout()
plt.show()
When we pick the correct figure size the image is nicely aligned as in
But if the figure size isn't correctly chosen the histogram is shown too large for image size or too far away as we can see below
or
Is there any way to tell matplotlib to align correctly, that is, put the histogram a fixed amount of pixels below the image and never stretch the histogram larger than image width.

Related

Manipulate axis in matplotlib to invert the axis conditionally

I would like to plot some coordinates on top of an image.
I want to invert the axis for the said coordinates but not for the image.
But with my code, the axis gets inverted for both the image and the coordinates.
This is my code:
import numpy as np
from matplotlib import pyplot as plt
plt.rcParams["figure.figsize"] = [10, 10]
plt.rcParams["figure.autolayout"] = True
im = plt.imread("bird.png")
fig, ax = plt.subplots()
im = ax.imshow(im, extent=[0, 720, 0, 576])
x = np.array(range(300))
fig.gca().invert_xaxis()
fig.gca().invert_yaxis()
ax.scatter(x_coords_true, y_coords_true, color='red')
ax.scatter(x_coords_pred, y_coords_pred, color='yellow')
plt.show()
Can you help me modify the code to get the result I am expecting, please?

How can I use SymLogNorm with matplotlib but still have colorbar appear linear?

Is there a way to use SymLogNorm with imshow, but make the colorbar basically stretch the colors so that the colorbar actually appears linear?
Below is a short code
from pylab import *
import numpy as np
from matplotlib.colors import SymLogNorm
data = np.random.uniform(low=-10, high=10, size=(10,10))
norm = SymLogNorm(2,vmin=-10,vmax=10)
fig, axes = plt.subplots()
im = axes.imshow(data,extent=[-10,10,-10,10],cmap=plt.cm.jet,norm=norm)
cb = fig.colorbar(im)
that produces this
I basically want this image, but want to stretch the colorbar so the ticks appear linear, not log.

Way to change only the width of marker in scatterplot but not height?

I want to make a scatterplot with marker type as rectange (not square), such that width is more than height. With the "s" I can control the overall size of the marker but it increases in both dimension.
I can not directly pass height and width as these are unknown properties of scatter.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.scatter(np.arange(1,6), np.random.normal(size=5), marker='s', s=16)
Try the following snippet.
import numpy as np
import matplotlib.pyplot as plt
width = 60
height = 30
verts = list(zip([-width,width,width,-width],[-height,-height,height,height]))
fig, ax = plt.subplots()
ax.scatter(np.arange(1,6), np.random.normal(size=5), marker=(verts,0),s=40)
Here, the argument s changes the size of the scatter. The drawn rectangle keeps the ratio width/height.
Output:
update
Since matplotlib 3.2x, use of (verts, 0) is depreciated. The working code should be changed to
fig, ax = plt.subplots()
ax.scatter(np.arange(1,6), np.random.normal(size=5), marker=verts, s=40)

How to create surface plot from greyscale image with Matplotlib?

Let's say I have a greyscale image (size: 550x150 px). I load the image with matplolib
import matplotlib.pyplot as plt
import matplotlib.image as mp_img
image = mp_img.imread("my-cat.png")
plt.imshow(image)
plt.show()
Now, plt.imshow displays the image on the screen. But what I want is a surface plot of the greyscale values, something like this:
.Colour is not really a necessity, but it would be helpful for the height lines. I know, that I need a function of the form f(x,y) -> z to create the surface plot. So, I want to use the greyscale value at (x_pixel,y_pixel) in my image to get the value of f. This leads to my problem:
I'd like to do some interpolation (e.g. smoothing) of my image values during plotting. This depends also on the size of my meshgrid, so how do I control this? And,
how do I make a surface plot of the greyscale values from my image?
So this is pretty straightforward. Load the data, build the plot:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# generate some sample data
import scipy.misc
lena = scipy.misc.lena()
# downscaling has a "smoothing" effect
lena = scipy.misc.imresize(lena, 0.15, interp='cubic')
# create the x and y coordinate arrays (here we just use pixel indices)
xx, yy = np.mgrid[0:lena.shape[0], 0:lena.shape[1]]
# create the figure
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(xx, yy, lena ,rstride=1, cstride=1, cmap=plt.cm.gray,
linewidth=0)
# show it
plt.show()
Result:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import cv2
# generate some sample data
import scipy.misc
lena = cv2.imread("./data/lena.png", 0)
# downscaling has a "smoothing" effect
lena = cv2.resize(lena, (100,100))
# create the x and y coordinate arrays (here we just use pixel indices)
xx, yy = np.mgrid[0:lena.shape[0], 0:lena.shape[1]]
# create the figure
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(xx, yy, lena ,rstride=1, cstride=1, cmap=plt.cm.jet,
linewidth=0)
# show it
plt.show()
If you want to get color plot, change the code to: "cmap=plt.cm.jet".
So you can get something like this:
color plot

issues with PyPlot color bar tick marks with images

I'm trying to plot an image with a superimposed fitted curve, but for now I'll just provide an example of an image.
I have been following this example ( http://matplotlib.org/examples/pylab_examples/colorbar_tick_labelling_demo.html ), but when I try to replace the gaussian noise with an image the color bar tick marks don't display correctly (i.e they are all smashed down at the left end).
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
from matplotlib import cm
from numpy.random import randn
fig, ax = plt.subplots()
data = np.clip(randn(250, 250), -1, 1)
#data = Image.open('testTop.tif')
cax = ax.imshow(data, interpolation='nearest', cmap=cm.afmhot)
ax.set_title('colorBar fun')
cbar = fig.colorbar(cax, ticks=[-1, 0, 1], orientation='horizontal')
cbar.ax.set_xticklabels(['Low', 'Medium', 'High'])# horizontal colorbar
plt.show()
#data = np.clip(randn(250, 250), -1, 1)
data = Image.open('testTop.tif')
Is there something intrinsic about displaying images that skews the colorbar, or is there something else obvious that I'm missing?
The colorbar axis only goes from -1 to 1 in the example with the random nose because the data ranges from -1 to 1. The tif image your using probably has a different range of values. You can get the minimum and maximum values of the data you're plotting and use that to set the color bar ticks. Here's an example that will work with both the random data and an image:
import matplotlib.cbook as cbook
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
from matplotlib import cm
from numpy.random import randn
# Load sample image
image_file = cbook.get_sample_data('grace_hopper.png')
data = plt.imread(image_file)
data = data[:,:,0] # Take only one channel for a grey scale image.
#data = np.clip(randn(250, 250), -1, 1)
fig, ax = plt.subplots()
cax = ax.imshow(data, interpolation='nearest', cmap=cm.afmhot)
ax.set_title('colorBar fun')
dataMin = np.amin(data)
dataMax = np.amax(data)
mid = ((dataMax - dataMin) / 2) + dataMin
cbar = fig.colorbar(cax, ticks=[dataMin, mid, dataMax], orientation='horizontal')
cbar.ax.set_xticklabels(['Low', 'Medium', 'High'])# horizontal colorbar
plt.show()

Categories

Resources