Reputation: 123
I have this code, which I largely modified from Matplotlib: How to plot images instead of points?
See my output graph: Output
I would like to rotate each hamster picture with respect to the column "Rotation" in the dataframe. So that the pictures are orientated in the correct rotation.
How do I do this? I am struggling to understand the "offsetbox" guide for Matplotlib.
These are the first 10 rows on my dataframe.
import pandas as pd
df = pd.DataFrame([['21:21:00',0.1,0.0,10], ['21:21:01',0.1,0.0,20], ['21:21:02',0.1,0.0,28]\
,['21:21:03',0.1,0.0,12], ['21:21:03',0.1,0.0,12], ['21:21:04',0.5,0.6,12]\
,['21:21:05',3.7,4.4,10], ['21:21:06',6.8,8.1,10], ['21:21:07',9.9,11.9,20]\
,['21:21:08',13.0,15.7,29], ['21:21:09',16.1,19.5,33]]\
,columns=['Time', 'Northings', 'Eastings','Rotation'])
def main():
x = df['Eastings'][::2]
y = df['Northings'][::2]
image_path = get_sample_data(r'C:\Users\j.smith.EA.000\Desktop\PYTHON\hamster.jpg')
fig, ax = plt.subplots()
imscatter(x, y, image_path, zoom=0.03, ax=ax)
ax = df.plot(x = 'Eastings', y = "Northings", grid = True, figsize=(15,8), legend = False\
, xlim = (-30,30), ylim = (-30,30), kind = 'line', ax=ax)
plt.show()
def imscatter(x, y, image, ax=None, zoom=1):
image = plt.imread(image)
im = OffsetImage(image, zoom=zoom)
x, y = np.atleast_1d(x, y)
artists = []
for x0, y0 in zip(x, y):
ab = AnnotationBbox(im, (x0, y0), frameon=False,)
artists.append(ax.add_artist(ab))
return artists
main()
Upvotes: 1
Views: 1471
Reputation: 724
Going through your code, in your imscatter() function the for loop is assigning each image to each datapoint. You are passing the image to
ab = AnnotationBbox(im, (x0, y0), frameon=False,)
where im
is your image object.
Here, I would suggest passing the image after rotating it to whatever degree you want.
For ex:
im = rotate_image_by_angle(im, get_the_rotation_angle_from_colume)
ab = AnnotationBbox(im, (x0, y0), frameon=False,)
artists.append(ax.add_artist(ab))
This approach is implemented in the following code
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
from matplotlib.cbook import get_sample_data
import cv2
import imutils
df = pd.DataFrame([['21:21:00',0.1,0.0,0], ['21:21:01',3.1,3.0,20], ['21:21:02',6.1,6.0,30]\
,['21:21:03',9.1,9.0,40], ['21:21:03',12.1,12.0,50], ['21:21:04',15.1,15.2,60]\
,['21:21:05',18.1,18.0,70], ['21:21:06',21.1,21.0,80], ['21:21:07',24.0,24.1,90]\
,['21:21:08',27.0,27.1,100], ['21:21:09',30.0,30.1,110]]\
,columns=['Time', 'Northings', 'Eastings','Rotation'])
def main():
x = df['Eastings'][::2]
y = df['Northings'][::2]
z = df['Rotation'][::2]
fig, ax = plt.subplots()
imscatter(x, y, z, zoom=0.03, ax=ax)
ax = df.plot(x = 'Eastings', y = "Northings", grid = True, figsize=(15,7), legend = False\
, xlim = (-5,30), ylim = (-5,30), kind = 'line', ax=ax)
plt.show()
def imscatter(x, y, z, ax=None, zoom=1):
image = cv2.imread('image.png')
im = OffsetImage(image, zoom=zoom)
x, y, z = np.atleast_1d(x, y, z)
artists = []
for x0, y0, z0 in zip(x, y, z):
rotated = rotate_bound(image, z0)
im = OffsetImage(rotated, zoom=zoom)
ab = AnnotationBbox(im, (x0, y0), frameon=False,)
artists.append(ax.add_artist(ab))
return artists
def rotate_bound(image, angle):
# grab the dimensions of the image and then determine the
# center
(h, w) = image.shape[:2]
(cX, cY) = (w // 2, h // 2)
# grab the rotation matrix (applying the negative of the
# angle to rotate clockwise), then grab the sine and cosine
# (i.e., the rotation components of the matrix)
M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# compute the new bounding dimensions of the image
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
# adjust the rotation matrix to take into account translation
M[0, 2] += (nW / 2) - cX
M[1, 2] += (nH / 2) - cY
# perform the actual rotation and return the image
return cv2.warpAffine(image, M, (nW, nH), borderValue=(255,255,255))
main()
I have made minor changes throughout the code and added a function rotate_bound(image, angle)
which will rotate the image by a given angle. More details on how it was done, can be found here.
The Output now looks like this...
Upvotes: 1