widget not working !

154 views
Skip to first unread message

Gilles Dubois

unread,
Jun 24, 2025, 5:11:54 PMJun 24
to VPython-users
Hello Everybody !
I'm using python 3.12 with vpython 7.6.5
Although createPoints and clearPoints work perfectly when called from the 'root' level. I cannot use them in a menu-manager. And BTW it seems that whatever I do in this function is ignored. No error message !
Here is my code. If you see a possible cause, please let me know.
Thank you !

from vpython import *
import random

B = box(opacity=0.5, size=vector(4, 4, 4), color=color.yellow)
SP = sphere(opacity=0.5, radius=2, color=color.red)


def alea_point():
    alea_pos = (random.uniform(-2, +2), random.uniform(-2, +2), random.uniform(-2, +2))
    if (alea_pos[0] * alea_pos[0] + alea_pos[1] * alea_pos[1] + alea_pos[2] * alea_pos[2]) < 1:
        couleur = color.black
    else:
        couleur = color.blue
    return points(pos=[vector(alea_pos[0], alea_pos[1], alea_pos[2])], radius=4, color=couleur, opacity=1)


def createPoints(n):
    scene.L = [alea_point() for i in range(n)]


def clearPoints():
    for p in scene.L:
        p.clear()
        del p
    scene.L = []


scene.L = []

createPoints(20)

wtext(text='Choisir le tir')
scene.append_to_caption('\n')


def selMenu(m):
    val = m.selected
    if val == "10 points":
        clearPoints()
        createPoints(10)
    if val == "100 points":
        clearPoints()
        createPoints(100)
    if val == "1000 points":
        clearPoints()
        createPoints(1000)
    if val == "10000 points":
        clearPoints()
        createPoints(10000)


M = menu(choices=['10 points', '100 points', '1000 points', '10000 points'], index=0, bind=selMenu)

Bruce Sherwood

unread,
Jun 24, 2025, 10:25:59 PMJun 24
to VPython-users
If I change the contents of the subroutine createPoints(n) to

    for i in range(n):
        scene.L.append(alea_point())

the program seems to run correctly.

Bruce

Gilles Dubois

unread,
Jun 25, 2025, 12:17:41 AMJun 25
to VPython-users
Thank you Bruce for your suggestion. Although I do not see any difference with a comprehension list the result is the same (no result...). A little more about my environment I use IDE Pycharm, (community version) all examples I could find using menus work perfectly on my system. It's really confusing.

Gilles Dubois

unread,
Jun 25, 2025, 1:30:19 AMJun 25
to VPython-users
More information:
It looks like the menu manager is never called. To see this I can change the code in print('hello') indistinctively of choice. Nothing appears on console never, whatever the choice.
But if I copy the code of a similar example given in the manual  on my system, for example
Everything works normally.
So the in my program the binding process fails ! Why ?

Gilles Dubois

unread,
Jun 25, 2025, 4:53:00 AMJun 25
to VPython-users
Things are more and more intriguing ...
I downloaded the code a lot of examples of programs including widgets (all kinds). I copied, pasted and executed in my Pycharm environment. Everything works interactively !
Now if I want to include in my own code any control strictly according the models whatever the kind (button, text area, droplist, and so on) and bind it with a function doing very simple things (printing on the console, modifying radius of the ball, size of the cube, etc..) nothing works. It looks like user generated events are completely ignored or binding process fails, without any error message at any time (compilation, execution)  I don't understand anything except that this has nothing to do with functions createPoints and clearPoints. 
But I can use input from the console, enter any chain, convert into int and call createPoints, it works ! But I need two screens, and the user must know that console is waiting for something to be entered. You cannot call this a friendly interface.
scene.L=[]
while True:
    n=int(input("Donner un entier\n"))
    clearPoints()
    createPoints(n)
This code works exactly as I want

John

unread,
Jun 25, 2025, 7:13:15 AMJun 25
to VPython-users
How are you running your program. Are you running from the terminal with a command like

     python myprogram.py

If so then you will need to add a rate statement to your program according to these instructions at this link.


When running from a terminal, if the program does not end with a loop
containing a rate() statement, you need to add "while True: rate(30)"
to the end of the program. This is not necessary when launching from
environments such as Jupyter notebook, IDLE, or Spyder.

I noticed that the code you posted didn't have a rate() statement in it but the example programs that worked all had "while True: rate(30)" or similar statement.

Gilles Dubois

unread,
Jun 25, 2025, 7:41:10 AMJun 25
to VPython-users
Thank you so much, John. IT WORKS !!!
Unfortunately I was not as perspicacious as you and lost a lot of time. The lesson is that I should read documentation more attentively, and that this forum is really helpful. Have a good day !


John

unread,
Jun 25, 2025, 11:05:47 AMJun 25
to VPython-users
Your welcome, and as a reward I learned a new word,   perspicacious  " having a ready insight into and understanding of things"
or " perspicacious implies unusual power to see through and understand what is puzzling or hidden"

Gilles Dubois

unread,
Jun 25, 2025, 3:50:01 PMJun 25
to VPython-users
Hi John :!
The story of 'perspicacious' is quite simple. I took it from the French 'perspicace' which old people like me continue to use quite often with the risk to be taken as aliens by new generation(s). The meaning is (fortunately) exactly the one you quoted. Anglicization of French words obeys simple rules which ,with time and practice, one can remember. So I could guess that 'perspicacious' was the thing I had in mind. Although I received confirmation from my spell-checker I took the risk not to check as well  the meaning in contemporary US-English. But I was lucky  it was not a "faux ami" resulting of the fluctuation of meaning on both sides  of the Channel. So the use was completely appropriate in this case.
Let's come back to our program. I join the final step (what I had in mind from the beginning). It's for educational purpose you can use for students to check the validity of the formula giving the volume of a sphere, or for computer scientists to check if the random distribution over the cube given by Python is really uniform, yours to choose.
It has some philosophical implications too, showing than a non deterministic method can be as efficient or more than  a rational deterministic  one. Yes sometimes it's better to rely on chance than on complicated computations (it's the lesson, isn't it ?) .
My machine supports 100000 random shots but I prefer to be modest and allow people with basic equipment to watch.
So here's the final step :

