Skip to article frontmatterSkip to article content

Appendix B - An Introduction to Visual Python

B.1Overview

This appendix gives a very brief introduction to calculus with a focus on the tools needed in physics.

B.2Code in this textbook

When referring to general ideas or something very brief, Visual Python code may be written in-line. For example, this is a general code statement. When giving explicit code to be implemented, Visual Python code will be written in “display mode”. For example,

print("This code is meant to be implemented into a trinket.")

The distinction should become clear as you work through this appendix. We hope to provide in this textbook all of the instruction necessary to create physics simulations using Visual Python in the trinket platform. In the event that more information is desired, a good reference is https://www.glowscript.org/docs/VPythonDocs/index.html.

B.3The trinket.io platform

Trinket.io is web-based programming platform with a few different programming languages available,e.g., Python, Visual Python, R, Java, and HTML5. In this textbook, we will use primarily Visual Python, which is a language built on Python that allows Python programming to manipulate simulated objects in three-dimensional space. The trinket Figure B.1 is a Visual Python program that simulates a moon-like mass orbiting an Earth-like mass. Click the play button to see the simulation.

Figure B.1:The moon orbiting the Earth.

A few notes about the embedded trinkets in this book:

  • The menu in the upper left corner allows full-screen viewing.
  • The center bar between the code and the simulation can be adjusted to make the either consume more of the screen for easier viewing.
  • The right mouse button allows rotation of the view.
  • The mouse wheel allows zooming in and out of the view.
  • If signed into trinket, readers should be able to click “Remix” in the upper right corner to save a trinket to their own account.

B.3.1Trinket accounts

The website trinket.io offers a variety of accounts. You can learn more about these at https://trinket.io/schools. The three main account modes trinket might be implemented in your course are

  • with free accounts for everyone where the instructor shares pre-written shells for students to complete
  • with free accounts for students and a pay account for the instructor. This allows the instructor to build trinket courses with assignments.
  • with pay accounts for everyone that offers the most options.

B.3.2What is a trinket?

A trinket is a Visual Python program written in the trinket.io web platform. When starting a new program, a trinket will look like Figure B.2. The Web Vpython line indicates the language. This line should always be in a trinket that uses the Visual Python language. The version number may change as updates are made to the Visual Python language.

Figure B.2:A blank trinket ready to begin programming.

Trinkets in this book are interactive. Readers can enter code and run the code while reading the textbook. Give it a try. Enter the following code and click the play button.

print("Hello World! This is my first trinket.")

If you wish, you can Remix the trinket to your own account. It will appear in your account as “BlankTrinket”. You may rename your trinkets from the trinket.io website.

B.4Programming in Visual Python

B.4.1Create objects in a trinket

The choice of Visual Python is so that readers can visualize the physics being discussed in the book. Therefore, almost every program will be focused on manipulating Visual Python objects. It is important for readers to become comfortable with creating these objects. In the following examples, we will demonstrate spheres and cylinders. All Visual Python objects have “attributes” such as position, color, and size. lists common objects and their attributes. Notice the attributes vary in definition such as vector, scalar, or some text-based variable. It is also possible to create new, user-defined attributes, which will be discussed below.

Table B.1:A quick reference for a few commonly used objects and their attributes

ObjectAttributes
spherepos (vector) – Position of center. Default (0,0,0).
radius (scalar) – Default 1.
color (vector) – Default color.white
size (vector) – Dimensions of a box surrounding the sphere. Default (2,2,2).
axis (vector) – Default (1,0,0)
boxpos (vector) – Position of center. Default (0,0,0).
axis (vector) – Extends from left to right end. Default <1,0,0>.
color (vector) – Default color.white.
length (scalar) – Length of box. Default 1.
height (scalar) – Height of box. Default 1.
width (scalar) – Width of box. Default 1.
size (vector) – Length, width, and height in one vector. An alternative to length, height, width.
arrowpos (vector) – Position of tail. Default (0,0,0).
axis (vector) – Extends from tail to tip. Default (1,0,0).
color (vector) – Default is color.white
round (boolean) – Makes shaft and head round instead of square. Default is False.
shaftwidth (scalar) – Width of tail. Default 0.1*(length of arrow)
headwidth (scalar) – Default 2*shaftwidth
headlength (scalar) – Default 3*shaftwidth
cylinderpos (vector) – Position of left end. Default (0,0,0).
axis (vector) – Extends from pos to end. Default (1,0,0).
color (vector) – Default color.white.
radius – Radius of the cylinder. Default is 1.
length (scalar) – Length of axis. Setting length sets magnitude of axis. Default is 1.
size (vector) – Length, height, width of a box surrounding the cylinder. Default is (1,1,1).

