0

Similar to in this StackOverflow post, I understand that it is possible to extract the pixel co-ordinates from points plotted in a pyplot figure. How to get pixel coordinates for Matplotlib-generated scatterplot?

However, what if we plotted a line between each of those points and wanted to get the location of all the pixels of not just those plotted dots, but all pixels that make up the line.

Is this something that is possible with matplotlib?

Brian Diep
  • 35
  • 5

1 Answers1

1

A line isn't made up of pixels. The pixels in its trajectory are modified taking line width and antialiasing into account. Drawing a line with default settings and zooming in on the image looks like the image below. Very few pixels get the full 100% of the given color. Lots of pixels are changed.

zoomed in image of drawn line

Depending on your final goal, you could calculate pixel coordinates using the method described in the post you linked (note that the pixels on a saved image can deviate a bit from the pixels on-screen). And then use e.g. Bresenham's line algorithm to find the coordinates of points in-between. Note that a naive Bresenham's algorithm would draw a 45 degree line much thinner looking than a horizontal line. On a modern screen a one-pixel wide line would be almost invisible.

Here is a possible Bresenham-like interpretation of the linked code:

import numpy as np
import matplotlib.pyplot as plt

def points_in_line(x0, y0, x1, y1):
    dx = np.round(np.abs(x1 - x0))
    dy = np.round(np.abs(y1 - y0))
    steps = int(np.round(max(dx, dy))) + 1
    return np.vstack([np.linspace(x0, x1, steps), np.linspace(y0, y1, steps)]).T

fig, ax = plt.subplots()
points, = ax.plot([0, 1, 2, 4, 5, 6, 9], [0, 5, 3, 2, 2, 9, 8], 'b-')
ax.axis([-1, 10, -1, 10])

# Get the x and y data and transform them into pixel coordinates
x, y = points.get_data()
xy_pixels = ax.transData.transform(np.vstack([x, y]).T)
x_pix, y_pix = xy_pixels.T

# find all points in each line
all_pix = [points_in_line(x0, y0, x1, y1) for x0, y0, x1, y1 in zip(x_pix[:-1], y_pix[:-1], x_pix[1:], y_pix[1:])]
all_x_pix, all_y_pix = np.concatenate(all_pix).T

# In matplotlib, 0,0 is the lower left corner, whereas it's usually the upper 
# left for most image software, so we'll flip the y-coords...
width, height = fig.canvas.get_width_height()
all_y_pix = height - all_y_pix

print('Coordinates of the lines in pixel coordinates...')
for xp, yp in zip(all_x_pix, all_y_pix):
    print(f'{x:0.2f}\t{y:0.2f}')

# save the figure with its current DPI
fig.savefig('test.png', dpi=fig.dpi)
JohanC
  • 71,591
  • 8
  • 33
  • 66