from vpython import *
import random

scene.title = "Méthode dite de Monte-Carlo\n"


B = box(opacity=0.5, size=vector(4, 4, 4), color=color.yellow)
SP = sphere(opacity=0.5, radius=2, color=color.red)

success = 0
total = 0


def alea_point():
    global success

    alea_pos = (random.uniform(-2, +2), random.uniform(-2, +2), random.uniform(-2, +2))
    if (alea_pos[0] * alea_pos[0] + alea_pos[1] * alea_pos[1] + alea_pos[2] * alea_pos[2]) < 1:
        couleur = color.black
        success += 1

    else:
        couleur = color.blue
    return points(pos=[vector(alea_pos[0], alea_pos[1], alea_pos[2])], radius=4, color=couleur, opacity=1)


def createPoints(n):
    global success
    global total
    total = n
    success = 0

    scene.L = [alea_point() for i in range(n)]


def clearPoints():
    for p in scene.L:
        p.clear()
        del p
    scene.L = []

scene.caption="""Pour faire tourner la caméra : drag avec bouton droit ou bien Ctrl-drag.
Pour zoomer utiliser la roulette.
Pour panorama droite/gauche et haut/bas : Maj-drag.

"""

wt = wtext(text='Volume calculé de la sphère : 0,5236')

scene.append_to_caption('\n')


def selMenu(m):
    global success, total
    val = m.selected
    if val == "100 points":
        clearPoints()
        createPoints(100)
        R.text = str(8 * success / total)

    if val == "1000 points":
        clearPoints()
        createPoints(1000)
        R.text = str(8 * success / total)

    if val == "10000 points":
        clearPoints()
        createPoints(10000)
        R.text = str(8 * success / total)
    if val == "20000 points":
        clearPoints()
        createPoints(20000)
        R.text = str(8 * success / total)


menu(bind=selMenu, choices=['Choisir le tir','100 points', '1000 points', '10000 points', '20000 points'], index=0)
scene.append_to_caption('\n')
R = wtext(text='approximation')


scene.L = []
while True:
    rate(30)

John

unread,
Jun 25, 2025, 9:30:38 PMJun 25
to VPython-users
Here is a link to your program running in Web VPython


I made a few changes to get it to run in Web VPython. I added the line 
from random import uniform
and changed the line
    alea_pos = (random.uniform(-2, +2), random.uniform(-2, +2), random.uniform(-2, +2))
to 
    alea_pos = (uniform(-2, +2), uniform(-2, +2), uniform(-2, +2))

I also implemented Bruce's suggestion to use
    
    for i in range(n):
        scene.L.append(alea_point())
instead of 
         scene.L = [alea_point() for i in range(n)]
in the createPoints(n) function since the latter was giving an error message in Web VPython

In addition, I commented out the last 2 lines since they are not needed in Web VPython. 

John

unread,
Jun 25, 2025, 10:06:32 PMJun 25
to VPython-users
Here is another Web VPython version that goes up to 1 Million points and gives a better approximation.

https://glowscript.org/#/user/johncoady/folder/Demo/program/TestPoints2

It might take a minute to calculate the value for 1 Million points but it gives a better approximation to the true value.

Gilles Dubois

unread,
Jun 26, 2025, 1:23:34 AMJun 26
to VPython-users
Thank you very much to both of you.

John

unread,
Jun 26, 2025, 12:43:37 PMJun 26
to VPython-users

I suppose you can try creating a variant of this that uses Archimedes discovery that the volume of a sphere is 2/3 the volume of a cylinder.

https://youtu.be/2IZh-KIAQLE?si=p4hg-RhLVDCImqE7

And also generating a uniform distribution of points over a disk.

Gilles Dubois

