Practice drawing concentric circles, alternating color fills, random RGB color generation, and nested rectangles with ReportLab shapes directly inside Google Colab.
View on GitHubCircles can be drawn by specifying center X, Y coordinates and giving a radius. We can also specify the color used to fill the circle using fillColor. Here two concentric circles are drawn with alternating background colors.
from pathlib import Path
from reportlab.graphics.shapes import Drawing, Circle
from reportlab.graphics import renderPDF
output_dir = Path('output')
output_dir.mkdir(exist_ok=True)
my_path = output_dir / 'two_color_circles.pdf'
d = Drawing(600, 600)
for rd in range(0, 300, 10):
if rd % 20 == 0:
d.add(Circle(300, 300, 300 - rd, fillColor=[1, 0, 0]))
else:
d.add(Circle(300, 300, 300 - rd, fillColor=[0, 1, 0]))
renderPDF.drawToFile(d, str(my_path), '')
print(f"PDF created: {my_path}")
We can generate floating-point numbers between 0 and less than 1 (exclusive) by using random.random().
random.uniform() returns floats between start and stop (inclusive).
More about Random numbers
import random
from pathlib import Path
from reportlab.graphics.shapes import Drawing, Circle
from reportlab.graphics import renderPDF
output_dir = Path('output')
output_dir.mkdir(exist_ok=True)
my_path = output_dir / 'random_color_circles.pdf'
d = Drawing(1200, 1200)
for rd in range(0, 600, 20):
r = random.random()
g = random.random()
b = random.random()
d.add(Circle(600, 600, 600 - rd, fillColor=[r, g, b]))
renderPDF.drawToFile(d, str(my_path), '')
print(f"PDF created: {my_path}")

Here we have used random.uniform(0,1) to generate random floats between 0 and 1 (inclusive of 0 and 1). Check this link for the difference between random.uniform() and random.random().
Here width and height are assigned to variables so they can easily be adjusted at a single point.
w, h = 620, 620
Full code for nested random color rectangles:
import random
from pathlib import Path
from reportlab.graphics.shapes import Drawing, Rect
from reportlab.graphics import renderPDF
output_dir = Path('output')
output_dir.mkdir(exist_ok=True)
my_path = output_dir / 'random_color_rectangles.pdf'
w, h = 620, 620
d = Drawing(w, h)
for rd in range(0, int(w / 2), 20):
r = random.uniform(0, 1)
g = random.uniform(0, 1)
b = random.uniform(0, 1)
d.add(Rect(rd, rd, w - (rd * 2), h - (rd * 2), fillColor=[r, g, b]))
renderPDF.drawToFile(d, str(my_path), '')
print(f"PDF created: {my_path}")
Vector shapes are fundamental elements in modern PDF document generation and automated publishing workflows:
Drawing canvas. When drawing concentric shapes, always add larger outer shapes first, followed by smaller inner shapes.fillColor accepts lists or tuples of RGB values between 0.0 and 1.0 (e.g., [1.0, 0.0, 0.0] for pure red) or ReportLab colors.HexColor / colors.Color objects. Passing values above `1` (like `255`) without converting will throw color rendering errors.pathlib.Path to ensure export directory structures exist before invoking renderPDF.drawToFile().Q: What is the difference between `random.random()` and `random.uniform()` when setting RGB colors?
A: `random.random()` returns floats in the half-open interval $[0.0, 1.0)$, while `random.uniform(a, b)` returns floats in $[a, b]$. In practice for RGB floats in $[0, 1]$, both methods work effectively, but `random.uniform(0, 1)` allows explicit bounds.
Q: How can I remove the black border stroke around drawn shapes?
A: Set strokeColor=None or strokeWidth=0 when creating the Circle or Rect object.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.