B.4.1.1Spheres

To create a sphere at the origin of a cartesian coordinate system, enter the following code.

ball = sphere(pos=vec(0,0,0), color=color.green, radius=0.1)

One can think of the spatial coordinate system being in meters so that all lengths are denoted in meters. Of course, this is arbitrary, and the scale could be considered any length desired, and the programming would need to match the chosen scale. Notice the color is defined with color=color.green. It is important to define colors this way, i.e., with the “color-dot” format. Readily available colors are red, green, blue, cyan, magenta, yellow, orange, purple, and white. The radius variable is often chosen based on the scale of motion that will be simultated. For example, if the sphere is going to be moved centimeters, the radius should be smaller than 1 cm, and if the sphere is going to move meters, the radius would be smaller than 1 meter.

B.4.1.2Cylinders

To create a magenta cylinder 5 meters long, radius 0.1 meter, named cyl, with one end at the origin and along the xx-axis, enter the following code.

cyl = cylinder(pos=vec(0,0,0), axis=vec(1,0,0), radius=0.1, length=5, size=2, color=color.magenta)

The axis can easily be changed to orient a cylinder along the cartesian axes. If it desired for the cylinder to be oriented at an angle, one would use the Pythagorean Theorem or trigonometry to determine the unit vector pointed in the desired direction. Then, this would become the axis vector. For example, a cylinder oriented at 45°45\degree in the xyxy-plane would be found by

x=rcos45°y=rsin45°z=0\begin{align*} x &= r\cos 45\degree\\ y &= r\sin 45\degree\\ z &= 0 \end{align*}

Since we want a unit vector (r=1r=1), and x=y=1/2x=y=\sqrt{1/2}. In Python power are expressed using ** rather than ^. The command to orient a cylinder at 45°45\degree is

cyl = cylinder(pos=vec(0,0,0), axis=vec(0.5**0.5,0.5**0.5,0), radius=0.1, length=5, size=2, color=color.magenta)

However, we may also use trigonometric functions.

cyl = cylinder(pos=vec(0,0,0), axis=vec(cos(pi/4),sin(pi/4),0), radius=0.1, length=5, size=2, color=color.magenta)

B.4.1.3for loops

It is possible to simplify the code using a for loop. This loop will increment through the desired angles to create the clock face with a single cylinder object command. The advantage is streamlined code. The disadvantage is that the cylinder objects cannot be manipulated unless we complicate the program by tracking the object names. This kind of programming is beyond the scope of this textbook. Figure B.5 shows the code using a for loop. In this program, we define the number of cylinders we want numcyl. This number is used to divide 2π2\pi into that many angle segments. The for loop uses the Python range() function, which is an “inclusive-exclusive” list. That is, for i in range(N): would increment i from 0 to N-1. Notice the tabbing after the line beginning the loop indicates which commands are inside the loop.

Figure B.5:For loop to place cylinders every 30°30\degree.

B.4.1.4User-defined attributes

Object attributes are accessed using the “dot” notation. For example, the position of a sphere named ball can be accessed with ball.pos. It is possible to add user-defined attributes to an object. Assigning attributes is a simple way to keep track of variables and constants associated with objects. These attributes do not affect the visualization of the object. Some examples of assigning attributes to a sphere named ball are shown in Table B.2. Users are free to choose the names of the attributes they assign. Rembember that computer code is unit agnostic. The units are whatever the programmer decides, and it is up to the programmer to keep track of units. In this book, we will primarily use SI (or mks) units.

Table B.2:Some examples of user-defined object attributes.

AttributeVisual Python
massball.m = 5
velocityball.vel = vec(1,1,1)
accelerationball.acc = vec(0,0,-9.8)
momentumball.p = ball.m * ball.vel

B.5Move objects using code and physics

Once we have objects, we can apply physical principles to make them move. One way to make the ball move is to repeatedly update the position using kinematic descriptions of motion. If we define an object’s position as r\vec r, the object will change position over time as

