Contents
Visualizing Pascal’s Law with Python and Pygame
This project demonstrates Pascal’s Law, a fundamental principle of fluid mechanics, using an interactive Pygame simulation. By dragging pistons and adjusting areas, users can visually and numerically understand how pressure and force behave in a confined fluid.
What Is Pascal’s Law?
Pascal’s Law states:
Pressure applied to a confined fluid is transmitted equally in all directions throughout the fluid.
Mathematically:
P = F / A
Where:
- P = Pressure (Pascals, Pa)
- F = Force (Newtons, N)
- A = Area (square meters, m²)
This principle is the reason hydraulic presses, car brakes, lifts, and excavators can multiply force.
What This Simulation Shows
This program visually simulates a hydraulic system with:
- A small input piston (left)
- A large output piston (right)
- A U-shaped fluid pipe connecting them
Key Features
- Real-time fluid visualization
- Mouse-controlled piston movement
- Adjustable output piston area
- Automatic force multiplication
- Live display of SI units (N, m², Pa)
Technologies Used
- Python 3
- Pygame (graphics + interaction)
- Physics equations (real SI units)
Physics Model Used
Pressure Calculation
Pressure is calculated using fluid depth:
P = ρ g h
Where:
- ρ = fluid density (1000 kg/m³ for water)
- g = gravity (9.81 m/s²)
- h = depth of piston (meters)
Force Transmission
Because pressure is equal everywhere:
F_in / A_small = F_out / A_big
So:
F_out = F_in × (A_big / A_small)
This is why small force on a small piston creates large force on a large piston.
Understanding the Code Structure
1. Window Setup (Portrait Mode)
W, H = 500, 650
S = pygame.display.set_mode((W, H))
A tall window helps visualize vertical piston motion.
2. SI Units Configuration
A_small = 0.01 # m²
A_big = 0.08 # m²
fluid_density = 1000
g = 9.81
All calculations are done using real physics units.
3. Area-to-Width Scaling
big_w = int(base_width * (A_big / A_small) ** 0.5)
Why square root?
Because:
Area ∝ width²
So width must scale with √area to remain visually correct.
4. Constant Fluid Volume Constraint
To simulate incompressible fluid:
initial_fluid_area = calculate_fluid_area(...)
When one piston moves down, the other must rise to conserve volume.
5. Mouse Interaction
- Drag left piston → increases pressure
- Drag right handle → changes piston area
This lets users experiment freely.
Complete code
"""This demonstrates Pascal's Law:
that pressure applied to a confined fluid is transmitted
equally throughout the fluid.
Key Features:
Real-time piston movement and corresponding pressure/force change.
Adjustable output piston area via mouse drag tovisualize force multiplication.
Realistic SI units (Force in N, Area in meter-square., Pressure in Pa).
Dynamic info panel displaying Pascal's law and live values.
visit www.pyshine.com for more details
"""
import pygame, sys
from pygame.draw import rect, lines
from pygame import Rect
pygame.init()
#Portrait window setup
W, H = 500, 650
S = pygame.display.set_mode((W, H))
pygame.display.set_caption("Hydraulic Pressure")
font = pygame.font.SysFont("Arial", 16, bold=True)
BLUE = (0, 120, 255)
GRAY = (180, 180, 180)
DARK = (15, 15, 25)
WHITE = (255, 255, 255)
OUTLINE = (100, 100, 100)
HANDLE_COLOR = (255, 200, 50)
ORANGE = (255, 165, 0) # New color for dragging
#SI Units Setup
# Areas in m^2,
# Pressure in Pa (Pascals),
# Force in N (Newtons)
A_small = 0.01 # 0.01 m^2 = 100 cm^2(small piston)
A_big = 0.08 # 0.08 m^2 = 800 cm^2 (big piston)
fluid_density = 1000 # kg/m³ (water density)
g = 9.81 # m/s² (gravity)
#Geometry
left_x, right_x = 150, 350
pipe_top, pipe_bottom = 440, 450
shaft_len = 60
piston_height = 25
# Calculate widths based on areas to
# maintain visual equality
base_width = 40 # base width for A_small
piston_width = base_width
# cylinder is 10px wider than piston
cylinder_w = base_width + 10
# Calculate big piston width to be
# visually proportional to area
big_w = int(base_width * (A_big / A_small) ** 0.5)
big_h = 50
piston_y = 300
dragging = False
area_drag = False
offset_y = 0
y_min, y_max = 300, 410
# Calculate initial total blue fluid area
# (all three regions)
def calculate_fluid_area(left_y, right_y, big_width):
"""Calculate total blue fluid area including
all three regions"""
# 1. Left cylinder blue area
# (from piston to pipe bottom)
left_area = 40 * (pipe_bottom - left_y)
# 2. Pipe region blue area
# (horizontal U-shaped part)
pipe_area = 40 * (pipe_bottom - pipe_top)
# 3. Right cylinder blue area
# (from piston to pipe bottom)
right_area = big_width * \
(pipe_bottom - (right_y + big_h))
return left_area + pipe_area + right_area
def input_pressure(y):
"""Pressure applied by left piston in Pascals"""
# Convert pixels to meters (100px = 1m)
depth = max(0, (y - y_min) / 100)
return depth * fluid_density * g # Pressure
def calculate_right_piston_position(left_y, big_width):
"""Calculate right piston position to maintain
constant total fluid area"""
# Current left and pipe areas
# (these change with left piston movement)
current_left_area = 40 * (pipe_bottom - left_y)
current_pipe_area = 40 * (pipe_bottom - pipe_top)
# Calculate required right area to maintain
# constant total
required_right_area = initial_fluid_area - \
current_left_area - \
current_pipe_area
# Calculate right piston position from required
# right area
if big_width > 0:
right_fluid_height = required_right_area / \
big_width
right_y = pipe_bottom - right_fluid_height -\
big_h
else:
right_y = initial_right_y
# Ensure the piston stays within bounds
return max(220, min(400, right_y))
# Initial fluid area calculation
initial_right_y = 400
initial_fluid_area = calculate_fluid_area(
piston_y,initial_right_y, big_w)
# Main Loop
# visit www.pyshine.com for more details
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit(); sys.exit()
if e.type == pygame.MOUSEBUTTONDOWN:
# Left piston drag
if (left_x - piston_width//2 < \
e.pos[0] < left_x + piston_width//2
and piston_y - piston_height//2 < \
e.pos[1] < piston_y + piston_height):
dragging, offset_y = True, \
e.pos[1] - piston_y
# Right piston area handle drag
handle_rect = Rect(right_x +
big_w//2 - 5, 350, 10, 50)
if handle_rect.collidepoint(e.pos):
area_drag = True
if e.type == pygame.MOUSEBUTTONUP:
dragging = area_drag = False
if e.type == pygame.MOUSEMOTION:
if dragging:
piston_y = max(y_min,
min(y_max, e.pos[1]-offset_y))
if area_drag:
# Change big piston area and
# update width accordingly
new_big_w = max(40,
min(200, e.pos[0]-right_x+big_w//2))
A_big = A_small * \
(new_big_w / base_width) ** 2
big_w = new_big_w
#Physics
P_in = input_pressure(piston_y) # Pressure Pascals
P_out = P_in # Same pressure (Pascal's principle)
F_in = P_in * A_small # Force in Newtons
F_out = P_out * A_big # Force in Newtons
# Calculate mechanical advantage safely
mechanical_advantage = F_out / F_in if \
F_in != 0 else 0
# Calculate right piston position to maintain
# constant total fluid area
right_y = calculate_right_piston_position(
piston_y, big_w)
# Calculate current total fluid area for display
current_fluid_area = calculate_fluid_area(
piston_y, right_y, big_w)
#Drawing
S.fill(DARK)
# U-shaped pipe - ALL THREE BLUE REGIONS:
# 1. Horizontal pipe region (constant)
rect(S, BLUE, (left_x - 20,
pipe_top,
right_x - left_x + 40,
pipe_bottom - pipe_top))
# 2. Left cylinder blue region (changes with piston)
rect(S, BLUE, (left_x - 20,
piston_y,
40,
pipe_bottom - piston_y))
# 3. Right cylinder blue region (changes with piston)
rect(S, BLUE, (right_x - big_w//2,
right_y + big_h,
big_w,
pipe_bottom - (right_y + big_h)))
# Left cylinder outline
cyl_rect = Rect(left_x - cylinder_w//2,
y_min - 10,
cylinder_w,
y_max - y_min + 50)
rect(S, OUTLINE, cyl_rect, 3)
# Left piston shaft + T-head - CHANGE COLOR
if dragging:
# Use ORANGE when dragging
rect(S, ORANGE,
(left_x - 5,
piston_y - shaft_len,
10,
shaft_len))
head = Rect(left_x - piston_width//2,
piston_y,
piston_width,
piston_height)
top_bar = Rect(left_x - piston_width,
piston_y - 10,
piston_width*2,
10)
rect(S, ORANGE, head)
rect(S, ORANGE, top_bar)
else:
# Use GRAY when not dragging
rect(S, GRAY,
(left_x - 5,
piston_y - shaft_len,
10,
shaft_len))
head = Rect(left_x - piston_width//2,
piston_y,
piston_width,
piston_height)
top_bar = Rect(left_x - piston_width,
piston_y - 10,
piston_width*2,
10)
rect(S, GRAY, head)
rect(S, GRAY, top_bar)
# Right piston
right_rect = Rect(right_x - big_w//2,
right_y,
big_w,
big_h)
rect(S, GRAY, right_rect)
rect(S, OUTLINE, right_rect, 2)
# Handle to drag width/area -
# CHANGE COLOR WHEN DRAGGING
handle_rect = Rect(right_x + big_w//2 - 5,
350, 10, 50)
if area_drag:
rect(S, ORANGE, handle_rect) # Orange dragging
else:
rect(S, HANDLE_COLOR, handle_rect) # Normal color
# Pipe outline
lines(S, WHITE, False, [
(left_x - 20, pipe_top),
(left_x - 20, pipe_bottom),
(right_x + big_w//2, pipe_bottom),
(right_x + big_w//2, pipe_top)
], 2)
# Pascal's Law formula and explanation added to the info panel
info_lines = [
"Pascal's Law:",
"Pressure applied to confined fluid is transmitted equally",
"Formula: P = F / A (Pressure = Force divided by Area)",
"",
f"Input Force: {F_in:.1f} N | Output Force: {F_out:.1f} N",
f"Input Area: {A_small:.4f} m² | Output Area: {A_big:.4f} m²",
"From Pascal's law: F_in / A_small = F_out/A_big",
f"Input Pressure: {F_in:.1f} N / {A_small:.4f} m² = {P_in:.1f} Pa",
f"Output Pressure: {F_out:.1f} N / {A_big:.4f} m² = {P_out:.1f} Pa"
]
for i, line in enumerate(info_lines):
S.blit(font.render(line, True, WHITE),
(30, 20 + i*22))
pygame.display.flip()
Live Information Panel
The top panel displays:
- Pascal’s Law explanation
- Input & output forces
- Input & output areas
- Pressure equality proof
Example:
Input Pressure: 981 Pa
Output Pressure: 981 Pa
Educational Use Cases
This simulation is excellent for:
- Physics classrooms
- STEM demonstrations
- Engineering intuition
- Interactive learning projects
- Educational games
Real-World Applications of Pascal’s Law
- Hydraulic car jacks
- Excavators
- Aircraft brakes
- Industrial presses
- Power steering systems
Common Questions (FAQ)
Why doesn’t force stay the same?
Because area changes. Pressure stays constant, not force.
Why is the output piston larger?
To demonstrate force multiplication.
Why is gravity included?
It converts piston depth into real pressure values.
Is this physically accurate?
Yes for ideal fluids (incompressible, no losses).
Possible Extensions
- Add pressure gauges
- Animate fluid particles
- Add oil vs water density
- Add real hydraulic ratios
- Export data graphs
Conclusion
This Pygame project transforms Pascal’s Law from a formula into a hands-on visual experience. By interacting with pistons and areas, users gain an intuitive understanding of pressure, force, and mechanical advantage.
If you can see physics, you can understand it.
Happy learning!