New py5 Release: 0.8.1a1

This is a minor release with many bug fixes and several new features.

Announcements

The big announcement is that py5 is now receiving direct support from the Processing Foundation to fund the creation of beginner tutorials. This is a part of the Processing Foundation's GSoC 2022 program. Our talented contributor, Zelle Marcovicci, is doing an amazing job writing tutorials. I am so deeply grateful for all of this.

We can now affirmatively state that py5 works on Apple Silicon (macOS-aarch64) machines. Hooray!

This release uses the latest Processing 4.0b9 jar files.

Pull Requests

There were two pull requests from Alexandre Villares to improve py5's translator utilities for converting code between processing.py, py5 imported mode, and py5 module mode.

New Features

This release has a handful of new features, almost all of which are the product of conversations with members of the py5 community.

Colors

You'll now be able to use the name of any color that matplotlib accepts as a parameter to any py5 method that requires a color value argument. For example:

py5.background('red')
py5.fill('b')
py5.stroke('xkcd:lilac')

Go to the matplotlib website for the full list of possible colors.

New hex_color() method

Processing and py5 store color values in 32 bit integers that are inconvenient for a human to parse. For example, a pleasant green color I randomly selected while writing this post is the integer -16744384. You could extract meaningful information from that number with the methods red(), green(), and blue(). The new hex_color() method provides an alternative approach, converting the integer -16744384 to the more readable string '#008040FF'. This is an 8 digit hex color code and is consistent with CSS colors. Like CSS, the channel order is red, green, blue, and alpha. This hex string can serve as the input to any py5 method that requires a color value argument.

Note that you can also specify colors with hexadecimal numbers such as 0xFF008040, but the channel order is alpha, red, green, and blue. This is consistent with Processing and Processing.py.

New select methods

There are three new methods for prompting the user to select a folder, an input file, or an output file. The methods are select_folder(), select_input(), and select_output(). Here is a working example:

def file_selected(selection):
    if selection is None:
        py5.println("Window was closed or the user hit cancel.")
    else:
        py5.println("User selected " + selection)


def setup():
    py5.select_input("Select a file to process:", file_selected)

In this example, py5 is able to use the file_selected() function as a callback after the user has selected an input file. The methods select_folder() and select_output() work the same way.

On OSX, these methods do not work when py5 is run in a Jupyter notebook environment. OSX users are encouraged to use IPython widgets for selection instead.

On Windows and Linux, py5 will use Java's (non-native) select dialog boxes, so they will look a little different from what you may be used to seeing. On OSX, py5 will use the operating system's native dialog boxes.

Upgraded random_choice() method

The random_choice() method has been upgraded to include an integer size parameter to specify the number of items to select and a boolean replace parameter to specify if items should be selected with or without replacement.

New np_random property

The numpy library contains many, many random number generation functions, and py5 cannot possibly serve as an interface to them all. To make the full breadth of numpy's random number generation capabilities available to py5 users in a way that still cooperates with py5's random_seed() method, use the property np_random. This will give you access to the random number generator that py5 uses to provide its random number functionality. Below is an example using numpy's shuffle() method:

def setup():
    words = ["apple", "bear", "cat", "dog"]
    py5.np_random.shuffle(words)
    # Prints the words in a random order
    for word in words:
        py5.println(word)

New g property

Use the g property to access the Py5Graphics object used to draw the graphics of the Sketch. This accesses the same object as get_graphics() but with less typing.

New next_page() method, exclusive to the PDF renderer

Use the next_page() method to move to the next page in a PDF document. This method is only available when using a PDF Py5Graphics object. Using this method with any other graphics renderer will result in an error.

Below is an example of its proper use:

def setup():
    py5.size(600, 600, py5.PDF, "/tmp/test.pdf")


def draw():
    for _ in range(50):
        py5.rect(py5.random_int(py5.width), py5.random_int(py5.height), 10, 10)

    if py5.frame_count < 5:
        py5.g.next_page()
    else:
        py5.exit_sketch()

Proper object equality

This is going to seem like a silly little thing but this is actually quite important. This change is best illustrated with an example that didn't work with previous py5 versions but does work now:

def setup():
    py5.size(200, 200)
    g1 = py5.get_graphics()
    g2 = py5.get_graphics()
    assert g1 == g2
    assert g1 is g2

Previously, the variables g1 and g2 would be two different Python Py5Graphics objects that both reference the same Java PGraphics object. Now there is only one Python py5 object for each Java Processing object. This applies for all of py5's object classes (Py5Surface, Py5Shape, Py5Image, etc.)

Nobody asked for this change and it does not currently solve any problems. I'm constantly thinking about how to enhance py5 over the long term. This is a necessary feature for what's to come.

Bug fixes

What's Ahead

  • Priority #1: Supporting Zelle and our GSoC documentation efforts

  • I will write some tutorials on some of py5's advanced features

  • Unit tests? I can't keep pushing this off.

Comments