October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
ThatPainter
creative coding

How to Create Digital Generative Art With Python

Build your own procedural artwork with Python, NumPy and Pillow. This practical guide covers seeded randomness, flow fields, RGBA layering, parameter experiments, reproducible series and troubleshooting.

By ThatPainter Team 9 min read
Performance · Free Tool

PC Slower Than It Used to Be?

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.

Run a Free PC Scan →Free scan · Windows 10 & 11

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

ThatPainter is reader-supported. When you buy through links on our site, we may earn an affiliate commission. Learn More

You can create original, repeatable digital artwork with a small Python stack: NumPy for coordinates, arrays and controlled randomness, Pillow for drawing and compositing, and optionally Matplotlib for mathematical fields and colormaps. The key is to treat the artwork as a system of rules, parameters and randomness—not as an unconstrained random image.

This guide builds a complete flowing-circles generator, then shows how to vary it, render a reproducible series, work directly with pixels and troubleshoot the usual problems.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What generative art means in Python

Generative art is artwork produced by a defined system: algorithms, geometry, data, simulations or randomness. The artist still chooses the geometry, palette, constraints, composition, degree of randomness, iteration process and which results are worth keeping.

This is different from prompt-based AI image generation. A NumPy-and-Pillow sketch is algorithmic or procedural art: you can inspect every rule, change a parameter and reproduce an edition. AI image tools use trained models to respond to prompts or other conditioning. Both can be legitimate creative practices, but they offer different kinds of control.

Approach Main mechanism Typical Python tools
Rule-based generative art Explicit algorithms and constraints NumPy, Pillow, Matplotlib
Procedural art Mathematical or simulated processes such as noise, particles or cellular automata NumPy, SciPy, Pillow
AI image generation Trained models responding to prompts or conditioning Model APIs, diffusion libraries or hosted services

You need only variables, functions, for loops, imports and basic image coordinates to begin. Trigonometry, virtual environments and NumPy broadcasting help later but are not prerequisites.

Install the tools

Install Python from the official download page. The Python documentation currently describes the 3.14 series (July 2026); check the support pages again when you install because versions change. Pillow’s documentation currently identifies version 12.3.0, but its supported Python matrix should be treated as authoritative for your date and platform.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create an isolated project so packages do not conflict with other work:

mkdir generative-art
cd generative-art
python -m venv .venv

Activate it on macOS or Linux:

source .venv/bin/activate

On Windows PowerShell:

.venvScriptsActivate.ps1

Install the core libraries. Using python -m pip ensures pip belongs to the interpreter that will run your script:

python -m pip install --upgrade pip
python -m pip install pillow numpy matplotlib

On a Windows installation where python is not recognized, use the launcher:

py -m pip install pillow numpy matplotlib
py -c "import PIL, numpy, matplotlib; print('Setup works')"

Otherwise verify with:

python -c "import PIL, numpy, matplotlib; print('Setup works')"

Install the package named pillow, but import it as from PIL import Image; import pillow is not the normal API.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Your first generated image: flowing translucent circles

Save this as generate.py:

from pathlib import Path
import math

import numpy as np
from PIL import Image, ImageDraw


# ---------- Artistic parameters ----------
WIDTH = 1600
HEIGHT = 1200
SEED = 42
COUNT = 900
OUTPUT = Path("generative_circles.png")

BACKGROUND = (13, 18, 35, 255)
PALETTE = [
    (255, 99, 146, 150),
    (255, 178, 92, 145),
    (89, 214, 196, 140),
    (107, 139, 255, 145),
    (220, 120, 255, 135),
]

rng = np.random.default_rng(SEED)

image = Image.new("RGBA", (WIDTH, HEIGHT), BACKGROUND)
draw = ImageDraw.Draw(image, "RGBA")

for _ in range(COUNT):
    x = rng.uniform(0, WIDTH)
    y = rng.uniform(0, HEIGHT)

    # A smooth field controls the direction of the mark.
    angle = (
        math.sin(x * 0.009)
        + math.cos(y * 0.011)
        + math.sin((x + y) * 0.004)
    ) * math.pi

    length = rng.uniform(20, 130)
    radius = rng.uniform(3, 24)

    x2 = x + math.cos(angle) * length
    y2 = y + math.sin(angle) * length

    color = PALETTE[int(rng.integers(0, len(PALETTE)))]
    outline = (*color[:3], min(255, color[3] + 35))

    draw.line((x, y, x2, y2), fill=outline, width=max(1, int(radius / 5)))
    draw.ellipse(
        (x - radius, y - radius, x + radius, y + radius),
        fill=color,
    )

image.convert("RGB").save(OUTPUT, format="PNG")
print(f"Saved {OUTPUT.resolve()}")

Run it:

python generate.py

The script creates generative_circles.png in the project directory. You should see a dark field containing hundreds of translucent colored circles and short strokes. The exact pixels can vary with library versions and rendering environments; the important result is a working, inspectable system.

How the program creates structure

Canvas and coordinates