unread,
Jun 26, 2025, 4:58:24 PMJun 26
to VPython-users
Let's begin to pay a tribute to the ancient Greeks with conic sections. Program at the end of this message.
About the disk I did something in Javascript quite equivalent to the sphere (uniform on a square to calculate the area of the circle by Monte-Carlo it's here 
Yes, I know the trick of Wolfram for a uniform distribution over a disk. Possible to make something with VPython, we'll think about this.
Right now I'm coaching one of my grandsons in maths. The boy has a pretty good knowledge of Python. My next attempt with VPython will be the computation of the volume of the sphere by slicing it.
About the sphere I  already did something with GeoGebra
 Capture d’écran du 2025-06-26 22-50-27.png
but we can do better 
Conic sections :
from vpython import *

scene.width = 500
scene.height = 500

scene.title = """Coniques - Intro
Intersection d'un plan avec un cône
Dans notre exemple l'angle du cône est de 45°
"""
C1 = cone(pos=vec(0, -7, 0), axis=vec(0, 7, 0), color=color.cyan, opacity=0.5, radius=7)
C2 = cone(pos=vec(0, 7, 0), axis=vec(0, -7, 0), color=color.cyan, opacity=0.5, radius=7)
P = box(pos=vec(-2, 0, 0), length=15, height=0.04, width=15, color=color.red, opacity=0.5, axis=vec(0, 1, 0))

scene.caption = """Pour faire tourner la caméra : drag avec bouton droit ou bien Ctrl-drag.

Pour zoomer utiliser la roulette.
Pour panorama droite/gauche et haut/bas : Maj-drag.

Ci-dessous réglez l'inclinaison du plan par rapport à l'axe du cone\n
"""

oldangle = 0
case = 'G'

def setincli():
    global oldangle
    global case
    wt.text = str(sl.value) + '°'
    rotangle = sl.value - oldangle
    oldangle = sl.value
    valrad = (rotangle / 180) * pi
    P.rotate(axis=vec(0, 0, 1), angle=valrad, origin=vec(0, 0, 0))
    if case == 'G':
        if sl.value < 45:
            inter.text = 'Hyperbole'
        elif sl.value == 45:
            inter.text = 'Parabole'
        elif sl.value < 135:
            inter.text = 'Ellipse'
        elif sl.value == 135:
            inter.text = 'Parabole'
        elif sl.value > 135:
            inter.text = 'Hyperbole'
        else:
            pass
    if case == 'P':
        if sl.value < 45:
            inter.text = 'Deux droites'
        elif sl.value == 45:
            inter.text = 'Une droite tangente'
        elif sl.value < 135:
            inter.text = 'Un point'
        elif sl.value == 135:
            inter.text = 'Une droite tangente'
        elif sl.value > 135:
            inter.text = 'Deux droites'
        else:
            pass


sl = slider(min=0, max=180, value=0, length=360, bind=setincli, step=5)

wt = wtext(text=str(sl.value) + '°')

scene.append_to_caption('\n')
inter = wtext(text='Hyperbole')

scene.append_to_caption('\n\ncas')


def setcas(evt):
    global case
    if evt.text == 'Général':
        P.pos = vec(-2, 0, 0)
        case = 'G'
        if sl.value < 45:
            inter.text = 'Hyperbole'
        elif sl.value == 45:
            inter.text = 'Parabole'
        elif sl.value < 135:
            inter.text = 'Ellipse'
        elif sl.value == 135:
            inter.text = 'Parabole'
        elif sl.value > 135:
            inter.text = 'Hyperbole'
        else:
            pass

    elif evt.text == 'Particulier':
        P.pos = vec(0, 0, 0)
        case = 'P'
        if sl.value < 45:
            inter.text = 'Deux droites'
        elif sl.value == 45:
            inter.text = 'Une droite tangente'
        elif sl.value < 135:
            inter.text = 'Un point'
        elif sl.value == 135:
            inter.text = 'Une droite tangente'
        elif sl.value > 135:
            inter.text = 'Deux droites'
        else:
            pass
    else:
        pass


r1 = radio(bind=setcas, checked=True, text='Général', name='cas')
r2 = radio(bind=setcas, text='Particulier', name='cas')

while True:
    rate(30)

John

unread,
Jun 27, 2025, 7:25:56 PMJun 27
to VPython-users
I asked an Artificial Intelligence tool ( Grok at X.com ) to have a look at your program and suggest any improvements to get it to run in Web VPython. This is what it produced.

https://glowscript.org/#/user/johncoady/folder/AI/program/AISphereInBox

I then asked the AI tool to generate a version of the program for a sphere inside a cylinder and verify the volume of the sphere was 2/3 the volume of the cylinder as Archimedes discovered. This is the web vpython program the AI produced.


Then I asked the AI tool to generate a version of the program for a double-napped-cone inside a cylinder and verify the volume was 1/3 the volume of the cylinder. This is the web vpython program the AI produced.

https://glowscript.org/#/user/johncoady/folder/AI/program/Double-Napped-Cone-in-cylinder

Gilles Dubois

unread,
Jun 28, 2025, 1:43:44 AMJun 28
to vpytho...@googlegroups.com

WOW !!!

I'm impressed.

What do you give to GROK for food ? My program as a base for improvements or a rough description in natural language of what you're expecting ?

Till now I have a very poor opinion of the so called AI programs and spend some time quarreling with one of my sons and proving him by simple examples that they are stupid.

This son uses ChatGPT extensively to generate business letters. I'm not enthusiastic about that, although I understand it's a useful tool for him to save time and spare money by replacing a human secretary.

Of course things change when you deal with an expert program (Although they are impressive I don't include such programs in AI) . I consider to be AI any program which can compete with human intelligence by understanding situations explained in natural language. Till now I haven't seen anything of the kind.

--
You received this message because you are subscribed to the Google Groups "VPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vpython-user...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/vpython-users/d85d3276-935b-4221-bec4-6a751f4e8b08n%40googlegroups.com.

John

unread,
Jun 28, 2025, 2:16:44 AMJun 28
to VPython-users
I provided Grok the following prompt along with your code
"The following web vpython program estimates the volume of the sphere that just fits inside a box from a uniform distribution of points in a the box. The number of points inside the box to use to make the estimation is determined from a drop down list menu. The more points that are used the better the estimation of the volume of the sphere appears to be. Can you suggest any improvements to this code."

It initially suggested the following changes and provided the code for the changes. I had to prompt it a few more times to get the desired result. So there was a bit of trial and error to get the code working properly. Here was the initial assessment of your program.

"
The provided Web VPython program uses a Monte Carlo method to estimate the volume of a sphere (radius 2) inscribed in a cube (side length 4) by generating random points and calculating the proportion that fall inside the sphere. The user selects the number of points via a dropdown menu, and the volume is estimated as the fraction of points inside the sphere multiplied by the cube’s volume (8). The program works but has areas for improvement in efficiency, clarity, user interaction, and accuracy. Below, I suggest specific improvements and provide an optimized version of the code.
Suggested Improvements
  1. Efficiency in Point Creation:
    • The createPoints function uses a loop with append, which is less efficient than a list comprehension, especially for large numbers of points (e.g., 1,000,000). The commented-out list comprehension in the original code is a better approach.
    • The points object creates individual point objects, which can be slow for rendering large numbers of points. Using a single points object with a list of positions is more efficient.
  2. Accuracy of Volume Calculation:
    • The sphere’s radius is 2, but the condition in alea_point checks if the distance is < 1, which is incorrect for a sphere of radius 2. This leads to an incorrect volume estimate (the code targets 0.5236, which is the volume of a unit sphere,
      \frac{4}{3}\pi \approx 4.1888
      , divided by 8). The correct condition should use radius 2.
    • The volume calculation (8 * success / total) assumes the cube’s volume is 8, which is correct (4×4×4 = 64, but the formula adjusts for the sphere). However, the displayed value should be updated dynamically and formatted for clarity.
  3. User Interface:
    • The dropdown menu (menu) has a placeholder option (“Choisir le tir”) that doesn’t trigger any action, which could confuse users. It’s better to default to a functional option or disable the menu until a choice is made.
    • The volume display (wt and R) could be clearer, showing the exact value, the theoretical value (
      \frac{4}{3}\pi \cdot 2^3 \approx 33.5103
      ), and the error percentage.
    • The French text in the caption and title is fine, but consider adding English translations or making it language-neutral for broader accessibility.
  4. Point Management:
    • The clearPoints function deletes individual point objects, which is inefficient. Clearing the trail or using a single points object simplifies cleanup.
    • The scene.L list stores individual point objects, which can cause memory issues for large n. A single points object with a list of positions is more scalable.
  5. Rendering Performance:
    • For large numbers of points (e.g., 1,000,000), rendering individual points with radius=4 and opacity=1 can slow down the browser. Reducing point size or using a single points object improves performance.
    • The commented-out while True: rate(30) loop is unnecessary since this is not an animation, but it suggests the original intent might have been to animate point addition. If animation is desired, it could be added with a toggle.
  6. Code Clarity and Robustness:
    • The alea_point function returns a points object but also modifies the global success variable, mixing responsibilities. It’s cleaner to separate point creation and success counting.
    • The menu’s if statements are repetitive. A dictionary or mapping of point counts to actions would reduce code duplication.
    • The program lacks error handling for edge cases (e.g., division by zero if total is 0).
  7. Additional Features:
    • Add a “Clear” button to reset the simulation without selecting a new point count.
    • Display the theoretical volume and error percentage to show how the Monte Carlo estimate converges.
    • Allow users to toggle point visibility for better performance or to focus on the sphere and box.
    • Add an option to animate point addition gradually for educational purposes.
Optimized Code
Below is an improved version of the program incorporating these suggestions. It uses a single points object for efficiency, corrects the sphere radius check, improves the UI with clearer output, and adds a “Clear” button.

Key Improvements in the Code
  1. Efficient Point Rendering:
    • Uses a single points object (point_cloud) to store all points, with lists for pos and color. This is much faster than creating individual points objects, especially for 1,000,000 points.
    • Reduced point size from 4 to 2 for better performance without sacrificing visibility.
    • Lowered opacity of the box and sphere to 0.3 to make points more visible.
  2. Corrected Sphere Radius:
    • Fixed the sphere radius check in generate_point to use <= 2**2 (radius 2) instead of < 1. This ensures the correct volume estimation for a sphere of radius 2 (theoretical volume:
      \frac{4}{3}\pi \cdot 2^3 \approx 33.5103
      ).
    • The volume is calculated as 8 * success / total, where 8 is the cube’s volume divided by the scaling factor for the sphere’s radius.
  3. Improved UI:
    • Replaced wt and R with a single volume_display wtext that shows:
      • Estimated volume (to 4 decimal places).
      • Theoretical volume (
        \frac{4}{3}\pi \cdot 2^3
        ).
      • Error percentage.
      • Number of points used.
    • Added a “Clear” button to reset the simulation without selecting a new point count.
    • Menu options are streamlined with a dictionary to map choices to point counts, reducing repetitive if statements.
  4. Simplified Point Management:
    • The generate_point function separates point creation and success counting, improving clarity.
    • create_points uses lists for positions and colors, then assigns them to the points object in one go.
    • clear_points clears the points object and resets counters, avoiding manual deletion of individual points.
  5. Robustness:
    • Added a check in update_volume_display to avoid division by zero when total is 0.
    • The menu’s default option (“Select number of points”) does nothing, prompting the user to choose a valid option.
  6. Performance:
    • Generating and rendering 1,000,000 points is now faster due to the single points object.
    • The code avoids unnecessary loops (removed the commented-out while True: rate(30)).
How to Run
  1. Sign in or create an account.
  2. Click “Create New Program,” paste the code, and press “Run.”
  3. Select a number of points from the dropdown menu to generate points and estimate the volume.
  4. Click “Clear” to reset the simulation.
  5. Use the mouse to rotate (right-click/Ctrl-drag), zoom (scroll), or pan (Shift-drag).
Additional Suggestions for Further Enhancement
  • Animation Option: Add a button to generate points gradually (e.g., 100 points at a time) with a rate loop to visualize the Monte Carlo process dynamically.
  • Toggle Points: Add a checkbox to hide/show points for better performance or to focus on the sphere/box.
  • Export Results: Allow users to download the estimated volume and error as a text file.
  • Random Seed: Add an option to set a random seed for reproducible results.
  • Graphing: Plot the estimated volume vs. number of points to show convergence.
If you’d like to implement any of these additional features or need help with specific aspects, let me know!

Gilles Dubois

unread,
Jun 28, 2025, 9:13:27 AMJun 28
to VPython-users
I am all the more impressed.
So I rushed to Grok 3 to ask my own question about improving my program for conic section.
Analysis was correct but the corrected version doesn't work the widgets are inoperative  ! So we come back to our first concern.
Here is the (wise) report of Grok 

Your VPython program is designed to demonstrate why second-degree algebraic plane curves are called conic sections by visualizing the intersection of a plane with a double-napped cone. It allows users to choose between a "general case" (plane not passing through the cone's vertex) and a "special case" (plane passing through the vertex), adjust the plane's inclination, and observe the resulting conic section (hyperbola, parabola, ellipse, or degenerate cases like two lines or a point). Below, I’ll review the code, suggest improvements for clarity and functionality, and ensure it effectively meets the educational goal of illustrating conic sections.


Code Analysis

The program does the following:

  1. Setup:
    • Creates a double-napped cone using two cone objects (C1 and C2) with a 45° apex angle, positioned along the y-axis with the vertex at the origin (0,0,0).
    • Creates a plane represented by a thin box (P) that can be rotated to intersect the cone.
    • Allows camera control (rotate, zoom, pan) via mouse interactions.
  2. Interactivity:
    • A slider (sl) adjusts the plane’s inclination angle (0° to 180°) relative to the cone’s axis (y-axis).
    • Radio buttons (r1, r2) toggle between the "general case" (plane at y=0, offset from the vertex) and the "special case" (plane at y=0, passing through the vertex).
    • The intersection type (e.g., hyperbola, parabola, ellipse, or degenerate cases) is displayed via a wtext object (inter) based on the angle and case.
  3. Logic:
    • In the general case (case='G'), the plane’s position is offset (P.pos=vec(-2,0,0)), and the intersection depends on the angle:
      • < 45°: Hyperbola
      • = 45°: Parabola
      • < 135°: Ellipse
      • = 135°: Parabola
      • > 135°: Hyperbola
    • In the special case (case='P'), the plane passes through the vertex (P.pos=vec(0,0,0)), producing degenerate conics:
      • < 45°: Two lines
      • = 45°: One tangent line
      • < 135°: A point
      • = 135°: One tangent line
      • > 135°: Two lines
  4. Loop:
    • A while True loop with rate(30) keeps the scene active for real-time updates.

Issues and Suggestions for Improvement

While the program is functional, there are areas where it can be improved for clarity, robustness, and educational value:

  1. Intersection Visualization:
    • The program does not explicitly visualize the intersection curve (hyperbola, parabola, ellipse, etc.). It only displays the cone and plane and labels the intersection type via text. For educational purposes, rendering the actual intersection curve would be more impactful for students.
  2. Angle Logic:
    • The angle thresholds (45°, 135°) are correct for a cone with a 45° apex angle, but the code could include comments explaining why these angles correspond to specific conic sections (e.g., plane parallel to cone’s generator for parabola).
    • The else: pass clauses are unnecessary and can be removed for cleaner code.
  3. Initial Plane Orientation:
    • The plane’s initial axis is vec(0,1,0) (aligned with the cone’s axis), which may confuse users since the initial angle is 0° but the plane is not horizontal. Starting with a horizontal plane (axis=vec(1,0,0)) might be more intuitive.
  4. Rotation Axis:
    • The plane rotates around vec(0,0,1) (z-axis), which is appropriate, but the code could clarify that this rotation is relative to the cone’s axis (y-axis). A comment explaining the coordinate system would help.
  5. Degenerate Case Accuracy:
    • The "special case" correctly identifies degenerate conics (e.g., two lines, one line, a point), but the visualization of these cases (especially a single point or line) may be hard to interpret without rendering the intersection.
  6. User Interface:
    • The caption text is in French, which is fine if the target audience is French-speaking, but consider adding an English version or making it language-agnostic for broader use.
    • The slider’s step size (step=5) may make it hard to hit exact angles like 45° or 135°. A smaller step size (e.g., step=1) could improve precision.
    • The scene.append_to_caption('\n\ncas') line seems incomplete, possibly a placeholder for additional text.
  7. Performance:
    • The while True loop with rate(30) runs continuously, even when no updates are needed, which may consume unnecessary resources. Consider removing it if all updates are handled by event-driven functions (setincli, setcas).
  8. Educational Clarity:
    • Adding labels or annotations (e.g., for the cone’s axis, plane’s angle, or intersection type) directly in the 3D scene could make the visualization more self-explanatory.
    • A brief explanation of the mathematical relationship between the plane’s angle and the conic section type could enhance the educational value.

Improved Code

Below is an improved version of your program that addresses these issues, adds intersection visualization (approximated for simplicity), and enhances clarity. Since rendering exact intersection curves is complex, I’ll approximate the intersection by plotting points along the curve using a mathematical approach.

python
RéduireEnvelopperExécuter
Copier
from vpython import *
# Set up the scene
scene.width = 500
scene.height = 500
scene.title = """Conic Sections Demo
Intersection of a plane with a double-napped cone (45° apex angle)
"""
scene.caption = """Rotate camera: Right-click or Ctrl-drag.
Zoom: Mouse wheel.
Pan: Shift-drag.
Adjust the plane's inclination relative to the cone's axis (y-axis) below:\n
"""
# Create double-napped cone (apex angle = 45°, so radius = height)
C1 = cone(pos=vec(0, -7, 0), axis=vec(0, 7, 0), color=color.cyan, opacity=0.5, radius=7)
C2 = cone(pos=vec(0, 7, 0), axis=vec(0, -7, 0), color=color.cyan, opacity=0.5, radius=7)
# Create plane (thin box, initially horizontal)
P = box(pos=vec(0, 0, 0), length=15, height=0.04, width=15, color=color.red, opacity=0.5, axis=vec(1, 0, 0))
# List to store intersection curve points
curve_points = []
# Function to compute and display intersection (approximation)
def update_intersection():
global curve_points, case, angle
# Clear previous intersection points
for pt in curve_points:
pt.visible = False
curve_points.clear()
# Plane equation after rotation: ax + by + cz = d
# Normal vector after rotation around z-axis
normal = vec(cos(angle), sin(angle), 0)
d = normal.dot(P.pos) # d = 0 for special case, non-zero for general case
# Approximate intersection by sampling points on the plane and checking if they lie on the cone
cone_slope = 1 # For 45° apex angle, radius = height, so slope = 1
for x in range(-70, 71, 2): # Sample x
for z in range(-70, 71, 2): # Sample z
x, z = x / 10, z / 10
# Plane equation: solve for y
if abs(normal.y) > 1e-6: # Avoid division by zero
y = (d - normal.x * x - normal.z * z) / normal.y
else:
continue
# Check if point lies on cone: x² + z² = y² (for cone with slope 1)
if abs(x**2 + z**2 - y**2) < 0.1: # Tolerance for approximation
pt = sphere(pos=vec(x, y, z), radius=0.1, color=color.yellow)
curve_points.append(pt)
# Slider to adjust plane inclination
oldangle = 0
case = 'G'
angle = 0 # Current angle in radians
def setincli(s):
global oldangle, angle
wt.text = f"{s.value}°"
rotangle = (s.value - oldangle) * pi / 180 # Convert to radians
oldangle = s.value
angle = (s.value * pi / 180) # Store current angle
P.rotate(axis=vec(0, 0, 1), angle=rotangle, origin=vec(0, 0, 0))
# Update intersection type based on angle and case
if case == 'G':
if s.value < 45:
inter.text = 'Hyperbola'
elif abs(s.value - 45) < 1:
inter.text = 'Parabola'
elif s.value < 135:
inter.text = 'Ellipse'
elif abs(s.value - 135) < 1:
inter.text = 'Parabola'
else:
inter.text = 'Hyperbola'
else: # case == 'P'
if s.value < 45:
inter.text = 'Two Lines'
elif abs(s.value - 45) < 1:
inter.text = 'One Tangent Line'
elif s.value < 135:
inter.text = 'Point'
elif abs(s.value - 135) < 1:
inter.text = 'One Tangent Line'
else:
inter.text = 'Two Lines'
# Update intersection visualization
update_intersection()
sl = slider(min=0, max=180, value=0, length=360, bind=setincli, step=1)
wt = wtext(text="0°")
scene.append_to_caption('\n')
inter = wtext(text='Hyperbola')
scene.append_to_caption('\n\nCase:\n')
# Radio buttons for case selection
def setcas(evt):
global case
if evt.text == 'General':
P.pos = vec(0, -2, 0) # Offset plane
case = 'G'
else: # 'Special'
P.pos = vec(0, 0, 0) # Plane through vertex
case = 'P'
# Update intersection type and visualization
setincli(sl) # Reuse slider function to update text and intersection
r1 = radio(bind=setcas, checked=True, text='General', name='case')
r2 = radio(bind=setcas, text='Special', name='case')
# Initial intersection visualization
update_intersection()

Key Improvements
  1. Intersection Visualization:
    • Added an update_intersection function that approximates the intersection curve by sampling points on the plane and checking if they lie on the cone (where x² + z² = y² for a 45° cone). Points are plotted as small yellow spheres to visualize the conic section.
    • This is a simplified approximation; exact curve rendering would require solving the quadratic equation of the cone-plane intersection, which is more complex.
  2. Plane Orientation:
    • The plane starts horizontal (axis=vec(1,0,0)), making the initial 0° angle intuitive (parallel to the xz-plane).
    • The plane’s position is adjusted to y=-2 for the general case and y=0 for the special case, with the origin of rotation at (0,0,0).
  3. Angle Precision:
    • Reduced slider step size to step=1 for finer control.
    • Used abs(s.value - 45) < 1 and abs(s.value - 135) < 1 to handle floating-point imprecision when checking exact angles.
  4. Code Clarity:
    • Added comments explaining the cone’s geometry (slope = 1 for 45° apex angle) and plane equation.
    • Removed unnecessary else: pass clauses.
    • Simplified the main loop by relying on event-driven updates (slider and radio buttons).
  5. User Interface:
    • Translated captions to English for broader accessibility (can be reverted to French if needed).
    • Fixed the incomplete caption ('\n\ncas' → '\n\nCase:\n').
    • Made radio button labels consistent (“General” and “Special”).
  6. Educational Enhancements:
    • The intersection visualization makes the conic sections tangible for students.
    • The code includes comments to explain the mathematical basis (e.g., cone equation x² + z² = y²).

Limitations and Further Improvements
  1. Intersection Approximation:
    • The current intersection visualization is a discrete approximation. For a smoother curve, you could compute the exact parametric equations of the intersection (e.g., solving the plane equation with the cone equation x² + z² = y²) and plot a continuous curve using VPython’s curve object.
  2. Performance:
    • The intersection computation samples many points, which may slow down the program. Optimizing the sampling range or using analytical curves would improve performance.
  3. Annotations:
    • Adding 3D text labels (e.g., “Cone Axis”, “Plane Angle”, or the conic type) in the scene could enhance clarity.
  4. Degenerate Cases:
    • The special case visualization (e.g., a point or single line) may still be hard to see. You could highlight these with larger spheres or a line object.
  5. Mathematical Explanation:
    • For advanced students, you could add a caption explaining why the angles produce specific conics (e.g., plane parallel to the cone’s generator at 45° yields a parabola).

Educational Value

The improved program effectively demonstrates why second-degree curves are called conic sections:

  • General Case: Shows how the plane’s angle relative to the cone’s axis produces an ellipse (plane less steep than cone), parabola (plane parallel to cone’s generator), or hyperbola (plane steeper than cone).
  • Special Case: Illustrates degenerate conics (point, line, two lines) when the plane passes through the vertex, reinforcing the concept of limiting cases.
  • The interactive slider and radio buttons engage students, letting them explore how angle changes affect the intersection.
  • The visual approximation of the intersection curve makes the mathematical concept concrete.

If you want to add specific features (e.g., exact curve plotting, 3D annotations, or a mathematical explanation in the UI), let me know, and I can provide further modifications!


Gilles Dubois

unread,
Jun 28, 2025, 9:54:51 AMJun 28
to VPython-users
Grok's code doesn't work at all. The best suggestion was of course update_intersection, which I decided to add to my own code to obtain this :
from vpython import *

scene.width = 500
scene.height = 500

scene.title = """Coniques - Intro
Intersection d'un plan avec un cône
Dans notre exemple l'angle du cône est de 45°
"""
C1 = cone(pos=vec(0, -7, 0), axis=vec(0, 7, 0), color=color.cyan, opacity=0.5, radius=7)
C2 = cone(pos=vec(0, 7, 0), axis=vec(0, -7, 0), color=color.cyan, opacity=0.5, radius=7)
P = box(pos=vec(-2, 0, 0), length=15, height=0.04, width=15, color=color.red, opacity=0.5, axis=vec(0, 1, 0))

scene.caption = """Pour faire tourner la caméra : drag avec bouton droit ou bien Ctrl-drag.
Pour zoomer utiliser la roulette.
Pour panorama droite/gauche et haut/bas : Maj-drag.

Ci-dessous réglez l'inclinaison du plan par rapport à l'axe du cone\n
"""

oldangle = 0
angle=0
case = 'G'
curve_points = []



def update_intersection():
    global curve_points, case, angle
    # Clear previous intersection points
    for pt in curve_points:
        pt.visible = False
    curve_points.clear()

    # Plane equation after rotation: ax + by + cz = d
    # Normal vector after rotation around z-axis
    normal = vec(cos(angle), sin(angle), 0)
    d = normal.dot(P.pos)  # d = 0 for special case, non-zero for general case

    # Approximate intersection by sampling points on the plane and checking if they lie on the cone
    cone_slope = 1  # For 45° apex angle, radius = height, so slope = 1
    for x in range(-70, 71, 2):  # Sample x
        for z in range(-70, 71, 2):  # Sample z
            x, z = x / 10, z / 10
            # Plane equation: solve for y
            if abs(normal.y) > 1e-6:  # Avoid division by zero
                y = (d - normal.x * x - normal.z * z) / normal.y
            else:
                continue
            # Check if point lies on cone: x² + z² = y² (for cone with slope 1)
            if abs(x ** 2 + z ** 2 - y ** 2) < 0.1:  # Tolerance for approximation

                pt = sphere(pos=vec(x, y, z), radius=0.1, color=color.yellow)
                curve_points.append(pt)
update_intersection()
while True:
    rate(30)
But behavior is unchanged intersection doesn't appear ( understand is not enhanced). No error, no result...

John

unread,
Jun 28, 2025, 11:12:00 AMJun 28
to VPython-users
I agree that Grok code doesn't always work. I had to go through several iterations with it in order to get the desired result. For instance I had to tell it to use the import statement in the Cylinder version of the Web VPython code

from random import uniform

since it wasn't aware that this was possible in Web VPython. I also needed to provide it links to some VPython documentation and a link to the uniform distributions over a disk article.
https://mathworld.wolfram.com/DiskPointPicking.html
and told Grok to use these. However in the end it did generate the final result I expected after several iterations of interacting with it. So it can be a useful tool in some programming situations if you are able to tell it exactly what the desired result is, at least it did it for me in this simple example.

I think to use Grok effectively in coding it will be necessary to write a good prompt to tell it exactly what the desired result is. There are several videos and tools available on how to write a great prompt for AI like the following link. This is all new to me so I guess I will need to improve my prompt writing skills to get AI to do what I want it to do.

Here is a video of a developer giving his thoughts on the current state of AI in coding.
https://youtu.be/SeyB0xGJdsE?si=OEjcQGmNq2Zf8anU

John

unread,
Jun 28, 2025, 1:00:42 PMJun 28
to VPython-users
I installed a free AI prompt extension into my Chrome browser called Prompt Perfect to help create better prompts. Here is a prompt it generated that you can enter into Grok which will in turn explain how it works.

"I would like to understand the process of utilizing the Prompt Perfect Chrome extension in conjunction with Grok. Specifically, I am looking for detailed steps on how to install and configure the extension, as well as tips on best practices for integrating it with Grok to enhance my experience. Please provide a structured response that includes installation instructions, configuration settings, and any relevant examples or use cases that demonstrate the effective use of this combination." 

John

unread,
Jun 28, 2025, 1:54:20 PMJun 28
to VPython-users
I fed Grok the following prompt:

"How can I recreate the Visualizing the Proton program in Web VPython that is explained at this link.

https://arts.mit.edu/projects/visualizing-the-proton/

"
And from this simple prompt it produced some text and some VPython code that output the following working 3D animation of a proton with 3 quarks and several gluons in its first attempt.

VisProton.jpg

Gilles Dubois

unread,
Jun 28, 2025, 3:26:15 PMJun 28
to vpytho...@googlegroups.com

"What you find is more important than what you're looking for".

We began with tuning up a vpython program and finish with AI assisted programming.

I discovered a lot of things.

First that AI have access to semantics of a program from the code they can explain in natural language what the problem does, what is its purpose. Reversely from a goal explained in plain English (or French or whatever) it can (in some cases) propose programs supposed to do the job.

This is quite a discovery for me. By the way if you are lazy documenting your code (my case) you can ask GROK doing it for you

The experience I had were not encouraging but my attitude was negative. I started from the point of view that AI was still in the limbos, using tricks as old as Weizenbaum ELIZA (1964) together with new technologies known as web scraping and data mining. But the examples I discovered with you were interesting and obliged me to change my mind.

But of course as a principle only intelligent questions receive intelligent (and useful) answers...

So the prompting is important

First even if you do not receive exactly what you expect, you always receive something interesting, so it's your duty to refine your questions again and again to head the AI in the right direction.

Maybe ALTAVISTA says nothing to you, it was something  as the common ancestor of all search engines. In this time (1995) some courses were organized to learn how to use the good keywords in the good order for an efficient filtering. Promptperfect (I registered today) make me think of this time. So yes AI are smart but (for now    at least) you must learn how to communicate with them.

To come back to my conic sections I was disappointed not to find something as 'intersection' of two objects, but I understood that given the shapes of basic objects the result could be nothing but a 'Points' with position(s) (precision or definition) defined by program. But this doesn't exist in standard VPython. So the use of equations was quite natural. But in our case we had a linear equation for the plan and a quadratic equation for the cone. So the generic point is defined by 2 parameters (which you can choose). And GROK was smart enough to come to this conclusion and propose the corresponding code. Of course there is something wrong because it doesn't work. But it's my duty now to find out why, unless I become enough prompt expert to ask GROK to correct its own mistake. That would be a challenge.

John

unread,
Jun 29, 2025, 1:46:03 AMJun 29
to VPython-users
I think you are not seeing the intersection of the conic and the plane is because in the function update_intersection() the value of normal.y is zero and you end up in the else condition in this code.

            if abs(normal.y) > 1e-6:  # Avoid division by zero
                y = (d - normal.x * x - normal.z * z) / normal.y
            else:      
                continue

So you never run the code after that which calculates the intersection. Also you should probably call the update_intersection() function when you move the slider and you should probably pass the angle as a parameter to this routine. You can add print() statements to your code which appear in the terminal window to debug it. For instance you can add a print statement in update_intersection() each time it is called.

    print("called update_intersection() with angle =", angle)

    print("normal.y = ", sin(angle))

Hope this helps.

John

unread,
Jun 29, 2025, 5:38:18 PMJun 29
to VPython-users
Here is a working version of your conic sections program that shows the intersection points.

John

unread,
Jun 29, 2025, 6:49:14 PMJun 29
to VPython-users
Here is an updated working version of your conic sections program with updates suggested by the AI. It also has a start/stop button to animate the slider.

https://glowscript.org/#/user/johncoady/folder/AI/program/AIconicsections

Gilles Dubois

unread,
Jun 30, 2025, 12:46:26 AMJun 30
to vpytho...@googlegroups.com

Perfect ! I had a version of my own correct for general case but not satisfactory for degenerated (special) one.

Here's my code

from vpython import *

scene.width = 500
scene.height = 500

scene.title = """Coniques - Intro
Intersection d'un plan avec un cône
Dans notre exemple l'angle du cône est de 45°
"""
C1 = cone(pos=vec(0, -7, 0), axis=vec(0, 7, 0), color=color.cyan, opacity=0.5, radius=7)
C2 = cone(pos=vec(0, 7, 0), axis=vec(0, -7, 0), color=color.cyan, opacity=0.5, radius=7
)
P = box(pos=vec(-2, 0, 0), length=15, height=0.02, width=15, color=color.red, opacity=0.5, axis=vec(0, 1, 0))
V1=P.axis
V2=P.up
V3=cross(V1,V2)

scene.caption = """Pour faire tourner la caméra : drag avec bouton droit ou bien Ctrl-drag.
Pour zoomer utiliser la roulette.
Pour panorama droite/gauche et haut/bas : Maj-drag.

Ci-dessous réglez l'inclinaison du plan par rapport à l'axe du cone\n
"""

oldangle = 0
angle=0
case = 'G'
curve_points = []


def update_intersection
():
    global V1,V2,V3,P,curve_points
    
for pt in curve_points:
        pt.visible = False
    
curve_points.clear()
    V1 = P.axis
    V2 = P.up
    V3 = cross(V1, V2)
    L=[P.pos+(h/100)*V1+(k/100)*V3 for h in range(-50,51) for k in range(-50,51)]
    I=[]
    for V in L:
        if abs(V.x*V.x+V.z*V.z-V.y*V.y)<0.2:
            I.append(V)
    for V in I:
        pt=sphere(pos=V,radius=0.05, color=color.yellow)
        curve_points.append(pt)


    update_intersection()

sl = slider(min=0, max=180, value=0, length=360, bind=setincli, step=5)

wt = wtext(text=str(sl.value) + '°')

scene.append_to_caption('\n')
inter = wtext(text='Hyperbole')

scene.append_to_caption('\n\ncas')


    update_intersection()


r1 = radio(bind=setcas, checked=True, text='Général', name='cas')
r2 = radio(bind=setcas, text='Particulier', name='cas')
update_intersection()
while True:
    rate(30)

Gilles Dubois

unread,
Jun 30, 2025, 7:53:50 AMJun 30
to vpytho...@googlegroups.com

Simply perfect !

Le 30/06/2025 à 00:49, John a écrit :

John

unread,
Jun 30, 2025, 10:11:51 AMJun 30
to VPython-users
I wrote some of the code by hand to determine the intersection, it wasn't all AI. I made use of the formula for "The Intersection of a Line and a Plane" that I posted about here.

https://groups.google.com/g/vpython-users/c/XIE5koUptdM/m/_cx7UaQ4AwAJ

Gilles Dubois

unread,
Jun 30, 2025, 10:30:11 AMJun 30
to VPython-users

Gilles Dubois

unread,
Jul 1, 2025, 12:33:14 AMJul 1
to VPython-users
The same with contact points of both Dandelin's spheres with cone

John

unread,
Jul 1, 2025, 9:20:28 AMJul 1
to VPython-users
I guess you can further improve it by adding the focus points of the ellipse where the Dandelin spheres are tangent to the plane P.

Gilles Dubois

unread,
Jul 1, 2025, 9:36:41 AMJul 1
to vpytho...@googlegroups.com

Yes it would be good. Again the same trick will work (intersection of the normal to the plane passing through the center of the sphere). BTW I have been knowing this trick for ever and  I show this method in my geometry course in the explicit example 7 of this page . Simply it's you you remind me to use it with the generatrices of the cone, that was the good idea.

I have a few remarks (positive and negative) about programming directly in web vpython.

I'm a little busy right now, but I will come back to it.

Gilles Dubois

unread,
Jul 1, 2025, 4:44:55 PMJul 1
to VPython-users

John

unread,
Jul 1, 2025, 8:01:44 PMJul 1
to VPython-users
Instead of programming directly in web vpython you can also try using the trinket interface.


For more about trinket.io visit

Gilles Dubois

unread,
Jul 2, 2025, 3:36:43 AMJul 2
to VPython-users
Original with 'curve' object instead of list of spheres

Gilles Dubois

unread,
Jul 2, 2025, 8:39:53 AMJul 2
to VPython-users
Last version 
Full functionality, clean code (avoiding repetition - I had forgotten  the initial call to update_intersection)

Reply all
Reply to author
Forward
0 new messages