With p5.js, how to use dates for line graph x-axis - p5.js

I would like to plot stock prices over time, and my x-axis data is day-month-year.
I can re-format how the date is presented in Excel, but is there an 'easy' way to use this type of data in a p5.js line graph?
Thanks!

I'd recommend looking into grafica. Here is a nice example that uses it in a p5 sketch (not mine), I found this on Google, it was made by 'piecesofuk':
function setup() {
createCanvas(400, 400);
// Create a new plot and set its position on the screen
points = [];
seed = 100 * random();
for (i = 0; i < 100; i++) {
points[i] = new GPoint(i, 10 * noise(0.1 * i + seed));
}
plot = new GPlot(this);
plot.setPos(0, 0);
plot.setOuterDim(width, height);
// Add the points
plot.setPoints(points);
// Set the plot title and the axis labels
plot.setTitleText("A very simple example");
plot.getXAxis().setAxisLabelText("x axis");
plot.getYAxis().setAxisLabelText("y axis");
// Draw it!
plot.defaultDraw();
}
function draw() {
// background(220);
}
Results in this:

Related

Processing 3.0 Question - struggling to implement some code

wondering if anyone can help with this. I have to write some ode using processing 3.0 for college, basically creating a series of circles that appear randomly and change colours etc. Ive got the circles to appear, and they change location on mouse click.
What Im struggling with is, its asked me to have the circles change colour when the mouse button is pressed, where circles to the right are blue and circles to the left of the mouse pointer are yellow? I have no idea how to implement that at all.
Here's what I have so far, any help would be hugely appreciated:
//declaring the variables
float[] circleXs = new float[10];
float[] circleYs = new float[10];
float[] circleSizes = new float[10];
color[] circleColors = new color[10];
void setup() {
size(600, 600);
createCircles();
}
//creation of showCricles function
void draw() {
background(0);
showCircles();
}
//creation of circles of random size greater than 10 but less than 50 - also of white background colour
void createCircles() {
for (int i = 0; i < circleXs.length; i++) {
circleXs[i] = random(width);
circleYs[i] = random(height);
circleSizes[i] = random(10, 50);
circleColors[i] = color(255,255,255);
}
}
void showCircles() {
for (int i = 0; i < circleXs.length; i++) {
fill(circleColors[i]);
circle(circleXs[i], circleYs[i], circleSizes[i]);
}
}
//creating new circles on mouse click
void mouseClicked() {
createCircles();
}
It's not very complicated, you just miss some of the basics. Here are 2 things you have to know to do what you want to do:
You can use mouseX or mouseY to compare coordinates with the current mouse pointer's position.
This would be way cleaner using class, but I am guessing that you are not quite there as you're using a couple arrays to store coordinates instead. But here's the thing with that method: the array's index always refer to the same object. Here your objects are circles, so every array's index n refers to the same circle. If you find a circle which x coordinate is leftward compared to the mouse pointer, you can change that circle's color by modifying the item at the same index but in the circleColors array.
So I added a couple lines to your mouseClicked() method which demonstrate what I just said. Here they are:
void mouseClicked() {
createCircles();
// here is the part that I added
// for each circle's X coordinate:
for( int i = 0; i < circleXs.length; i++) {
// if the X coordinate of the mouse is lower than the circle's...
if( mouseX > circleXs[i]) {
// then set it's color to yellow
circleColors[i] = color(255, 255, 0);
} else {
// else set it's color to blue
circleColors[i] = color(0, 0, 255);
}
}
}
It should show what you described, or close enough for you to clear the gap.
Hope it helps. Have fun!

In p5.js, is it possible to load a gif in the setup or preload function, and then use that gif multiple times elsewhere?