Image.new("RGBA", (WIDTH, HEIGHT), BACKGROUND) creates a raster image. RGBA means red, green, blue and alpha (opacity). Pillow uses an upper-left origin: (0, 0) is the top-left, x increases to the right and y increases downward. Drawing outside the image bounds is discarded. See Pillow’s ImageDraw reference.

Reproducible randomness

np.random.default_rng(SEED) creates a local NumPy Generator. A fixed integer seed gives the same random sequence in the same relevant environment, which makes debugging and comparing parameter changes possible. During exploration you can use np.random.default_rng() without a seed for a fresh result each run.

A seed is not a permanent guarantee of identical pixels. NumPy documents that Generator does not promise bitstream compatibility across all future versions. Fonts, operating systems, color management and rendering libraries can also alter output. For archival work, record the source code, seed, every parameter, Python and package versions, operating system, fonts, input assets and output format.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Controlled randomness

Positions, radius, length and color are random, but each is bounded. A small palette and a direction field give the marks a visual relationship. Unconstrained random dots often read as noise; constraints turn variation into composition.

The mathematical field

The sine and cosine expression maps each location to an angle. Smaller multipliers such as 0.004 make broad, slowly changing flows. Larger multipliers create tighter turns. Adding terms increases complexity; removing them produces a simpler rhythm.

Alpha compositing

An RGBA color is (red, green, blue, alpha), with alpha values near 0 more transparent and values near 255 more opaque. Drawing translucent marks over one another creates depth. Keep the image in RGBA while layering; flatten only when exporting to a format that does not need transparency.

Export

The final conversion to RGB removes the alpha channel before saving a broadly compatible PNG. PNG is lossless and a strong default for crisp marks. If you need transparency, save the RGBA image directly as PNG instead. JPEG is lossy:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Python Programming Funny Programmer Python Logo Sneks T-Shirt, Men, Black, 3X-Large
  • Funny python logo programming design for python programmers with a famous programmer meme of sneks as python language.
  • Programmer humor Sneks python programming design for programmers, coders, and developers who work in python language.
  • Lightweight, Classic fit, Double-needle sleeve and bottom hem
image.convert("RGB").save("generative_circles.jpg", quality=95)

Use JPEG only when its smaller files and non-transparent workflow justify possible compression artifacts.

Make one system produce many artworks

Density

COUNT = 200   # more negative space
COUNT = 2000  # denser, slower rendering

More marks do not automatically mean a better image. Watch for muddy overlaps and increased render time.

Palette

PALETTE = [
    (245, 238, 220, 150),
    (35, 61, 77, 155),
    (190, 82, 71, 145),
]

A limited palette usually creates more cohesion than independently sampling every possible color. You can also reserve one color for emphasis and use the others as supporting tones.

Field scale and geometry

Change the multipliers in the original angle expression to alter the flow. For a different mathematical behavior, try:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
angle = math.atan2(
    math.sin(y * 0.01),
    math.cos(x * 0.01),
)

For circular motion around the center:

cx, cy = WIDTH / 2, HEIGHT / 2
angle = math.atan2(y - cy, x - cx) + math.pi / 2

To create negative space, reject points inside a central radius or restrict marks to a mask. Symmetry, grids and attractors are other ways to impose intention without removing all variation.

Canvas dimensions

WIDTH = 2400
HEIGHT = 1800

A larger canvas increases memory use and does not improve composition by itself. Adjust radii, line widths and field frequencies when changing scale; otherwise marks may become too small or the flow may change character.

Render a reproducible series

Once one image works, treat each seed as an edition:

from pathlib import Path
import json

series = Path("series")
series.mkdir(exist_ok=True)

for seed in range(12):
    rng = np.random.default_rng(seed)
    # Put the generation code here, using this rng.
    # Save each image to series/art_{seed:03d}.png

Use zero-padded names such as art_003.png so files sort naturally. Save the parameters alongside the image:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Python Programming Logo for Programmers T-Shirt
  • Python Programming Language design with distressed logo for Python Software Engineers and Developers.
  • Vintage and Distressed Python Programming Language design.
  • Lightweight, Classic fit, Double-needle sleeve and bottom hem
parameters = {
    "width": WIDTH,
    "height": HEIGHT,
    "seed": SEED,
    "count": COUNT,
    "palette": PALETTE,
}

Path("parameters.json").write_text(
    json.dumps(parameters, indent=2),
    encoding="utf-8",
)

Generation is only half the practice. Review the outputs, select the strongest compositions and explain why they work. Producing thousands of variants does not remove the artist’s role as editor and curator. If you need to document the environment, save python -m pip freeze with the project.

Start with simpler projects

  1. Random dots: create a canvas, choose random coordinates and fill small circles. This teaches image creation, color selection and saving.
  2. Circles and lines: vary radius, direction, layering and alpha.
  3. Flow fields: calculate a direction from each coordinate using sine, cosine or another function.
  4. Array-based art: calculate a value for every pixel with NumPy, then map those values to colors.

Generate pixels with NumPy

This example creates a reproducible grayscale field:

import numpy as np
from PIL import Image

width, height = 1200, 900
rng = np.random.default_rng(42)

y, x = np.mgrid[0:height, 0:width]