r(t+Δt)=r(t)+vΔt+12aΔt2\vec r(t + \Delta t) = \vec r(t) + \vec v\Delta t + \frac{1}{2}\vec a\Delta t^2

Suppose we want to model a situation where there is not acceleration. We could write lines of code that take the current position r(t)\vec r(t) and update it with some amount vΔt\vec v\Delta t. Since we are in a 3D world, we must do this with vectors. For simplicity, let’s assume the velocity is only the xx-direction that is a speed of v=0.5m/sv = 0.5 {\rm m/s}, i.e., ball.vel=vec(0.5,0,0). Suppose we want to update every second, i.e., t = 0, 1, 2, 3,... or Δt=1\Delta t = 1. To update the position of our object we could write code to position the ball each second that passes.

ball = sphere(pos=vec(0,0,0), radius=0.1, color=color.red)
ball.vel=vec(0.5, 0, 0)
dt = 1
ball.pos = ball.pos + ball.vel * dt #move ball after 1s
ball.pos = ball.pos + ball.vel * dt #move ball after 2s
ball.pos = ball.pos + ball.vel * dt #move ball after 3s
ball.pos = ball.pos + ball.vel * dt # move ball after 4s
ball.pos = ball.pos + ball.vel * dt # move ball after 5s

The statements at the end of the lines after # are comments that are ignored by the computer. Copy the code above run these lines in the trinket below.

Figure B.2:A blank trinket ready to begin programming.

You will see that your program runs all of the lines instantly, and you do not see the motion. Slow the computation down by adding the command rate(1) between each line updating the ball’s position. This will delay each line by 1 second. For example,

ball.pos = ball.pos + ball.vel * dt
rate(1)
ball.pos = ball.pos + ball.vel * dt
rate(1)

It might also be helpful to keep track of the time and position. To do this, create a variable for time, t, and add print statements between each move. Notice below that we can access the xx position with ball.pos.x.

ball = sphere(pos=vec(0,0,0), radius=0.1, color=color.red)
ball.vel=vec(0.5, 0, 0)
t = 0
dt = 1
print(t, ball.pos.x)
rate(1)
ball.pos = ball.pos + ball.vel * dt #move ball after 1s
t = t + dt #increase the total time
print(t, ball.pos.x)
rate(1)
ball.pos = ball.pos + ball.vel * dt #move ball after 2s
t = t + dt #increase the total time
print(t, ball.pos.x)
rate(1)
ball.pos = ball.pos + ball.vel * dt #move ball after 3s
t = t + dt #increase the total time
print(t, ball.pos.x)
rate(1)
ball.pos = ball.pos + ball.vel * dt # move ball after 4s
t = t + dt #increase the total time
print(t, ball.pos.x)
rate(1)
ball.pos = ball.pos + ball.vel * dt # move ball after 5s
t = t + dt #increase the total time
print(t, ball.pos.x)

Finally, let’s make the ball’s motion obvious by adding a trail to it. In the definition of the ball add make_trail = True.

ball = sphere(pos=vec(0,0,0), radius=0.1, color=color.red, make_trail=True)

B.5.1while loops

Hopefully it is clear to you this is an inefficient way to write a program, especially if we want to run many iterations of changing the ball’s position. To make the process more streamlined, we use loops. In this case, we will use a while loop. The while loop runs “while” a condition is met. For example, we can run the ball simulation while the time is less than 5 seconds. Because the loop streamlines the computation, we can get higher time resolution and update the position every 0.1 second. A while loop looks similar to a for loop.

while t < 5:

Since we are using the total time as the condition for the while loop, it is important to keep track of the total time as we did in the previous section. To implement a while loop, we first initialize variables and objects. Then, every command inside the while loop will repeat until the condition is met.

#Initialization of objects and variables
ball = sphere(pos=vec(0,0,0), radius=0.1, color=color.red, make_trail=True)
ball.vel=vec(0.5, 0, 0)
t = 0
dt = 0.1

while t < 5:
	rate(1)
	ball.pos = ball.pos + ball.vel * dt #move ball after dt
	t = t + dt #increase the total time
	print(t, ball.pos.x) #print time and position

Copy and paste this code to replace the code from the previous section. It will appear to run very slowly. Increase the rate until the motion looks continuous.