How do you directly overlay a scatter plot on top of a jpg image in matplotlib / Python?
Question:
I need to rapidly plot jpg frames that result as the output of a tracking algorithm. Companion with the jpg frames are text files containing simple (x,y) data locating the image targets that are being tracked. I would like to use matplotlib to plot the jpg images, then overlay a scatter plot of the (x,y) data which gets read from the text file and stored into a Pythonic list. Below is code that will plot the jpg image, but in all of the scouring I have done of matplotlib, scipy, and PIL manuals and help pages, I cannot find anything that explains how to maintain this plot window and simply overlay a scatter plot of simple markers at various (x,y) locations in the image. Any help is greatly appreciated.
import matplotlib.pyplot as plt;
im = plt.imread(image_name);
implot = plt.imshow(im);
plt.show()
Answers:
this should work:
import matplotlib.pyplot as plt
im = plt.imread('test.png')
implot = plt.imshow(im)
plt.plot([100,200,300],[200,150,200],'o')
plt.show()
keep in mind that each pixel in the image is one unit on the x,y axes. The 'o'
is a shorthand way of getting the plot
function to use circles instead of lines.
The pyplot.scatter()
function was tailor made for this reason:
import matplotlib.pyplot as plt
im = plt.imread(image_name)
implot = plt.imshow(im)
# put a blue dot at (10, 20)
plt.scatter([10], [20])
# put a red dot, size 40, at 2 locations:
plt.scatter(x=[30, 40], y=[50, 60], c='r', s=40)
plt.show()
See the documentation for more info.
I know this has been answered but similarly zorder works as well. Which is great if you want to put something on top of a scatterplot or under it
import matplotlib as plt
im = plt.imread(image_name)
plt.imshow(im,zorder=1)
plt.scatter(x,y,zorder=2)
plt.show()
lower zorder means it is below other things
Here’s a way to plot directly over an image without having to invoke imshow()
.
It renders the plot as a transparent image with an identical shape as the input and then alpha-composits it onto the input image.
import numpy as np
import matplotlib.pyplot as plt
import imageio
from contextlib import contextmanager
@contextmanager
def plot_over(img, extent=None, origin="upper", dpi=100):
h, w, d = img.shape
assert d == 3
if extent is None:
xmin, xmax, ymin, ymax = -0.5, w + 0.5, -0.5, h + 0.5
else:
xmin, xmax, ymin, ymax = extent
if origin == "upper":
ymin, ymax = ymax, ymin
elif origin != "lower":
raise ValueError("origin must be 'upper' or 'lower'")
fig = plt.figure(figsize=(w / dpi, h / dpi), dpi=dpi)
ax = plt.Axes(fig, (0, 0, 1, 1))
ax.set_axis_off()
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)
fig.add_axes(ax)
fig.set_facecolor((0, 0, 0, 0))
yield ax
fig.canvas.draw()
plot = np.frombuffer(fig.canvas.buffer_rgba(), dtype=np.uint8).reshape(h, w, 4)
plt.close(fig)
rgb = plot[..., :3]
alpha = plot[..., 3, None]
img[...] = ((255 - alpha) * img.astype(np.uint16) + alpha * rgb.astype(np.uint16)) // 255
img = imageio.imread("image.jpg")
img_with_plot = img.copy()
with plot_over(img_with_plot) as ax:
ax.scatter(...)
# etc
imageio.imwrite("result.png", img_with_plot)
I need to rapidly plot jpg frames that result as the output of a tracking algorithm. Companion with the jpg frames are text files containing simple (x,y) data locating the image targets that are being tracked. I would like to use matplotlib to plot the jpg images, then overlay a scatter plot of the (x,y) data which gets read from the text file and stored into a Pythonic list. Below is code that will plot the jpg image, but in all of the scouring I have done of matplotlib, scipy, and PIL manuals and help pages, I cannot find anything that explains how to maintain this plot window and simply overlay a scatter plot of simple markers at various (x,y) locations in the image. Any help is greatly appreciated.
import matplotlib.pyplot as plt;
im = plt.imread(image_name);
implot = plt.imshow(im);
plt.show()
this should work:
import matplotlib.pyplot as plt
im = plt.imread('test.png')
implot = plt.imshow(im)
plt.plot([100,200,300],[200,150,200],'o')
plt.show()
keep in mind that each pixel in the image is one unit on the x,y axes. The 'o'
is a shorthand way of getting the plot
function to use circles instead of lines.
The pyplot.scatter()
function was tailor made for this reason:
import matplotlib.pyplot as plt
im = plt.imread(image_name)
implot = plt.imshow(im)
# put a blue dot at (10, 20)
plt.scatter([10], [20])
# put a red dot, size 40, at 2 locations:
plt.scatter(x=[30, 40], y=[50, 60], c='r', s=40)
plt.show()
See the documentation for more info.
I know this has been answered but similarly zorder works as well. Which is great if you want to put something on top of a scatterplot or under it
import matplotlib as plt
im = plt.imread(image_name)
plt.imshow(im,zorder=1)
plt.scatter(x,y,zorder=2)
plt.show()
lower zorder means it is below other things
Here’s a way to plot directly over an image without having to invoke imshow()
.
It renders the plot as a transparent image with an identical shape as the input and then alpha-composits it onto the input image.
import numpy as np
import matplotlib.pyplot as plt
import imageio
from contextlib import contextmanager
@contextmanager
def plot_over(img, extent=None, origin="upper", dpi=100):
h, w, d = img.shape
assert d == 3
if extent is None:
xmin, xmax, ymin, ymax = -0.5, w + 0.5, -0.5, h + 0.5
else:
xmin, xmax, ymin, ymax = extent
if origin == "upper":
ymin, ymax = ymax, ymin
elif origin != "lower":
raise ValueError("origin must be 'upper' or 'lower'")
fig = plt.figure(figsize=(w / dpi, h / dpi), dpi=dpi)
ax = plt.Axes(fig, (0, 0, 1, 1))
ax.set_axis_off()
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)
fig.add_axes(ax)
fig.set_facecolor((0, 0, 0, 0))
yield ax
fig.canvas.draw()
plot = np.frombuffer(fig.canvas.buffer_rgba(), dtype=np.uint8).reshape(h, w, 4)
plt.close(fig)
rgb = plot[..., :3]
alpha = plot[..., 3, None]
img[...] = ((255 - alpha) * img.astype(np.uint16) + alpha * rgb.astype(np.uint16)) // 255
img = imageio.imread("image.jpg")
img_with_plot = img.copy()
with plot_over(img_with_plot) as ax:
ax.scatter(...)
# etc
imageio.imwrite("result.png", img_with_plot)