[b]Introduction[/b][br][br]Visualization of text based mathematics problems, and the ability to solve problems presented that way, are two well known obstacles in learning mathematics for students anywhere. Not seeing what the text represents hinders the student to, sometimes, even begin analyzing and solving what is at hand.[br][br]With GeoGebra we can create visualization tools for better understanding and modeling abstract problems, but this can be a tedious task, both for students and pupils.[br][br]Using AI and PyGgb we can quickly create visualization of problems, both directly on the platform, but also (sometimes) in native GeoGebra. [br][br]Using Python in GeoGebra to visualize math problems requires a bit of Python knowledge. Sure, you can go in blind, but if the code doesn’t work immediately, it’s easier to troubleshoot if you know a bit of Python.[br][br]I will use examples from tests in upper secondary schools, from Nordic and Baltic different countries. I have appended all GeoGebra Python classes at the end, with examples, at the end of this text.[br][br]Important notes:[br]Remember to back up any Python code from geogebra.org/python, since it will disappear when the cache is emptied.[br][br][b]Why?[/b][br]Visualizing math is an essential and [url=https://scholar.google.se/scholar?q=students+visualization+problems+math&hl=sv&as_sdt=0&as_vis=1&oi=scholart]well researched[/url] part of solving mathematical problems, when only given a text problem to solve. For students who have a hard time visualizing, either students with aphantasia ([url=https://pubmed.ncbi.nlm.nih.gov/34872033/]which 1 in 20 are estimated to have[/url]) or just an untrained visualization skill, using tools to visualize the problems for them can be helpful in solving the problems.[br][br][b]How?[/b][br]For PyGgb: I have fed a custom chatbot in Google Gemini with [url=https://docs.google.com/document/u/0/d/1vGmpKnfj1HVLfAf9PzbjBIbkhy_lpXIuPztB4DOiC2c/edit]this prompt[/url]. The chatbot can be found [url=https://gemini.google.com/gem/1fk7FQx5N3wcO3rTIMMOqtpPIn7nr5GUm?usp=sharing]here[/url], but you can give the prompt to an AI of your choice. Then feed the AI with a screenshot or paste of your math problem. We then use geogebra.org/python to paste the code the AI comes up with.[br]Using Claude, I give it instructions to visualize the problem interactively with JavaScript, directly in the browser. This is more beautiful than GeoGebra, which to some might be an advantage.[br]Examples[br][br][b]Example 1:[/b] Problem 12 from the national test for course Matematik 2b, spring 2015 ([url=https://arkiv.edusci.umu.se/np/np-2-4-prov/Ma2b-vt15.pdf]link[/url]). Past tests from the Swedish national tests in mathematics, both for primary and secondary school forms, can be found [url=https://www.su.se/primgruppen/nationella-prov]here[/url] and [url=https://www.umu.se/institutionen-for-tillampad-utbildningsvetenskap/np/np-2-4/tidigare-givna-prov/]here[/url]. [br][br]
Asking for a GeoGebra code, I got this from Gemini:[br][br][code]import math[br][br]# --- Step 1: Slider for x ---[br]# x is the length of one side. The interval for x must be (0, 8).[br]# We choose 0.01 to 7.99 to handle GeoGebra objects.[br]x_slider = Slider(0.01, 7.99, increment=0.01)[br]x_slider.value = 4.0 # Starting value at the maximum[br]x_slider.caption = "Side x (cm)"[br][br]# Create a Number object for the other side length (8-x)[br]side_y_num = Number(8.0 - x_slider.value)[br][br]# Create a Number object for the total area A(x) = 2 * x * (8 - x)[br]Area_num = Number(2.0 * x_slider.value * side_y_num.value)[br][br]# --- Step 2: Draw the Rectangles ---[br][br]# Dimensions: Width = 8 - x, Height = x (based on the image)[br]rect_width = side_y_num[br]rect_height = x_slider[br][br]# Base points for the first rectangle[br]A = Point(-rect_width.value - 0.5, 0, is_visible=False)[br]B = Point(-0.5, 0, is_visible=False)[br]C = Point(-0.5, rect_height.value, is_visible=False)[br]D = Point(-rect_width.value - 0.5, rect_height.value, is_visible=False)[br][br]# Base points for the second rectangle (with a small gap)[br]E = Point(0.5, 0, is_visible=False)[br]F = Point(rect_width.value + 0.5, 0, is_visible=False)[br]G = Point(rect_width.value + 0.5, rect_height.value, is_visible=False)[br]H = Point(0.5, rect_height.value, is_visible=False)[br][br]# Rectangle 1[br]Rectangle1 = Polygon([A, B, C, D], color="#0077ff", opacity=0.3, line_thickness=3)[br][br]# Rectangle 2[br]Rectangle2 = Polygon([E, F, G, H], color="#0077ff", opacity=0.3, line_thickness=3)[br][br]# --- Step 3: Dynamic update of rectangles and area ---[br][br]# Helper point to show the maximum area value on the graph (Step 4)[br]# The maximum occurs when x = -b / (2a) = -16 / (2*(-2)) = 4.[br]# Max area is A(4) = 16*4 - 2*4^2 = 64 - 32 = 32.[br]Max_Area_Pt = Point(4, 32, size=5, color="#ff0000")[br][br]# Point on the graph corresponding to the current value of x[br]Current_Area_Pt = Point(x_slider.value, Area_num.value, size=5, color="#00aa00")[br][br]@x_slider.when_changed[br]def update_visualization():[br] # Update the y-side length[br] side_y_num.value = 8.0 - x_slider.value[br] [br] # Update the total area[br] Area_num.value = 2.0 * x_slider.value * side_y_num.value[br] [br] # Update Rectangle 1 corners[br] A.x = -side_y_num.value - 0.5[br] C.y = x_slider.value[br] D.x = -side_y_num.value - 0.5[br] D.y = x_slider.value[br] [br] # Update Rectangle 2 corners[br] F.x = side_y_num.value + 0.5[br] G.x = side_y_num.value + 0.5[br] G.y = x_slider.value[br] H.y = x_slider.value[br] [br] # Update the point on the graph[br] Current_Area_Pt.x = x_slider.value[br] Current_Area_Pt.y = Area_num.value[br][br] # Print current area (shown in the console)[br] print(f"x = {x_slider.value:.2f} cm")[br] print(f"Side y (8-x) = {side_y_num.value:.2f} cm")[br] print(f"Total Area A(x) = {Area_num.value:.2f} cm²")[br][br]# --- Step 4: Draw the graph of the area function ---[br]# Area function: A(x) = -2x² + 16x[br]Area_Function = Parabola(-2, 16, 0)[br]Area_Function.color = "#888888"[br]Area_Function.line_thickness = 2[br][br]# Update on startup[br]update_visualization()[br][br]print("Drag the 'Side x (cm)' slider to change the rectangles' dimensions.")[br]print("Observe how the total area A(x) changes. The graph A(x) = -2x² + 16x is shown.")[br]print("The red point shows the maximum area A = 32 when x = 4.")[/code][br][br][br]Asking Claude for an interactive page, I got this: https://claude.ai/public/artifacts/bab4905f-d2aa-4f4e-85d5-8cf9cc5c06fa[br][br][br][br][b]Example 2:[/b] Problem 6 from Part 2 of the national test for course 1T, MAT 1021 [url=https://matematikk.net/matteprat/download/file.php?id=5025]spring 2025[/url], upper secondary school, in Norway. Norway’s national exams can be found [url=https://matematikk.net/side/Forside]here[/url].[br][br]
This is from Gemini, to use in PyGgb:[br][br][code]import math[br]import time[br][br]# --- Constants ---[br]V = 450 # Volume in cm³[br][br]# --- Step 1: Create Slider for Radius (r) ---[br]# The slider allows the user to adjust the radius and see the effects interactively.[br]r_slider = Slider(1.0, 10.0, increment=0.1)[br]r_slider.caption = "Radius, r (cm)"[br]r_slider.value = 4.15 # Starting value close to the theoretical minimum[br][br]# --- Step 2: Create dynamic Numbers for Height (h) and Surface Area (O) ---[br]# These Number objects will hold the calculated dynamic values.[br]# IMPORTANT: Number objects DO NOT support the .caption attribute.[br]h_value = Number(0)[br]O_value = Number(0)[br][br]# Helper point to show the current (r, O(r)) value on the graph[br]P_O = Point(r_slider.value, O_value.value, size=6, color="#0000FF") # Blue point[br][br]# --- Step 3: Calculation Function ---[br]# This function calculates the height (h) and total surface area (O) [br]# based on the current radius (r) from the slider.[br]@r_slider.when_changed[br]def calculate_cylinder_properties():[br] r = r_slider.value[br] [br] # Calculate Height (h)[br] # h = V / (pi * r^2)[br] h = V / (math.pi * r**2)[br] h_value.value = h # Update Number object[br] [br] # Calculate Total Surface Area (O) - The function we want to minimize[br] # O(r) = 2*pi*r^2 + 2*pi*r*h = 2*pi*r^2 + 900/r[br] O = 2 * math.pi * r**2 + 900 / r[br] O_value.value = O # Update Number object[br][br] # Update the position of the point on the graph[br] P_O.x = r[br] P_O.y = O[br] [br] # Print the calculated values to the console for easy reading[br] print(f"Radius r: {r:.3f} cm")[br] print(f"Height h: {h:.3f} cm")[br] print(f"Surface Area O: {O:.3f} cm²")[br] time.sleep(0) # Crucial to prevent the program from freezing[br][br]# Run the calculation with the initial slider value[br]calculate_cylinder_properties()[br][br]# --- Step 4: Visualize the Function O(r) ---[br]# We plot the function O(r) = 2*pi*r^2 + 900/r by creating many points.[br]# The graph shows Radius (r) on the x-axis and Surface Area (O) on the y-axis.[br]def plot_surface_area_function():[br] # Define the range for the plot[br] min_r = 1.0[br] max_r = 10.0[br] num_points = 100[br] [br] for i in range(num_points + 1):[br] # Calculate r for the current point[br] r_i = min_r + (max_r - min_r) * (i / num_points)[br] [br] # Calculate O(r_i)[br] O_i = 2 * math.pi * r_i**2 + 900 / r_i[br] [br] # Create a point on the graph[br] # Using size=1 gives the appearance of a continuous curve[br] Point(r_i, O_i, size=1, color="#FF0000") # Red color for the graph[br] time.sleep(0) # Prevent freezing during loop execution[br][br]# Call the function to draw the graph[br]plot_surface_area_function()[br][br]print("\n--- Interactive Values ---")[br]print("Use the 'Radius, r (cm)' slider to explore how Height (h) and Surface Area (O) change.")[br]print("Find the lowest point on the red curve to determine the minimum surface area.")[br]print(f"Current Height h (cm): {h_value.value:.3f}")[br]print(f"Current Surface Area O (cm²): {O_value.value:.3f}")[br][/code][br][br][br]And this is from Claude, an interactive visualization:[br][b][url=https://claude.ai/public/artifacts/fe80f71b-c62a-43a0-ab51-b25722e90075]https://claude.ai/public/artifacts/fe80f71b-c62a-43a0-ab51-b25722e90075[br][br][br][/url][/b][b]Example 3:[/b] Problem 3 from Matematik FP9 - Folkeskolens prøver Prøven med hjælpemidler, from december 2022. Denmark’s national exams can be found [url=https://www.provebanken.dk/proevematerialer/FAP/MAT]here[/url].[br][br]
Here is what Gemini produced for me, to use in PyGgb:[br][br][code][/code][code][/code][code]import math[br]import time[br][br]# --- Settings and Constants ---[br]# The constant slope angle[br]ANGLE_DEGREES = 8.0[br]# Convert to radians for trigonometric functions[br]ANGLE_RADIANS = math.radians(ANGLE_DEGREES)[br]# Visual size for points[br]PT_SIZE = 5[br][br]# --- Task 3.1: Interactive Slope Visualization ---[br][br]# Slider to control the horizontal length 'a' (adjacent side)[br]# The sketch suggests a horizontal length 'a' of ca. 396 m.[br]a_slider = Slider(100, 1500, increment=1)[br]a_slider.value = 396[br]a_slider.caption = "Horizontal Length 'a' (m)"[br][br]# Base Points (A and B define the horizontal length 'a')[br]A = Point(0, 0, size=PT_SIZE, color="#0000FF") # Base, start point (left)[br]B = Point(a_slider.value, 0, size=PT_SIZE, color="#008800") # Base, end point (right)[br][br]# The initial position of the apex C is calculated using h = a * tan(8°)[br]initial_h = a_slider.value * math.tan(ANGLE_RADIANS)[br]C = Point(a_slider.value, initial_h, size=PT_SIZE, color="#FF0000") # Apex/Top[br][br]# Segments forming the right triangle[br]seg_a = Segment(A, B, color="#008800", line_thickness=2) # Horizontal length 'a'[br]seg_h = Segment(B, C, color="#FF0000", line_thickness=2) # Height 'h'[br]seg_slope = Segment(A, C, color="#0000FF", line_thickness=5) # The actual slope[br][br]# Polygon to fill the triangular cross-section[br]slope_poly = Polygon([A, B, C], color="#AAAAFF", opacity=0.3, line_thickness=0)[br][br]# Dynamic Number objects for displaying calculated values (Numbers don't have captions)[br]h_number = Number(C.y) # Stores Height 'h'[br]fall_proc_number = Number(0) # Stores Average Grade (h/a) in percent[br][br]@a_slider.when_changed[br]def update_ski_slope():[br] # 1. Update point B's x-coordinate based on the slider (a)[br] B.x = a_slider.value[br] [br] # 2. Calculate and update the height h: h = a * tan(angle)[br] h_value = a_slider.value * math.tan(ANGLE_RADIANS)[br] h_number.value = h_value[br] [br] # 3. Update point C's coordinates[br] C.x = a_slider.value[br] C.y = h_value[br] [br] # 4. Calculate Average Grade (Genomsnittligt Fall): (h/a) * 100[br] fall_percent = (h_value / a_slider.value) * 100[br] fall_proc_number.value = fall_percent[br] [br] # Print current values for context[br] print(f"--- Slope 1 (Interactive) Updated ---")[br] print(f"Horizontal Length (a): {a_slider.value:.2f} m")[br] print(f"Calculated Height (h): {h_value:.2f} m")[br] print(f"Average Grade (h/a): {fall_percent:.2f} %")[br][br]# Initial call to set up the visualization correctly[br]update_ski_slope()[br][br]# --- Task 3.2: Analysis of Slope 2 (Length 1200 m, 8°) ---[br][br]# Slope 1 Reference: Use a1 = 396m from the sketch to find h1[br]a1 = 396[br]h1 = a1 * math.tan(ANGLE_RADIANS)[br][br]# Slope 2: The given length L2 = 1200m is the hypotenuse (pisten's length)[br]L2 = 1200 [br]# Calculate the height h2: h2 = L2 * sin(angle)[br]h2 = L2 * math.sin(ANGLE_RADIANS)[br][br]# Calculate the ratio h2 / h1 (Should be close to 3)[br]ratio_h = h2 / h1[br][br]# Create a static visualization of Slope 2 (scaled down for the view)[br]SCALE_X_OFFSET = 500 # Shift the second slope to the right for clear view[br]# Calculate horizontal length a2: a2 = L2 * cos(angle)[br]a2 = L2 * math.cos(ANGLE_RADIANS) [br][br]A2 = Point(SCALE_X_OFFSET, 0, size=PT_SIZE, color="#00AA00")[br]B2 = Point(SCALE_X_OFFSET + a2, 0, size=PT_SIZE, color="#00AA00")[br]C2 = Point(B2.x_number, h2, size=PT_SIZE, color="#FF0000") [br][br]seg_a2 = Segment(A2, B2, color="#00AA00", line_thickness=2)[br]seg_h2 = Segment(B2, C2, color="#FF0000", line_thickness=2)[br]seg_slope2 = Segment(A2, C2, color="#0000AA", line_thickness=4)[br]Polygon([A2, B2, C2], color="#FFAAAA", opacity=0.3, line_thickness=0)[br][br][br]# --- Outputting Solutions to Console ---[br][br]print(f"\n--- Task 3.2 Solution ---")[br]print(f"Slope 1 (Horizontal a1=396m): Height h1 = {h1:.2f} m")[br]print(f"Slope 2 (Hypotenuse L2=1200m): Height h2 = {h2:.2f} m")[br]print(f"Height ratio h2/h1 = {ratio_h:.2f}")[br]print(f"Since the ratio is approximately 3.01, Sofia's observation that h2 is 3 times h1 is correct (based on proportional triangles).")[br][br]# --- Task 3.3: Average Grade Calculation ---[br][br]# The formula is: Average Grade = h/a * 100%. In a right triangle, h/a = tan(angle).[br]tan_8_percent = math.tan(ANGLE_RADIANS) * 100[br][br]print(f"\n--- Task 3.3 Solution ---")[br]print(f"Average Grade = h/a = tan(8°) * 100")[br]print(f"Calculated Average Grade: {tan_8_percent:.2f} %")[br]print(f"The mother claims the slope corresponds to 15% to 25%. Since {tan_8_percent:.2f}% is within the range 15% to 25%, Sofia's mother is **correct**.")[br][/code][br][br][br]And this visualization is what Claude produced:[br][url=https://claude.ai/chat/cddbf1bc-a965-42fd-9a64-31607283db3e][b]https://claude.ai/public/artifacts/4932dc52-992e-4be5-ad40-264cc77bad90[/b][/url]
[url=https://docs.google.com/document/d/10z5d74d49q-70Cur_73691fsTcIiwcBzj3schr_HoKY/edit?usp=sharing]All PyGgb classes with examples[/url]
[url=https://docs.google.com/document/d/1vGmpKnfj1HVLfAf9PzbjBIbkhy_lpXIuPztB4DOiC2c/edit?usp=sharing]My Gemini prompt for creating code[/url]