The 2024 Plotnine Contest will close in 5 days on 26th July 2024, this is after a two week extension.

We have many submissions already but we could have move in these two categories.

1. Visualisation of Distributions#

Most of the time, the main plot of statistical graphics is to get a sense of how the data is distributed. I would love to see more submissions of this type. This resource from the University of Iowa is a good introduction to the kinds of ways you can visualise distributions. I think there is plenty of room for otherwise simple visualisations of data distributions made more compelling by the choice of dataset, colors, annotations and overall polish.

2. Visualisation Art#

Plotnine implements The Grammar of Graphics, which moulds Drawing and Painting Art into a system suitable for statistical graphics. Constrained within, the Art says “I want to break free” and a contest is the party at which to break free. We got all week.

A contest can trigger you into action on tasks you’ve long procrastinated or avoided due to concerns about developing an unhealthy addiction. This one may have got me. Inspired by a Yan Holtz piece, Michael Chow has deeped into generative art for this contest. In turn, I have given it a go.

From Yan and through Michael, I get an abstract form and first I unpaint it to reveal its spiky nature.

The Spiky World#

Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from plotnine import (
    aes,
    coord_cartesian,
    element_rect,
    geom_area,
    ggplot,
    scale_color_manual,
    theme_void,
    theme,
)
import pandas as pd
import numpy as np


num_groups = 30

def get_colors(cmap_name, start=0, stop=1, n=10):
    """Return colors from a colormap"""
    from mizani.palettes import get_colormap
    x = np.linspace(start, stop, n)
    return get_colormap(cmap_name).continuous_palette(x)

def combine(colors: list[str]):
    from mizani.palettes import gradient_n_pal
    x = np.linspace(0, 1, num_groups)
    return gradient_n_pal(colors)(x)

def make_data(seed=123):
    names = [f"G{i}" for i in range(num_groups)]
    population = [0] * 100 + list(range(1, num_groups+1))
    rs = np.random.RandomState(seed)
    frames = []
    for i in range(30):
        arr = rs.choice(population, num_groups)
        _data = pd.DataFrame({
            "x": i,
            "y": arr / np.sum(arr),
            "g": rs.choice(names, num_groups, replace=False),
        })
        frames.append(_data)
    return pd.concat(frames).sort_values(["x", "g"])

def blink(colors: list[str] | list[list[str]], seed=123):
    data = make_data(seed)
    p = (
        ggplot(data, aes(x="x", y="y", fill="g", color="g"))
        + geom_area(show_legend=False)
        + coord_cartesian(expand=False)
        + scale_color_manual(values=combine(colors), aesthetics=["fill", "color"])
        + theme_void()
    )
    return p

(
    ggplot(make_data(), aes(x="x", y="y", group="g"))
    + geom_area(fill="white", color="black", show_legend=False)
    + coord_cartesian(expand=False)
    + theme_void()
    + theme(plot_background=element_rect(fill="white"))
)

Then with each blink of the eye, The Spiky World reveals one of her infinite faces.

Blink.

Spiky Desert Dunes#

Code
1
blink(get_colors("inferno", .5, 1)[::-1])

Blink.

A Spiky Volcano#

Code
1
blink(get_colors("magma", .3, .95))

Blink.

A Morning in a Spiky Forest#

Code
1
blink(get_colors("Greens"))

Blink.

A Spiky Sunset at the Beach#

Code
1
2
3
4
5
blink([
    *reversed(get_colors("YlOrBr", 0.4, 0.7)),
    *reversed(get_colors("Blues", 0.25, 0.7)),
    *reversed(get_colors("Oranges", 0.05, 0.3)),
])

This is generative art, the art that never ends. I did not know. I started blinking. I must continue blinking forever.

Create your world, blink and share what you see.