I have a class (lets call it "Enemies"), I want them to attack me when close enough (It will display an animated gif, that looks like a bite).
I've gotten all of this to work, except the only way I could figure it out, was by putting loadImage("attack.gif"), in the class. That got laggy really quick, since every time an enemy would spawn, it would have to reload that gif.
I've tried to use a loaded gif from the setup(), in my class, but all of their attacks were in sync.
Is there another way to do this?
You can preload the gif (or gifs) and store them in a array which you can reuse later to draw in multiple places (e.g. multiple spawned enemies in your case).
Here's a basic example that demonstrates:
loading images into an array
spawning objects on screen (re)using the loaded images
let images;
let enemies = [];
function preload(){
// load images and store them in an array
images = [
loadImage("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAPFBMVEX///8AAADf399fX19/f38/Pz+/v78fHx+fn58XFxeHh4cPDw+np6fX19fHx8evr6+3t7dvb2/39/dPT08jn1NmAAAA+UlEQVR4nO3ZSRKCMBBAUQnzPHj/u7qwOwtS0QhBwfpviaH9bDTG2w0AAAAAgNNLE2HC7zF6T0oAAQT8Q0CTC1M8Df61gywxek8TIcAq5anKXUsIIICACwaMmWhlept5OUvGCAH2o3iLqN8FBBBAwJcDJt3U1Dqsk+1O538/Z0mtU6aPAypnuu4JjfNKwJKKAAIIuEzAi+lxvPuFSQABBJwnoHY2JFu4U4ID7GYqzpYs+KiLAAIIOHPA7D+aWZsPCdh1Wk4AAQRcJ2CRQ5ai1yu9XrnnK/YfqWb9SuqfsoQ/xpoehSf+x1PHHtcTQAABPwsAAAAAAOAYD7+UFrmL/czUAAAAAElFTkSuQmCC"), loadImage("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAclBMVEX///8AAAAMDAwUFBRtbW20tLTKysrr6+s0NDSMjIzo6OgrKytzc3Py8vJKSkolJSWSkpIODg5jY2OlpaW7u7ubm5urq6tEREQaGhr29vZRUVHg4ODDw8Pc3Nw/Pz9VVVWAgIDU1NQ3NzdcXFx6enovLy+wzkUiAAACjElEQVR4nO2a63qCMAxAlU5QEEEUuSMivP8rjptS2iid0qmfOT/XfM0BHGlLZjMEQRAE+ShMXQBTXn79aAgQ6tIE4u1cgG0sTWAvJrBHARRAART4bIFEvUm8Fsk/nxe3p1BH60RskJsIXX+FcnsKkp5GBAQv8nGyEQFHtoCDAiiAAihwP38gXyAAE592LbYhW6B0u1QJnX9nKS2y09d0mTIqv5n+R2KGH0pAW6IACqAACqDAewtYGwaPQGHEY+OsaQRK1WTJoLiMC1PLSQToyI4FULeVBR/3M4nA+nGBeztNFEABFEABcQFgM7WDBHZc2N2NnrgAcVYMWQ7F5Rkb54BF688CkkABFEABFEABWsDcvEBgUGRjm8YdAthtHTbItR2gQp7Z8kQh3mWw4if2ND5M83jPaVoZAIEN0CcCPEciTSCFBPg7IFEAeATAcas8gRz6DfDLJKLKEli+WqAEPgEDbzN5AgYgoPOnEfIELEiA/9YhT8CHBPgTIYkC0TsK+FzYdh8EgWma2lMNdsH5OqHihS1r6E1YhOGxxuurUn4+hhsvTcOxtgUItVg3OH3jRB4FLZrbDfbYwawb1IHy6T4gYPPTeJcL3/Obvv4fg7plV+yJBYDt+TsJHL9eIESBFwtAi/wvE+BXp1MJXFfjQF8fJXD2LYYSOEMcoB449JXCYl3f6JpD2EFqoaxHbLu51hRFU6tp/xIldEGtnho7HzmcFixU00WgsoP3692iKopVVczzZVka1S3xfVJQw8B6Ejj3fAbg49HI9hwFUAAFUOB/BYDDDeUwqUDBCwyO6dzSal7QPcY027oL6pJQk9fJjOEVdjVKjxqSJAE2f0+h13M2XCok3NiIIMgX8guBhVuAILp8rwAAAABJRU5ErkJggg=="),
];
}
function setup(){
createCanvas(600, 600);
imageMode(CENTER);
}
function draw(){
background(255);
// update + draw enemies
for(let i = 0; i < enemies.length; i++){
enemies[i].update();
}
text("click to spawn", 10, 15);
}
function mousePressed(){
// pick a random image
let randomImage = images[int(random(images.length))];
// make a new enemy
enemies.push(new Enemy(randomImage, mouseX, mouseY));
}
class Enemy {
constructor(skin, x, y) {
this.skin = skin;
this.position = createVector(x, y);
this.velocity = createVector(random(-1,1), random(-1,1));
}
update(){
// add velocity
this.position.add(this.velocity);
// check borders and flip direction (roughly)
if(this.position.x < 0 || this.position.x > width ||
this.position.y < 0 || this.position.y > height){
this.velocity.mult(-1);
}
// render
push();
blendMode(MULTIPLY);
image(this.skin, this.position.x, this.position.y);
pop();
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.0/p5.min.js"></script>
In the example above I'm using base64 encoded images to avoid CORS issues, however you should be fine loading your custom images instead.
The idea is to store the images globally so you can re-use them later when instantiating new enemies. (If you have a couple of images individual variables per image should do, otherwise an array will make it easier to manage)
Notice in Enemy constructor simply receives a reference to the previously loaded image:
// when declared
constructor(skin, x, y) {
this.skin = skin;
// when intantiated
new Enemy(randomImage, mouseX, mouseY)
The only thing left to do is to render the image as needed:
image(this.skin, this.position.x, this.position.y);
Update Based on the comment and shared code the is that each enemy shares the same gif which updates at the same rate with the same frame number in sync.
One option would be to fill the images array with multiple copies of the same image, essentially reloading the gif once per enemy, though that seems wasteful.
Unfortunately p5.Image.get() returns a snapshot of the current frame and there is no magic function to clone a loaded gif, however the undocummented gifProperties holds the necessary data to manually do so:
let images;
let enemies = [];
function preload(){
// load images and store them in an array
images = [
loadImage("data:image/gif;base64,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"),
];
}
function setup(){
createCanvas(600, 600);
imageMode(CENTER);
}
function draw(){
background(255);
// update + draw enemies
for(let i = 0; i < enemies.length; i++){
enemies[i].update();
}
text("click to spawn", 10, 15);
}
function mousePressed(){
// pick a random image
let randomImage = images[int(random(images.length))];
// offset the start frame of each enemy by one
let startFrame = enemies.length % randomImage.numFrames();
// make a new enemy
enemies.push(new Enemy(cloneGif(randomImage,startFrame), mouseX, mouseY));
}
function cloneGif(gif, startFrame){
let gifClone = gif.get();
// access original gif properties
gp = gif.gifProperties;
// make a new object for the clone
gifClone.gifProperties = {
displayIndex: gp.displayIndex,
// we still point to the original array of frames
frames: gp.frames,
lastChangeTime: gp.lastChangeTime,
loopCount: gp.loopCount,
loopLimit: gp.loopLimit,
numFrames: gp.numFrames,
playing: gp.playing,
timeDisplayed: gp.timeDisplayed
};
// optional tweak the start frame
gifClone.setFrame(startFrame);
return gifClone;
}
class Enemy {
constructor(skin, x, y) {
this.skin = skin;
this.x = x;
this.y = y;
}
update(){
image(this.skin, this.x, this.y);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.0/p5.min.js"></script>
The cloneGif makes a new object (which means new start frame, etc.), however it should point to the original gif's frames (which hold the pixels / ImageData)
Now each enemy starts at a new frame.
I noticed that changing the delay seems to affect all enemies: once a delay is set to one it seems the underlying imagedata is copied at the same rate.
If you need to have different delay times you can manage still access the same gif frame ImageData, but rather than relying on p5.Image to control the gif playback (e.g. setFrame() / delay()) you'd need manually manage that and render to p5's canvas:
let images;
let enemies = [];
function preload(){
// load images and store them in an array
images = [
loadImage("data:image/gif;base64,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"),
];
}
function setup(){
createCanvas(600, 600);
imageMode(CENTER);
}
function draw(){
background(255);
// update + draw enemies
for(let i = 0; i < enemies.length; i++){
enemies[i].update();
}
text("click to spawn", 10, 15);
}
function mousePressed(){
// pick a random image
let randomImage = images[int(random(images.length))];
// make a new enemy
let enemy = new Enemy({frames: randomImage.gifProperties.frames, gifWidth: randomImage.width, gifH: randomImage.height}, mouseX, mouseY);
// pick a random start frame
enemy.currentFrame = int(random(images.length));
// pick a random per gif frame delay (e.g. the larger the number the slower the gif will play)
enemy.frameDelay = int(random(40, 240));
enemies.push(enemy);
}
class Enemy {
constructor(gifData, x, y) {
this.frames = gifData.frames;
this.offX = -int(gifData.gifWidth * 0.5);
this.offY = -int(gifData.gifHeight * 0.5);
this.currentFrame = 0;
this.numFrames = this.frames.length;
this.frameDelay = 100;
this.lastFrameUpdate = millis();
this.x = x;
this.y = y;
}
update(){
let millisNow = millis();
// increment frame
if(millisNow - this.lastFrameUpdate >= this.frameDelay){
this.currentFrame = (this.currentFrame + 1) % this.numFrames;
this.lastFrameUpdate = millisNow;
}
// render directly to p5's canvas context
drawingContext.putImageData(this.frames[this.currentFrame].image, this.x + this.offX, this.y + this.offY);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.0/p5.min.js"></script>
Also notice the p5.Image does something nice about transparency (even when the original gif is missing it): that's something you'd need to manually address if going this lower level route.

How to generate random position object

I'm trying to generate 15 circles on a 1500 - 1000 space, every cirlce with a diferent position. I know how to generate 1 random circle but that's all. How should I do it?
It sounds like you're looking for a for loop:
for(int i = 0; i < 15; i++){
// draw a random circle here
}
Shameless self-promotion: here is a tutorial on for loops in Processing.
Basically, you need to create a Circle class and ArrayList which contains all your circles.
Then using a for you add in that list 15 circles passing to constructor random coordinates and a fixed width and height you decide.
class Circle {
float x, y, size;
public Circle(float x, float y, float size) {
this.x = x;
this.y = y;
this.size = size;
}
public void update() {
ellipse(x, y, size, size);
}
}
Declare globally your ArrayList. Now, in setup() you instantiate your ArrayList and populate it with randomly generated coordinates
ArrayList<Circle> circlesList; // This needs to be declared globally
float circleSize = 64; // Circles size in pixels
void setup() {
size(1500, 1000);
circlesList = new ArrayList<Circle>();
// Populating the ArrayList with circles
for (int i = 0; i < 15; i++) {
float randomx = random(0, 1500); // Random generated X
float randomy = random(0, 1000); // Random generated Y
Circle newCircle = new Circle(randomx, randomy, circleSize);
circlesList.add(newCircle);
}
}
Now in draw() function, using a foreach loop, you'll draw every single circle inside that ArrayList
void draw() {
background(255); // Background color
fill(255, 0, 0); // Circle fill color
for (Circle c : circlesList) {
c.update();
}
}
Please note that this way your circles may overlap or be a little bit outside of the screen. Ask anything if the code is unclear, don't just copy-paste it.
Hope this helped :)

draw shape on input gives unexpected result how to fix?

I want to draw a shape based on the input of a slider. see the code below:
import controlP5.*;
ControlP5 cp5;
int people = 5;
int DMamt = 0;
int peoplehis;
Slider abc;
PShape vorm;
void setup() {
cp5 = new ControlP5(this);
size(displayWidth, displayHeight);
cp5.addSlider("people")
.setPosition(10,10)
.setWidth(400)
.setRange(0,20)
.setValue(0)
.setNumberOfTickMarks(20)
.setSliderMode(Slider.FIX)
;
cp5.addSlider("DMamt")
.setPosition(450,10)
.setWidth(400)
.setRange(0,255)
.setValue(0)
.setNumberOfTickMarks(5)
.setSliderMode(Slider.FIX)
;
vorm = createShape();
frameRate(10);
}
void draw(){
if(peoplehis != people){
vorm.beginShape();
vorm.fill(DMamt);
for(int i = 0; i <= people; i++){
vorm.vertex(random(500), random(500));
}
endShape();
}
peoplehis = people;
shape(vorm, 100,100);
}
the first time i set the slider value i get a shape with the desired amount of points. but when i change the slider value after the first time the value of the slider get added to the points that are already drawn. but i want a new shape. the old shape should be gone. see below for a example:
first value of slider = 5
this gives me a shape with 5 points (GREAT);
second value of silder = 12
this gives me a shape with 17 points (NOT GREAT)
i want 12 points instead of 17.
how do i do this?? i am not very experienced with code :(
A Processing PShape can consist of multiple shapes, which you can add by calling the beginShape(), vertex(), and endShape() functions multiple times.
If you just want to recreate a new shape instead of adding multiple shapes, then call the createShape() function again to start over with a new PShape instance. Also, make sure you clear out previous frames by calling the background() function.
Here is a simple example:
PShape shape;
void setup() {
size(500, 500);
shape = createShape();
frameRate(60);
}
void mousePressed(){
shape = createShape();
shape.beginShape();
for(int i = 0; i < 3; i++){
shape.vertex(random(width), random(height));
}
shape.endShape();
}
void draw(){
background(0);
shape(shape, 0,0);
}

How to crop an image in P5?

I am working on a program in P5, an offshoot of Processing, that allows the user to upload an image, draw a line on top of the image, and then crop everything outside of the drawn shape out of the image.
(The green line jitters around on purpose)
I managed to get the points of the drawn line into an array, as well as make a shape out of these points. However, the cropping of the image is still a problem.
Processing has this functionality in vertex:
(https://processing.org/reference/vertex_.html)
However, I don't believe P5 has this functionality. I really don't want to have to convert the entire sketch into Processing. Is there any way to do this in P5, or to quickly convert this sketch into processing?
// Make a variable to store the start image, as well as the drop image.
var img;
var cropX = [];
var cropY = [];
var pos = 25;
// Make an array for all paths.
var paths = [];
// Make a bool for whether or not I am painting.
var painting = false;
// Int for how long until drawing the next circle
var next = 10;
// Make vars for vectors that determine where the line is drawn.
var current;
var previous;
// Make ints for how much the lines dance around.
var shake = 10;
var minShake = shake * -1;
var maxShake = shake * 1;
// Make an int for the line thickness.
var thickness = 2;
var camera;
var tracing = false;
// Make vars to store the random values for colours into.
var rc1;
var rc2;
var rc3;
// Variable for the framerate.
var fr;
// Variable that disables drawing lines when you didn't upload an image yet.
var tracing = false;
//------------------------------------------------------------------------------------------------
function preload() {
//Load the starting image, and store it in img.
img = loadImage("assets/startscreen.png");
//Load the sound that plays when you export a screenshot.
soundFormats('mp3');
camera = loadSound('assets/camera.mp3');
}
//------------------------------------------------------------------------------------------------
function setup() {
// Set the framerate so the lines don't jump about too quickly.
fr = 20;
// Setup a canvas
var c = createCanvas(1680, 1050);
// Store a random value out of 255 into the random colour values.
rc1 = random(255);
rc2 = random(255);
rc3 = random(255);
// Apply the right framerate
frameRate(fr);
// Add an event named drop, that runs function gotFile when a file is dropped onto the canvas
c.drop(gotFile);
// Store 0,0 vectors in current and previous.
current = createVector(0, 0);
previous = createVector(0, 0);
};
//------------------------------------------------------------------------------------------------
function draw() {
// Colour the background dark grey.
background(200);
// Draw the loaded image at 0,0 coordinates.
image(img, 0, 0);
//------------------------------------------------------------------------------------------------
// Count if I've been painting for longer than the 'next' variable.
// Also check if tracing is enabled (if I've dropped an image or not).
// If these are true I can draw a new line.
if (millis() > next && painting && tracing) {
// Grab mouse position and store it in variables mouseX and mouseY.
current.x = mouseX;
current.y = mouseY;
// Add new particle
paths[paths.length - 1].add(current);
// Update the 'next' variable, to allow itself 200 extra millisecond for drawing the actual line.
next = millis() + 200;
// Move the mouse values used to draw the end of the line
// to a variable used to draw the start of the line,
// so that the line is continuous.
previous.x = current.x;
previous.y = current.y;
append(cropX, current.x);
append(cropY, current.y);
}
// Make an integer called i, with a value of 0.
// Add 1 to i for each item in the array paths.
// Run this once for each item in the array.
// Name each item in the array 'i' while working.
// Display each item in the array.
for (var i = 0; i < paths.length; i++) {
// Update the current object in the array.
paths[i].update();
// Display each item in the array.
paths[i].display();
}
noStroke();
noFill();
beginShape();
for (var i = 0; i < cropX.length; ++i) {
vertex(cropX[i], cropY[i]);
}
endShape(CLOSE);
}
//------------------------------------------------------------------------------------------------
var ready = false;
// Make a function called gotFile, using the variable file.
function gotFile(file) {
// Check if the dropped file is an image file
if (file.type === 'image') {
// Enable drawing lines.
tracing = true;
// if (ready) {
// img.remove();
// }
// Store the dropped image in the container which used to hold the startimage.
img = createImg(file.data).style("opacity: 100; position: absolute; top: -10; right: -10; z-index: 100;draggable=false;");
ready = true;
// Error message in case not an image file.
} else {
println('Not an image file!');
}
}
//------------------------------------------------------------------------------------------------
function mouseWheel(event) {
//event.delta can be +1 or -1 depending
//on the wheel/scroll direction
print(event.delta);
//move the square one pixel up or down
pos += event.delta;
//uncomment to block page scrolling
return false;
}
function mouseDragged() {
return false;
}
// If left mousebutton is pressed down,
function mousePressed() {
if (mouseButton == LEFT) {
// set the variable counting when to place a new line to 0,
next = 0;
// set painting to true,
painting = true;
// store the mouse coordinates in mouseX and mouseY,
previous.x = mouseX;
previous.y = mouseY;
// and add a new Path method to the array.
paths.push(new Path());
}
}
// When mouse is released, set painting to false, which disables any paths being drawn.
function mouseReleased() {
painting = false;
}
//------------------------------------------------------------------------------------------------
// Describe the Path function that should be pushed to the array.
function Path() {
// Create an array inside this function named particles.
this.particles = [];
}
// Add the variable position to the function Path as its function'()' variable.
Path.prototype.add = function(position) {
// Add a new particle to this particle array with a position and hue.
this.particles.push(new Particle(position, this.hue));
}
// Take the Path() function, and and add this command to it.
Path.prototype.update = function() {
// Make an integer called i, with a value of 0.
// Add 1 to i for each item in the array paths.
// Run this once for each item in the array.
// Name each item in the array 'i' while working.
// Display each item in the array.
for (var i = 0; i < this.particles.length; i++) {
this.particles[i].update();
}
}
// Display the Path array.
Path.prototype.display = function() {
// Loop through the array of particles backwards.
for (var i = this.particles.length - 1; i >= 0; i--) {
// Display each of these particles.
this.particles[i].display(this.particles[i + 1]);
}
}
// Particles along the path
function Particle(position, hue) {
// Set the position of Particles to the mouseposition by creating a vector.
this.position = createVector(position.x, position.y);
}
// Constantly update Particle.
Particle.prototype.update = function() {}
// Draw particle and connect it with a line
// Draw a line to another
Particle.prototype.display = function(other) {
stroke(255, 255);
// If we need to draw a line
if (other) {
stroke(rc1, rc2, rc3);
strokeWeight(thickness);
line(this.position.x + random(minShake, maxShake), this.position.y + random(minShake, maxShake), other.position.x + random(minShake, maxShake), other.position.y + random(minShake, maxShake));
}
if (keyIsDown(LEFT_ARROW) && !camera.isPlaying()) {
camera.play();
save('myRemix.jpg');
print(cropX);
print(cropY)
}
}
The vertex() function you pointed out isn't cropping the image.
To crop an image, you probably want to use the PImage.mask() function. This lets you overlay a mask image overtop your original image so that only parts of your original image are visible.
You can also use a PGraphics instance as a mask image, so you can draw whatever mask you want. Here's a small example that creates a PGraphics mask consisting of an ellipse, then masks the original photo with that mask:
PImage photo;
PGraphics maskImage;
void setup() {
size(100, 100);
photo = loadImage("pic.jpg");
maskImage = createGraphics(photo.width, photo.height);
maskImage.beginDraw();
maskImage.background(0);
maskImage.fill(255);
maskImage.ellipseMode(RADIUS);
maskImage.ellipse(photo.width/2, photo.height/2, 500, 500);
maskImage.endDraw();
photo.mask(maskImage);
}
void draw() {
background(255, 0, 0);
image(photo, 0, 0, width, height);
}
Your sketch would use a shape instead of an ellipse, but those are the basics.

Resources