A year ago I wrote a post about converting screen pixel coordinates to graph coordinates: https://chrisheydrick.com/2012/11/01/converting-pixel-coordinates-to-graph-coordinates/

This is something you want to do if you need to map the location of a pixel to an arbitrary graph coordinate, which I needed to do to plot the Mandelbrot set, or plot a sine wave, and so on.

Unfortunately I made a mistake in that post which makes things appear to work, but doesn’t actually work at all (it mirrors the graph). Here is what I’m hoping is the right way to do it. There’s a big TL;DR at the end that lays out the formula and the rules, if you want to skip down to there.

The general form is correct:

Graph Location = Pixel Location * (Graph Width / Pixel Width) + Graph Minimum

However, what you consider to be “Graph Minimum” is a matter of perspective. Let’s try this on a mock image.

Here is an example of an image that’s 320 pixels horizontally, and 200 pixels vertically. Remember that you count pixels starting at the top left. I want to treat this image as if it represents a graph, and I’ll represent pixel and graph coordinates as a pair of X and Y values like this: (X,Y). The center of the image is going to be graph coordinates (0,0), and the graph extends one graph unit positive and negative horizontally and vertically. So, we can see visually that pixel location (0,0), which is at the top left of the image, is graph location (-1,1). Pixel location (319,200), which is at the bottom right of the image, is graph location (1,-1).

Great, so we can see this visually, but we want to calculate it in a program. Let’s do it the wrong way, the way I described it in the other post, first. How about pixel location 0 on the X axis first?

Horizontal Pixel Location = 0

Horizontal Graph Width = 2 (since the graph spans from -1 to 1 for a total of two graph units across)

Horizontal Pixel Width = 320

Horizontal Graph Minimum = -1

Horizontal Graph Location = 0 * (2 / 320) + -1 = -1

Alright, this makes sense. The X-axis pixel 0 corresponds to graph location -1. We can visually see that. Now let’s try to calculate the graph location of the Y-axis pixel 0.

Vertical Pixel Location = 0

Vertical Graph Width = 2 (since the graph spans from -1 to 1 for a total of two graph units across)

Vertical Pixel Width = 200

Vertical Graph Minimum = -1

Vertical Graph Location = 0 * (2 / 200) + -1 = -1

So here’s the problem! We can see that it SHOULD be +1 on the graph, but it’s not.

Where I went wrong was thinking that Graph Minimum should be the minimum value that we can visually see on the axis. -1 is smaller than +1, so -1 is the minimum. What you really need to do is consider Graph Minimum to be the value that can be represented by the minimum pixel value on the screen. X Pixel 0 is at graph value -1, and Y Pixel 0 is at graph value +1. So coincidentally the X Pixel calculation above worked out since the graph minimum is -1 and the graph value represented by the minimum X pixel is -1. The Y value didn’t work out because the graph value represented by the minimum pixel is +1, but the graph minimum is -1.

So here’s big reveal #1: Consider the graph minimum to be the values of the graph at the pixel location (0,0). Consider the graph maximum to be the values of the graph at the max pixel location, which in this example is pixel location (320,200).

And here’s big reveal #2: The graph width is the graph minimum subtracted from the graph maximum. To make this clear, here’s the revised formula.

Graph Location = Pixel Location * ((Graph Maximum – Graph Minimum) / Pixel Width) + Graph Minimum

Obviously plugging in a +1 in the formula above would fix it, so lets try a different pixel location, this time at the bottom right of the image, starting with X pixel location 320. Remember, the X-axis graph value at X pixel 0 is -1, and the X-axis graph value at X pixel 320 is +1.

Horizontal Pixel Location = 320

Horizontal Graph Width = 2 (because (1 – -1 = 2))

Horizontal Pixel Width = 320

Horizontal Graph Minimum = -1

Horizontal Graph Location = 320 * (2 / 320) + -1 = 1

Ok good. The X-axis pixel 320 (which is the far right of the X-axis) corresponds to graph location 1. We can visually see that. Now let’s try to calculate the graph location of the Y-axis pixel 200.

Vertical Pixel Location = 200

Vertical Graph Width = -2 (because Y-axis min is +1, and Y-axis max is -1, and the width is calculated by (graph max – graph min), and (-1 – 1 = -2))

Vertical Pixel Width = 200

Vertical Graph Minimum = 1 (THIS IS +1 NOW BECAUSE IT’S THE VALUE OF THE GRAPH AT THE MINIMUM Y PIXEL VALUE)

Vertical Graph Location = 200 * (2 / 200) + 1 = -1

I’m not sure how clearly I’ve been able to spell this out.

TL;DR, the formula is:

Graph Location = Pixel Location * ((Graph Maximum – Graph Minimum) / Pixel Width) + Graph Minimum

Pixel Location is the location (pixel location) of the pixel on the respective axis, Graph Minimum is the graph value of the lowest pixel value (0), Graph Minimum is the graph value of the highest pixel value, and Pixel Width is the number of pixels on that axis.

TL;DR Example: if we have an image of resolution (320,200), and we consider that image to represent a graph with (0,0) in the center that expands +1 and -1 on both the X and Y axis, what graph value is represented by the pixel location (240,50) which I’ve marked in red?

We now know that the X Graph Minimum is -1 because that’s the Graph X value a X Pixel 0, and we know that the Y Graph Minimum is +1 because that’s the Graph Y value at Y Pixel 0.

We now know that the X Graph Maximum is +1 because that’s the Graph X value at X pixel 320, and we know that the Y Graph Maximum is -1 because that’s the Graph Y value at Y Pixel 200.

X Graph Location =240 * ((1 – -1) / 320) + -1 = .5

Y Graph Location = 50 * ((-1 – 1) / 200) + 1 = .5

So the graph location at pixel (240,50) is (.5, .5), which looks right to me!