Tips for Processing Java Users#

Welcome!

We hope you enjoy using the Processing graphics vocabulary, now with Python 3. This page shows all examples in py5 imported mode style. You can learn more about the py5 modes at The Five py5 Modes. Some of the tips here might be useful to Processing Python mode users too, as they show some new Python 3 related behavior and things that py5 does differently from Processing altogether.

The slightly different snake_case names#

The first thing you might notice is how the Processing function/method names you were used to followed the Java community’s convention called camelCase and on py5 they use the Python community’s snake_case convention: mouseX becomes mouse_x, and noFill() becomes no_fill(), etc.

Another thing you should know is that the global mousePressed variable becomes is_mouse_pressed and the event function we define for a “mouse pressed event”, that in Java would be written void mousePressed(){ ..., should now be defined as def mouse_pressed(): ....

This is because in Python the namespace for variable names and function names is the same. Note also that keyPressed becomes is_key_pressed for the variable, and key_pressed() for the event function.

Processing’s map(value, start, end, target_start, target_end) is now remap() because there is a Python built-in map(func, iterable). Likewise, filter() becomes apply_filter().

Processing’s get() and set() functions to manipulate pixels become get_pixels() and set_pixels(), but you might want to read about np_pixels and set_np_pixels(). That’s because in Python, set() creates a set data structure.

Instead of frameRate, use the frame_rate() function to set a target frame rate and the get_frame_rate() function to find out the current frame rate (an exponential moving average).

For more advanced users, if you used the g reference to the main PGraphics object, you can obtain an equivalent Py5Graphics object with get_graphics(). The this reference to the current sketch that must be passed to some libraries, like PeasyCam or Camera3D, can be obtained with this = get_current_sketch(). And lastly, if you need to terminate a sketch from its own code, to end the sketch properly use exit_sketch() instead of Python’s exit(), so it won’t skip the normal sketch clean up and the “exiting event” that will trigger a call to exiting(), if it exists, a function you can define with def exiting(): to run some code as the sketch ends.

Important

Please have a look at the py5 Reference Summary, it will help you find any missing names.

How about the P-Classes?#

Most of Processing high-level objects, like PFont for typography fonts, or PImage, for image buffers, have an equivalent, a wrapper, in py5. So Py5Font does whatever PFont does, and Py5Image everything PImage does, with some bonus stuff: Py5Image brings in a very helpful new numpy interface for an “array of pixels”.

If you are used to PVector, please note that Py5Vector is a completely new implementation of vector objects, 2D, 3D and 4D, so it has some different method & attribute names, you won’t regret reading the Py5Vector documentation.

More tips for porting Processing Java code to py5#

Maybe you want to port some existing Processing Java code to Python + py5? The following tips should help you with the most common issues.

Getting started on quick code conversions!#

  • As you probably know already, Python uses indentation to place code lines ‘inside’ a function definition and in many other code nesting structures. In Java the braces{} rule, but it is common for the indentation to also reflect the code hierarchy, even if this is not mandatory, so use the IDE auto-formatting tool before you start, and take care!

  • The braces need to be removed, and you should replace each { with : at the beginning of an instruction block (this is not true for array definitions, which have braces but are not an instruction block, and will probably become a list or tuple with [] or ().

  • Remove the ; at the end of the lines.

  • Comments with // in Java become comments with #. Multiline comments with /*...*/ can be converted to docstrings, with triple quotes in Python, """ ... """.

  • Java is a static typing language and Python is a dynamic typing language that means we can remove all type declarations and everything should work fine, but, alternatively, one can keep the type information as type annotations that can then be used by a static type checking tool (like mypy or the checkers in some IDEs).

  • For variables, you either simply remove the type int, float, String, color, boolean from variable declarations (for example, int i = 0; becomes i = 0), otherwise you can write i : int = 0, in this case String should be written str, Boolean will become bool and you might have to figure out a few other different class/type names.

  • On function definitions, we should remove void or any return type declaration, replacing it with Python’s def. You can optionaly annotate the return type using -> T: as shown below. The type declaration of parameters should be removed or should follow the same pattern as the annotations for variables.

    Java

    float average(float a, float b) {
      return (a + b) / 2;
    }
    

    Python

    def average(a, b):
        return (a + b) / 2
    

    Type annotated Python

    def average(a: float, b: float) -> float:
        return (a + b) / 2
    

A table with some equivalences for conversion#

Boolean values in Java are named true and false, in Python they are True and False. Let’s make a chart with the logical operators and some other equivalences.

Java

Python

void func() {...}

def func():...

true and false

True and False

a && b (logical AND)

a and b

a || b (logical OR)

a or b

!a (logical NOT)

not a

i++ (increment)

i += 1

i-- (decrement)

i -= 1

a <= b && b < c

a <= b < c

for (int i=0; i<limit; i++) { ...

for i in range(limit): ...

for (int i=start; i<limit; i+=step) { ...

for i in range(start, limit, step): ...

for (Ball b : arrayListOfBalls) { ...

for b in list_of_balls: ...

fill(#FFCC00) // hexadecimal color notation

fill('#FFCC00') # needs ' ' or " "

Similar to null in Java we have the special value None in Python, they are not totally equivalent but it is usually a good guess to make the substitution.

Looping with for#

The simplest case is a for based on a counter, such as for (int i=0; i<limit; i++) { ... which translates into for i in range(limit): ... and the so-called for each loop, shown in the chart, is also very straightforward.

But if you have a Java for loop with a float step, as the range() based for construct in Python works only with integers, you might want to convert it to a while loop like in the example below, or use a ‘special’ non-int range generator.

Java

float angleStep = TWO_PI / 18
for (float angle=0; angle < TWO_PI; angle += angleStep){ 
    ...
}

Python

Using a while loop

angle_step = TWO_PI / 18
angle = 0
while angle < TWO_PI:
    ...
    angle += angle_step

Using numpy

import numpy as np

angle_step = TWO_PI / 18
for angle in np.arange(0, TWO_PI, angle_step):
    ...

Another option would be to define a ‘special’ range generator:

def frange(start, stop=None, step=1):
    if stop is None:
        stop, start = start, 0
    assert step != 0, "step can't be zero"
    invalid_limit_error_message = (
        'start must be smaller than stop for positive step'
        if step > 0 else
        'stop must be smaller than start for negative step'
    )
    assert stop > start if step > 0 else stop < start, invalid_limit_error_message
    count = start
    while count < stop:
        yield count
        count += step

# and then frange in use...
angle_step = TWO_PI / 18
for angle in frange(0, TWO_PI, angle_step):
    ...

Now an example of a loop made just to get objects from a data structure:

for (int i = 0; i < my_array.length; i ++) {
  something(my_array[i]);
}

Python

for item in my_list:
    something(item)

or, if you need the index.

for i, item in enumerate(my_list):
    something(i, item)

Here a reversed iteration for removing items from an ArrayList in Java, a list in Python:

Java

for (int i = particles.size() - 1; i >= 0; i--) {
  Particle p = particles.get(i);
  p.run();
  if (p.isDead()) {
    particles.remove(p);
  }
}

Python

for i, p in reversed(list(enumerate(particles))):
    p.run()
    if p.is_dead():
        del particles[i]

or maybe:

for i in reversed(range(len(particles))):
    p = particles[i]
    p.run()
    if p.is_dead():
        del particles[i]

if, else and their friends#

Note that the if condition in Python does not require the parentheses as in Java. The combination of else if becomes the elif contraction.

Java

for (int i = 2; i < width-2; i += 2) {
  if ((i% 20) == 0) {
    stroke(255);
    line(i, 80, i, height / 2);
  } else if ((i% 10) == 0) {
    stroke(153);
    line(i, 20, i, 180);
  } else {
    stroke(102);
    line(i, height / 2, i, height-20);
  }
}

Python

for i in range(2, width - 2, 2):
    # If 'i' divides by 20 with no remainder
    if i % 20 == 0:
        stroke(255)
        line(i, 80, i, height / 2)
    elif i % 10 == 0:
        stroke(153)
        line(i, 20, i, 180)
    else:
        stroke(102)
        line(i, height / 2, i, height - 20)

Ternary operator#

Java

result = cond ? a : b

Python

result = a if cond else b

switch & case#

Until recently there was nothing like Java’s switch / case in Python, now from Python 3.10 onwards we get the match / case construct that could be used to translate that, but some people still frown upon it. You can arguably convert Java code with switch / case to a sequence of if / elif or, if just to call different functions, a function dictionary.

Java

char letter = 'b';

switch(letter) {
  case 'a':
  case 'A': 
    println("Alpha");  // Does not execute in this example
    break;
  case 'b':
  case 'B': 
    println("Bravo");  // Prints "Bravo"
    break;
  default:            // default is optional
    println("Not found");  
    break;
}

Python

letter = 'b'

if letter == 'a' or letter == 'A':
    println("Alpha")  # Does not execute in this example
elif letter in ('b', 'B'):
    println("Bravo")  # Prints "Bravo"
else:
    println("Not found")  

You might want to try a dictionary strategy.

def setup():
  size(400, 400)

def t( x, y, w, h):
    triangle(x, y, x + w, y, x, y + h)

func = {
    'r': rect,
    'e': ellipse,
    't': t,
    'default': rect,
    } 

def draw():
    func.get(key, func['default'])(100, 100, 200, 50)

Global variables#

If a variable is declared and initialized (type and value are defined) at the beginning of the sketch, like in the example bellow int rad = 60;, you can remove the type declaration and semicolon, leaving just rad = 60 (or change it to an annotated assignment, like rad: int = 60).

Since there is no way in Python to declare a variable without making an assignment, when the variable is just declared (a type is set without initialization) at the beginning of the sketch, we need to find where it is assigned for the first time and add the global variable_name statement at the beginning of that function.

In fact, every function that changes the assignment of global variables in its body needs the global statement with the names of the variables that are modified.

An example:

Java

int rad = 60;       // Width of the shape
float xpos, ypos;   // Starting position of shape
float xspeed = 2.8; // Speed of the shape
yspeed float = 2.2; // Speed of the shape
int xdirection = 1; // Left or Right
int ydirection = 1; // Top to Bottom

void setup()
{
  size(600, 300);
  // Set the starting position of the shape
  xpos = width / 2;
  ypos = height / 2;
}

void draw()
{
  background(102);
  xpos = xpos + (xspeed * xdirection);
  ypos = ypos + (yspeed * ydirection);
    
  if (xpos > width-rad || xpos < rad) {
    xdirection * = -1;
  }
  if (ypos > height-rad || ypos < rad) {
    ydirection * = -1;
  }

  ellipse(xpos, ypos, rad * 2, rad * 2);
}

Python

rad = 60; # Width of the shape
# The original had this here: float xpos, ypos; // Starting position of shape
xspeed = 2.8;   # Speed of the shape
yspeed = 2.2;   # Speed of the shape
xdirection = 1; # Left or Right
ydirection = 1; # Top to Bottom

def setup(): 
    size(600, 300)
    global xpos, ypos # xpos, ypos are assigned first here in setup
    noStroke()
    xpos = width / 2
    ypos = height / 2

def draw():
    global xpos, ypos, xdirection, ydirection # will be changed!
    background(102)
    xpos + = xspeed * xdirection
    ypos + = yspeed * ydirection
    
    if xpos < rad or width - rad < xpos: # note that rad is never changed
        xdirection * = -1
    if ypos < rad or height - rad < ypos:
        ydirection * = -1
    ellipse(xpos, ypos, rad * 2, rad * 2)

Integer Division#

In Java, arithmetic operations on integers will always yield an integer result. This is true for all operations, including division. Therefore, 5 / 2 in Java will equal 2.

In Python, arithmetic operations are handled differently. Python (3+) evaluates 5 / 2 as 2.5. If you want the same 2 result as Java, use the integer division operator //, as in 5 // 2.

Strings#

Type char in Java

Java has a special type for characters, char, with literals written in code with single quotes ' ', Python makes no such distinction, using single character strings (in key, for instance) and single or double quotes for strings in general.

To get a character at a certain position in a string, in Java, a special method is needed:

String word = "love";
char c = word.charAt(1); // c = 'o'

In Python the index notation [i] gets you a single character string from a string:

word = 'love'
c = word[1] # c = 'o'

Comparing strings in Java

String str1 = "love";
String str2 = "love";
// Test if str1 is equal to str2
if (str1.equals(str2)) {
  println("equal"); } else {
  println("not equal"); 
}

Comparing strings in Python

str1 = "love"
str2 = "love"
# Test if str1 is equal to str2
if str1 == str2:
  println("equal")
else:
  println("not equal")

Importing libraries and using multiple files in your sketch#

Noimport processing.pdf.*; is needed for using the Processing PDF export feature with py5, same with SVG, but for other Processing Java libraries… it could be more complicated. Have a look at the Camera3D tutorial for an example.

In Processing Java mode the libraries are imported with import but in Python mode this instruction is more often used to import modules from the Python standard library, other installed Python libraries, and .py files in the same folder.

Unlike in Processing Java mode, other files in the same folder, that would appear as tabs in the Processing IDE, are not automatically a part of your sketch, and you have to import them or parts of their content.

Here you can see a few ways you can bring in functions and classes from other modules/libraries or other files, if you split your sketch into several .py files.

import numpy as np
import library_with_a_big_name as short_alias

from shapely import Polygon

from some_module_or_other import helpful_function

from my_other_file import MyClass, my_function # from other_file.py in the same folder
# this is generally considered not very good style, and could be trouble with libraries
from other_file import *  # everything from other_file.py

When you are using py5 in imported mode with code split in more than one file, you might need to add the special comment, # PY5 IMPORTED MODE CODE, to the head of your other files, like explained on this Importing Imported Mode Code section.

Object Orientation#

Getting an instance and access to its methods and attributes#

Java needs the keyword new to create an instance of a class, just remove it! Access to methods and attributes is exactly the same.

Java

import camera3D.Camera3D;

Camera3D camera3D;

void setup() {
  size(600, 600);
  camera3D = new Camera3D(this);
  camera3D.setBackgroundColor(192);
}

Python

from camera3D import Camera3D

def setup():
    global camera3D
    size(600, 600)
    this = get_current_sketch()    
    camera3D = Camera3D(this)
    camera3D.setBackgroundColor(192)

Declaring a class#

Class declarations change slightly, roughly, the def __init__(self ...): ... method plays the same initialization role of the constructor method of a Java class (the method with the same name as the class). Strictly, the __init__() method, which we read like “dunder init”, is not a constructor, but you don’t have to worry about it. If you are curious, read more about Python’s “data model” at the Python docs.

By convention, you’ll add self as the first parameter of each method, and then use self. to access its members, any methods or attributes, of the class or instance.

Let’s see the MRect class in the example Basics > Objects > Objects that comes with the Processing IDE.

Java

class MRect 
{
  int w; // single bar width
  float xpos; // rect xposition
  float h; // rect height
  float ypos ; // rect yposition
  float d; // single bar distance
  float t; // number of bars
 
  MRect(int iw, float ixp, float ih, float iyp, float id, float it) {
    w = iw;
    xpos = ixp;
    h = ih;
    ypos = iyp;
    d = id;
    t = it;
  }
 
  void move(float posX, float posY, float damping) {
    float dif = ypos - posY;
    if (abs(dif) > 1) {
      ypos -= dif/damping;
    }
    dif = xpos - posX;
    if (abs(dif) > 1) {
      xpos -= dif/damping;
    }
  }
 
  void display() {
    for (int i=0; i<t; i++) {
      rect(xpos+(i*(d+w)), ypos, w, height*h);
    }
  }
}

Python

class MRect:

    def __init__(self, iw, ixp, ih, iyp, id, it):
        self.w = iw  # single bar width
        self.xpos = ixp  # rect xposition
        self.h = ih  # rect height
        self.ypos = iyp  # rect yposition
        self.d = id  # single bar distance
        self.t = it  # number of bars

    def move(self, posX, posY, damping):
        self.dif = self.ypos - posY
        if abs(self.dif) > 1:
            self.ypos -= self.dif / damping

        self.dif = self.xpos - posX
        if abs(self.dif) > 1:
            self.xpos -= self.dif / damping

    def display(self):
        for i in range(self.t):
            rect(self.xpos + (i * (self.d + self.w)),
                 self.ypos, self.w, height * self.h)

You can read about Object Orientafion in Python at the official Python Tutorial, for instance, details like how inheritance works in Python.

Data structures#

Arrays like int[], float[] or PVector[] usually become lists in Python (sometimes tuples if they are created and left alone). And a Java ArrayList is very much like a Python list:

Java

ArrayList<Fruit> fruits; // a list of Fruit objects

void setup() {
  size(400, 400); 
  fruits = new ArrayList<Fruit>();
  for (int i=0; i <50; i++) {
    fruits.add(new Fruit(100, 100, 12));
  }
}

Python

fruits = []  # a list of Fruit objects

def setup():
    size(400, 400); 
    for i in range(50):
        fruits.append(Fruit(100, 100, 12))

Or you could use a list comprehension:

def setup():
    global fruits
    size(400, 400); 
    fruits = [Fruit(100, 100, 12) for i in range(50)]

2D Arrays#

Java

int[][] board;
board = new int[grid_w][grid_h]

Python

board = [[0] * grid_w for _ in range(grid_h)]

Instead of 0 it could be a None placeholder or any calculated value if the structure will hold other things.

Python with numpy

import numpy as np

board = np.zeros((2, 3))
print(board)
# array([[0., 0., 0.],
#        [0., 0., 0.]]

Other things you might want to explore#

  • HashMap and FloatDict, are mapping data structures in Java, they become dictionaries (dict) in Python.

  • If an array or an ArrayList is used to retain some kind of ‘history’, you might want to learn about double ended queues, deque (from collections import deque).

  • Very simple classes in Java might suitably become just a named tuple or a data class.