The Map Function¶
In these notes you will learn:
- How to shrink and expand ranges of numbers using basic arithmetic.
- How to use the
map
function.
Some Handy Mathematical Functions¶
Processing has a number of pre-defined mathematical functions that you can use in your programs. For example:
sq(x)
returns the square ofx
. For example,sq(3)
returns 9, andsq(sq(2))
returns 16.sqrt(x)
returns the square root ofx
. For example,sqrt(121)
returns 11, andsqrt(sq(74))
returns 74.abs(x)
returns the absolute value ofx
. For example,abs(-3.1)
returns 3.1, andabs(2.55)
returns 2.55.pow(x, y)
returnsx
to the power ofy
, e.g. \(x^y\). For example,pow(2, 5)
returns 32 (i.e. \(2^5\)), andpow(3, 3)
returns 27.min(x, y)
returns the smallest ofx
any
. For example,min(6, 2)
returns 2, andmin(min(1, 2), 3)
returns 1.max(x, y)
returns the largest ofx
any
. For example,max(6, 2)
returns 6, andmax(max(1, 2), 3)
returns 3.dist(x, y, a, b)
returns the distance between the points (x
,y
) and (a
,b
). For example, the distance between the points (5, 4) and (10, 10) isdist(5, 4, 10, 10)
, which equals 7.81025.constrain(x, lo, hi)
returnslo
ifx <= lo
,hi
ifx >= hi
, andx
otherwise. For example,contrain(12, 1, 10)
returns 10,contrain(0, 1, 10)
returns 1, andcontrain(3.2, 1, 10)
returns 3.2.
The Map Function¶
map
is a particularly useful function that is used to stretch and shrink
ranges of numbers. It shows up often enough in graphics programming that we
will look at it in some detail.
It’s often interesting to set colors automatically. For instance, lets write a
a program that draws circles whose fill color is a shade of gray that depends
upon mouseY
:
void setup() {
size(500, 500);
noStroke();
}
void draw() {
fill(mouseY); // not so good!
ellipse(mouseX, mouseY, 50, 50);
}
This program simply sets the fill color of the ellipse to be mouseY
:
As you can see, circles are drawn only on the top half the screen.
Why is this happening? The problem is that the range of legal values for
mouseY
is bigger than the range of legal values for fill
.
Specifically, mouseY
ranges from 0 to 500 (the height of the screen), but
fill
values only range from 0 to 255 (which you learn from the
documentation for fill).
So we can’t directly use the value of``mouseY`` as the fill
value.
Instead, we want a value, based on mouseY
, that fits in the range 0 to
255.
One trick is to use this expression: 255 * (mouseY / 500). The sub-
expression mouseY / 500
is guaranteed to be in the range 0 to 1 because
the maximum possible value of mouseY
is 500 (and the smallest possible
value is 0). Thus, multiplying mouseY / 500
by 255 gives a value that is
in the range 0 to 255, which is what fill
needs:
void draw() {
fill(256 * mouseY / 500); // good!
ellipse(mouseX, mouseY, 50, 50);
}
Using the map Function¶
Shrinking and stretching numbers like this is so common in graphics
programming that Processing provides a helper function to do it for you. The
map(x, low1, high1, low2, high2) function converts x
from the
source range [low1, high1]
to a new value in the target range [low2,
high2]
. The key fact is that the new value is at proportionally the same
position in the target range as x
is in the source range.
For example, suppose you have a point 25% of the way between 10 and 20 (i.e. the point 12.5):
Then map(12.5, 10, 20, 12, 19)
returns the point 13.75, which is
exactly 25% of the way between 12 and 19.
As another example, suppose instead of having the color depend upon
mouseY
, we wanted it to depend upon mouseX * mouseY
. The smallest
possible value of this expression is 0, while the largest possible value is
500 * 500, and so the range is [0, 500 * 500]. To map this into the range [0,
255] we do this:
map(mouseX * mouseY, 0, 500 * 500, 0, 255)
This always returns a number in the target range, i.e. a number from 0 to 255. And using this function we can choose colors based on the mouse position like this:
void setup() {
size(500, 500);
}
void draw() {
noStroke();
fill(map(mouseX * mouseY, 0, 500 * 500, 0, 255));
ellipse(mouseX, mouseY, 50, 50);
}
As another example, lets draw an ellipse whose diameters are always between 25 and 100, and change in proportion to the mouse location:
color orange = color(255, 165, 0);
color white = color(255, 255, 255);
void setup() {
size(500, 500);
noStroke();
smooth();
}
void draw() {
background(white);
fill(orange);
ellipse(mouseX, mouseY, map(mouseX, 0, 500, 25, 100),
map(mouseY, 0, 500, 25, 100));
}
Since the screen is 500 by 500, we know that mouseX
(and mouseY
) must
be in the range [0, 500]. The legal diameter values are in the range [25,
100], and so map(mouseX, 0, 500, 25, 100)
returns a value in [25, 100]
that corresponds to the same location as mouseX
in the range [0, 500].
A Non-Graphical Example¶
You can use the map
function to help you calculate your score on an exam.
For instance, suppose you write a final exam and score 65 out of a possible 71
marks, and you scored 65. What is this as a percentage?
The easiest way to calculate this percentage is like this:
We could also use the map
function:
map(65, // score of the exam
0, 75, // range of possible marks on the exam
0, 100 // range of possible percentages
)
This call to map
returns 86.667, just like the first way of calculating
your percentage.
Of course, you probably wouldn’t use map
in practice to calculate
percentages, but it is a good test of your understanding of how map
works.
An Example with Images¶
In the notes on image processing we saw how to apply
various filters to images using the filter
function. Here, lets make a
program that displays two copies of an image side-by-side and lets you apply a
threshold filter in real time. Being able to compare the processed image to
the original is quite convenient.
// each will be displaying two different images, so we need
// two images variables
PImage img;
PImage img2;
void setup() {
// load the image file from the "data" folder
img = loadImage("cat.jpg");
// set the window to be wide enough for two copies
// of the image drawn side-by-side
size(2 * img.width, img.height);
}
void draw() {
// display the original image
image(img, 0, 0);
// make a copy of the original
img2 = img.get();
// calculate threshold based on the y-position of mouse
float t = map(mouseY,
0, height, // range of values for mouseY
0, 1.0 // target range to convert to
);
// apply the filter
img2.filter(THRESHOLD, t);
// display the image
image(img2, img.width, 0);
}
Warning
You should understand every line and detail of this program!
When you run this program the threshold for the black and white image is set proportionally based on the height of the mouse pointer. The image on the left doesn’t change, and so it is easy to compare the two.
Questions¶
What values do each of the following expressions return?
sq(2) + sq(3) - sqrt(16)
sqrt(sq(3.14))
abs(min(1, 2) + max(abs(-2), abs(-1)))
min(min(4, -1), max(8, 2))
pow(max(1, 2), pow(2, 2))
sq(dist(3, abs(-4), min(0, 11), 0))
constrain(max(5, 1), -3, 3) + constrain(sq(2), 15, sq(5))
Explain, in brief English, what the
map
function does.Explain what each of the 6 variables in the following
map
statement mean:a = map(b, c, d, e, f);
For each of the following exam scores, write a
map
function that calculates what percentage out of 100 the score is:- 36 out of 43
- 10 out of 12
- 85 out of 100
- 55 out of 50
Write a program that draws a purple square with a yellow edge at the mouse pointer. Make the width and height of the square equal to
(mouseX + mouseY) / 5
, and use strokeWeight to give the edge a thickness of at least 10.Modify the previous program so that, in addition to what it already does, the color of the square’s interior is based on
mouseX + mouseY
. Use themap
function to convertmouseX + mouseY
into a legal RGB color.Write a program that draws an ellipse centered at the mouse pointer and its fill color set to be proportional to
mouseX * mouseY
.