field = (
    np.sin(x * 0.02)
    + np.cos(y * 0.015)
    + rng.normal(0, 0.12, size=(height, width))
)

normalized = (field - field.min()) / (field.max() - field.min())
image_array = (normalized * 255).astype(np.uint8)

Image.fromarray(image_array, mode="L").save("field.png")

The data flow is: mgrid creates coordinate arrays; functions create a scalar field; noise adds variation; normalization maps values to 0–1; conversion to uint8 maps them to 0–255; Pillow writes the grayscale array. The same approach can produce RGB or RGBA arrays by adding channels or applying a colormap.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

When Matplotlib is useful

Use Matplotlib when the artwork is primarily a mathematical visualization: it offers colormaps, array previews, axes-free figure export and plotting primitives. Its image tutorial documents workflows between Pillow images and 8-bit NumPy arrays.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Need Prefer
Circles, lines, polygons and layered raster images Pillow
Pixel-wide calculations, gradients, fields or simulations NumPy with Pillow
Colormaps, plots and interactive inspection Matplotlib
Resolution-independent paths SVG, Cairo or another vector workflow

Raster output is straightforward and supports texture, but it consumes memory at large sizes and is difficult to edit element by element later. Vector output scales cleanly and suits geometric designs or plotters, but complex textures may eventually need rasterization. Pillow is principally a raster tool, not an editable-vector authoring environment.

Where to go next

Once the seeded circle system is comfortable, explore particle systems, L-systems, fractals, cellular automata, Voronoi patterns, reaction-diffusion, noise fields, audio-reactive animation and plotter output. SciPy or scikit-image can add scientific filters and image processing; svgwrite or Cairo can produce vectors; pygame is useful for interactive sketches; Numba or GPU tools become relevant only after profiling shows that ordinary NumPy and Pillow are too slow.

For experimentation, Jupyter gives inline previews after each parameter change. A normal Python script is usually easier for batch rendering, packaging and long-term provenance. An editor such as Visual Studio Code is optional; neither it nor a paid creative application is required for the core workflow.

Troubleshoot common failures

ModuleNotFoundError

The package is probably installed in a different environment. Run:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Python Code Programming Syntax Computer Geek T-Shirt
  • Python Programming design. The inclusion of Python syntax makes it a fun conversation starter for fellow coding enthusiasts.
  • A playful design that resonates with developers and anyone passionate about the world of python programming.
  • Lightweight, Classic fit, Double-needle sleeve and bottom hem
python -m pip install pillow numpy matplotlib
python -c "import sys; print(sys.executable)"
python -c "import PIL, numpy, matplotlib; print('Setup works')"

Transparent marks look opaque

Confirm that the image mode is RGBA, colors have four components, the drawing context is using RGBA, and you have not flattened to JPEG. If compositing separate layers, ensure the layers are actually composited onto the image you save.

The output is black, blank or missing

Check that array values are in the expected range, normalized arrays are converted to uint8, coordinates fall inside the canvas and every generated layer is saved or composited. Print the absolute destination:

print(Path("output.png").resolve())

The image changes every run

Use one intentional generator such as rng = np.random.default_rng(42). Avoid creating unrelated unseeded generators in different functions unless that variation is deliberate.

The image is chaotic

Reduce the palette and size ranges, use a coordinate-dependent field, constrain marks to a region, add symmetry or a grid, preserve negative space and limit opacity variation.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The image is repetitive

Add a second field, vary scale and opacity independently, introduce a small amount of noise, break symmetry at selected points or use several related palettes.

Rendering is slow

Preview at a smaller size, reduce the shape count and avoid repeated image conversions or unnecessary layers. Prefer vectorized NumPy operations for large array calculations. Profile before reaching for Numba or GPU rendering; a basic Pillow/NumPy sketch rarely needs cloud hardware.

Fonts or text differ between machines

Font availability and rendering vary by operating system. Pillow supports bitmap and TrueType/OpenType fonts, but bundle or document the exact font when typography is part of the artwork.

Licensing and provenance

Python, NumPy and Pillow can provide the complete core workflow without a paid subscription. Check licenses for fonts, textures, reference images, palettes and copied code separately. Keep the source, parameter file, environment record and generated date with each edition. That record is as important to a reproducible artwork as the final PNG.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Quick Recap

Bestseller No. 3
Python Programming Funny Programmer Python Logo Sneks T-Shirt, Men, Black, 3X-Large
Python Programming Funny Programmer Python Logo Sneks T-Shirt, Men, Black, 3X-Large
Lightweight, Classic fit, Double-needle sleeve and bottom hem
$19.99
Bestseller No. 4
Python Programming Logo for Programmers T-Shirt
Python Programming Logo for Programmers T-Shirt
Vintage and Distressed Python Programming Language design.; Lightweight, Classic fit, Double-needle sleeve and bottom hem
$19.99
Bestseller No. 5
Python Code Programming Syntax Computer Geek T-Shirt
Python Code Programming Syntax Computer Geek T-Shirt
Lightweight, Classic fit, Double-needle sleeve and bottom hem
$16.99

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

More from the Paint Desk

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.