Meine Coverbildchen mach ich ab sofort mit Python (und Chatgpt)
from PIL import Image, ImageDraw, ImageFont
import random
import math
class GridSpheresWithEdges:
def __init__(self, width=900, height=900, rows=3, cols=3, background=(10, 10, 20), base_color=(255, 255, 255)):
self.width = width
self.height = height
self.rows = rows
self.cols = cols
self.background_color = background
self.base_color = base_color
self.image = Image.new("RGB", (self.width, self.height), self.background_color)
self.draw = ImageDraw.Draw(self.image)
self.positions = [] # Store centers of spheres
def _draw_sphere(self, x, y, radius, base_color):
size = radius * 2
sphere = Image.new("RGBA", (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(sphere)
for r in range(radius, 0, -1):
alpha = int(255 * (r / radius) ** 2)
brightness = int(base_color[0] * (r / radius) ** 1.8)
color = (brightness, brightness, brightness, alpha)
draw.ellipse((radius - r, radius - r, radius + r, radius + r), fill=color)
self.image.paste(sphere, (x - radius, y - radius), sphere)
def _draw_arrow(self, start, end, arrow_color=(255, 0, 0), arrow_size=15, width=3):
# Draw line
self.draw.line([start, end], fill=arrow_color, width=width)
# Calculate arrowhead
angle = math.atan2(end[1] - start[1], end[0] - start[0])
arrow_angle = math.pi / 6 # 30 degrees
# Points for arrowhead
left = (end[0] - arrow_size * math.cos(angle - arrow_angle),
end[1] - arrow_size * math.sin(angle - arrow_angle))
right = (end[0] - arrow_size * math.cos(angle + arrow_angle),
end[1] - arrow_size * math.sin(angle + arrow_angle))
self.draw.polygon([end, left, right], fill=arrow_color)
def draw_grid_spheres(self):
cell_width = self.width // self.cols
cell_height = self.height // self.rows
self.positions.clear()
for row in range(self.rows):
for col in range(self.cols):
cx = col * cell_width + cell_width // 2
cy = row * cell_height + cell_height // 2
max_radius = min(cell_width, cell_height) // 2 - 10
radius = random.randint(max_radius // 2, max_radius)
self._draw_sphere(cx, cy, radius, self.base_color)
self.positions.append((cx, cy))
def draw_arrows_between(self, edges):
# edges = list of (from_index, to_index)
for from_idx, to_idx in edges:
start = self.positions[from_idx]
end = self.positions[to_idx]
# Adjust start and end points to be on the edge of the spheres:
# Rough approximation: shift start/end closer by some pixels
dx = end[0] - start[0]
dy = end[1] - start[1]
dist = math.hypot(dx, dy)
if dist == 0:
continue
offset = 30 # Adjust depending on avg radius
start_adj = (start[0] + dx * offset / dist, start[1] + dy * offset / dist)
end_adj = (end[0] - dx * offset / dist, end[1] - dy * offset / dist)
self._draw_arrow(start_adj, end_adj)
def show(self):
self.image.show()
def save(self, filename="grid_spheres_with_arrows.png"):
self.image.save(filename)
# ------------------------
# run
# ------------------------
if __name__ == "__main__":
art = GridSpheresWithEdges()
art.draw_grid_spheres()
# Example edges (from node index to node index)
example_edges = [
(0, 1),
(1, 2),
(3, 0),
(4, 8),
(7, 6),
(5, 4),
(2, 5),
]
art.draw_arrows_between(example_edges)
art.show()
art.save()