enter image description hereI'm having trouble overplotting a relation between radial velocity and offset(position). I've looked at various solutions, but it doesn't seem to work. I've converted the equation into numbers, with only one variable.It also doesn't display the picture to the required dimensions.
x = np.linspace(-0.8 ,0.8 , 1000)
y = 0.5*((1.334e+20/x)**0.5)
img = plt.imread('Pictures/PVdiagram1casaviewer.png')
fig, ax = plt.subplots(figsize=(16, 16), tight_layout=True)
ax.set_xlabel('Offset(arcsec)', fontsize=14)
ax.set_ylabel('Radial Velocity (Km/S)', fontsize=14)
ax.imshow(img, extent=[-0.8, 0.8, -5, 15])
ax.plot(x, y, linewidth=5, color='white')
plt.title('PV Diagram')
plt.show()
enter image description here
If I plot your image, you can see that the axis of the image and matplotlib don't match, because the image contains space between the plot and border of the pictures (axis titles, and so on...)
So, first you need to crop the image, so that it contains just the plot area.
Next, you can plot the image with the argument aspect=auto to scale it to your figsize:
ax.imshow(img, extent=[-0.8,0.8,-5,15], aspect='auto')
If you try to plot your y function over the image, you will see that the values of y are much larger, so the curve is above the image (notice the tiny image is at the bottom).
I don't know what the physical background of y is, but if you divide it by 10e9 it fits inside the image-range.
Full code:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-0.8 ,0.8 , 1000)
y = 0.5*((1.334e+20/x)**0.5)/10e9 # Scale it here... but how?
img = plt.imread('hNMw82.png')
fig, ax = plt.subplots(figsize=(16, 16), tight_layout=True)
ax.set_xlabel('Offset(arcsec)', fontsize=14)
ax.set_ylabel('Radial Velocity (Km/S)', fontsize=14)
ax.imshow(img, extent=[-0.8,0.8,-5,15], aspect='auto')
ax.plot(x, y, linewidth=5, color='white')
ax.set_ylim([-5,15])
ax.set_xlim([-0.8,0.8])
plt.title('PV Diagram')
plt.show()
Result:
(I also set the axis limits.)
Related
I have an image which already has semilogarithmic scale in the y axis:
I would like to imshow this in matplotlib such that I can plot stuff over it. Here's the approach I took:
image = Image.open("cropped.jpg")
fig = plt.figure()
ax = plt.gca()
ax.imshow(image, extent=(0, 6, 1, 400), aspect="auto")
ax.set_yscale('log')
Unfortunately, this stretches my data and I end up with the following:
How can I preserve the underlying data but still readjust the scale to semilog?
Good day to all,
I am trying to create a heatmap, given a set of x, y coordinate pairs extracted from a CSV file. I am using numpy.histogram2d to plot it, the heatmap gives me correct, but I need to overlay it on another image. I share my code
Here is the CSV
csv = pd.read_csv("../test2.csv")
#Gets the centroid of the coords
csv["x"] = (combined_csv["x_min"]+(combined_csv["x_max"]-combined_csv["x_min"])/2).astype(int)
csv["y"] = (combined_csv["y_min"]+(combined_csv["y_max"]-combined_csv["y_min"])/2).astype(int)
am = csv[(csv["tracking_id"] != 7) &(csv["tracking_id"] != 28)] #Some filters
#Taken from another question
def myplot(x, y, s, bins=1000):
heatmap, xedges, yedges = np.histogram2d(x, y, bins=bins, range=[[0, 960], [0, 480]])
heatmap = gaussian_filter(heatmap, sigma=s)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
return heatmap.T, extent
img, extent = myplot(am["x"], am["y_max"], 16,200)
plt.imshow(img, extent=extent, origin='upper', cmap=cm.jet)
The previous code gives me this image
I put the range between 0 and 480 for x and 0 and 960 for y, because the target image has that size, but doing this, histogram2d returns me the histogram matrix h, which is 200x200, then I use matplotlib to plot it and This graphs me correctly in the range 0-480 for x and 0-960 for y, what I need is to save said image, preserving as much information as possible in the 480x960 pixel size, and then add it with the target image using this tutorial how to superimpose heatmap on a base image?
final_img = cv2.addWeighted (heatmap_img, 0.5, image, 0.5, 0)
For creating something like this
But the image and the histogram doesnt match in the sizes that i wanted.
This is the target image
Ok, so i fix the error by the next code, printing the two images at the same plot
base_image = image
sigma = 8
fig, ax = plt.subplots(1, 1, figsize = (20, 16))
heatmap, xedges, yedges = np.histogram2d(am["x"], am["y"], bins=200, range=[[0,960],[0,480]])
heatmap = gaussian_filter(heatmap, sigma=sigma)
extent = [xedges[0], xedges[-1], yedges[-1], yedges[0]]
img = heatmap.T
ax.imshow(img, extent=extent, cmap=cm.jet)
ax.imshow(base_image, alpha = 0.5)
ax.set_xlim(0, 960)
ax.set_ylim(480,0)
ax.axes.get_yaxis().set_visible(False)
ax.axes.get_xaxis().set_visible(False)
plt.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
plt.savefig("heatmap_final.png", bbox_inches='tight')
plt.show()
plt.close(fig)
I am displaying images from a 2D array with pyplot and have removed axis markings and padding. However, between rows of images, there is still whitespace which I would like to remove. The images themselves have no whitespace.
fig = plt.figure(figsize=(10, 10))
for x in range(quads_x):
for y in range(quads_y):
# ADD IMAGES
fig.add_subplot(quads_y, quads_x, (quads_x * x) + y + 1)
plt.imshow(cv2.imread("./map/" + winning_maps[x][y], 0))
# PYPLOT FORMATTING
plt.subplots_adjust(wspace=0, hspace=0)
ax = plt.gca()
ax.axis("off")
ax.xaxis.set_major_locator(matplotlib.ticker.NullLocator())
ax.yaxis.set_major_locator(matplotlib.ticker.NullLocator())
The code yields something like
Any ideas on how I should deal with the issue?
Normally using plt.subplots_adjust(wspace=0, hspace=0) would collapse all of the axes onto each other. The issue you are running into is that using imshow fixes the aspect ratio of the axes in the plot.
To compensate, you need to adjust the size of your canvas so that the frame has the same ratio as the images you are showing. The next issue is that the border padding around the axes is a ratio of the size of the image. If you are ok with it, you can remove the border, drop in the images, then adjust the height of the canvas to be the figure height times the ratio of the images times the number of rows of images divided by the number of columns of images.
Here is an example:
from matplotlib import pyplot as plt
from PIL import Image
img = Image.open('fox.jpg').resize(80,50)
fig, axes = plt.subplots(rows, columns, figsize=(7,7))
for ax in axes.ravel():
ax.imshow(img)
ax.set_autoscale_on(False)
ax.axis('off')
plt.subplots_adjust(hspace=0, wspace=0, left=0, bottom=0, right=1, top=1)
r, c = axes.shape
fig.set_figheight(fig.get_figwidth() * ax.get_data_ratio() * r / c )
plt.show()
Here is the image before using set_figheight:
And here it is with the adjustment:
I'm using matplotlib for plotting, and I have the following matrix, Mat which I would like to plot into a heatmap.
Mat.shape
which yields (20,20).
I use the following code to plot it into a heatmap, following the this.
plt.imshow(Mat, cmap='Reds', interpolation='nearest')
plt.show()
But I have to resize this heatmap into 1600 x 1200(x,y) size, since, I want it to be overlapped with the image, img. The code is as follows.
plt.imshow(img, alpha=.5) # for image
plt.xlim(0, 1600)
plt.ylim(1200, 0)
plt.axis('off')
plt.imshow(Mat, cmap='Reds', interpolation='nearest', alpha=.5) # for heatmap to overlap
plt.show()
For some reason I would not like to change the size of img.
My try
I tried to resize at the level of plt.imshow(Mat), which I found hard. The only option I see at present is to resize Mat into 1600 x 1200 matrix with redundancy. Anyone to give me some efficient solution?
Use the extent= parameter of imshow to scale your matrix to the image's scale (more information here as well).
plt.figure()
img = plt.imread('stinkbug.png')
plt.imshow(img, alpha=1) # for image
#plt.axis('off')
xmin, xmax = plt.xlim()
ymin, ymax = plt.ylim()
Mat = np.random.normal(size=(20,20))
plt.imshow(Mat, cmap='Reds', interpolation='nearest', alpha=.5, extent=(xmin,xmax,ymin,ymax)) # for heatmap to overlap
plt.show()
I have a GUI that displays a plot. I want to fit that plot to an existing image. I displayed the image under the plot using:
myaxe.plot(...)
myaxeimage = myaxe.imshow(myimage, axpect='auto', extent=myaxe.axis(), zorder=-1)
I'm already able to play with the opacity of the image, using
myaxeimage.set_alpha()
Now I'd like to be able to zoom in and out and to move around the image, using the GUI, without touching to the existing plot and axes, in order to align it with my plot. In other words, I want to scale to given sx and sy factors, and to put origin of the image at a given (x,y) point, clipping parts of the image going outside the axes. How can I do that?
There is a watermark example distributed with matplotlib that is sort of similar. Starting from that code, we can modify as follows:
Use ax.imshow to plot the image first. I do this because the extent parameter affects the final extent of ax. Since we want the final extent to be governed by the plt.plot(...), let's put it last.
myaximage = ax.imshow(im, aspect='auto', extent=(1,15,0.3,0.7), alpha=0.5, origin='upper', zorder=-1)
Instead of extent=myaxe.axis(), use extent to control the position and size of the image. extent=(1,15,0.3,0.7) places the image in the rectangle with (1, 0.3) as the bottom left corner and (15, 0.7) as the top right corner.
With origin='upper', the [0,0] index of the array im is placed at the upper left corner of the extent. With origin='lower' it would have been placed at the lower left corner.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
import matplotlib.image as image
np.random.seed(1)
datafile = cbook.get_sample_data('logo2.png', asfileobj=False)
im = image.imread(datafile)
fig, ax= plt.subplots()
myaximage = ax.imshow(im, aspect='auto', extent=(1,15,0.3,0.7), alpha=0.5, zorder=-1)
ax.plot(np.random.rand(20), '-o', ms=20, lw=2, alpha=1.0, mfc='orange')
ax.grid()
plt.show()
If you want to expand the image and clip it to the extent of the plot, you might need to use ax.set_xlim and ax.set_ylim as well:
myaximage = ax.imshow(im, aspect='auto', extent=(-1,25,0.3,0.7), alpha=0.5, zorder=-1,
origin='upper')
ax.plot(np.random.rand(20), '-o', ms=20, lw=2, alpha=1.0, mfc='orange')
ax.set_xlim(0,20)
ax.set_ylim(0,1)
Or, for more control, you can clip the image to an arbitrary path by using myaximage.set_clip_path:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
import matplotlib.image as image
import matplotlib.patches as patches
np.random.seed(1)
datafile = cbook.get_sample_data('logo2.png', asfileobj=False)
im = image.imread(datafile)
fig, ax= plt.subplots()
myaximage = ax.imshow(im, aspect='auto', extent=(-5,25,0.3,0.7),
alpha=0.5, origin='upper',
zorder=-2)
# patch = patches.Circle((300,300), radius=100)
patch = patches.Polygon([[5, 0.4], [15, 0.4], [15, 0.6], [5, 0.6]], closed=True,
transform=ax.transData)
myaximage.set_clip_path(patch)
ax.plot(np.random.rand(20), '-o', ms=20, lw=2, alpha=1.0, mfc='orange',
zorder=-1)
ax.set_xlim(0, 20)
ax.set_ylim(0, 1)
plt.show()
Finally, I followed tcaswell suggestion and used 2 different axes. This way, I simply have to play with set_xlim() and set_ylim() of my image axes to change the origin and/or the zooming factor of my image. I order to get the image below my plot, without hiding it with the frame of the plot, I removed the frame of the plot and used the frame of the image axes instead. I also hidden the ticks from the image axes.
from matplotlib import pyplot
f = pyplot.figure()
a = f.add_subplot(111, frameon=False) # Remove frame
a.plot(...)
myimg = pyplot.imread(...)
imgaxes = f.add_axes(a.get_position(), # new axes with same position
label='image', # label to ensure imgaxes is different from a
zorder=-1, # put image below the plot
xticks=[], yticks=[]) # remove the ticks
img = imgaxes.imshow(myimg, aspect='auto') # ensure image takes all the place
# now, to modify things
img.set_alpha(...)
imgaxes.set_xlim((x1, x2)) # x1 and x2 must be calculated from
# image size, origin, and zoom factor