Labs 1 and 2: Python, Jupyter, DataHub, NumPy, SciPy, and Matplotlib#

Lab 01: Python, Jupyter, and DataHub#

  • Get your own copy running

  • Change a number; run it again

Open your own copy of this notebook so you can change the code.

Start from the website: open the lab page (https://jduarte.physics.ucsd.edu/phys142/labs/lab01_lab02.html), or scan this QR code. You can click it too.

QR code linking to Labs 1 and 2 on the course website

On that page, click the rocket icon at the top right. The box below marks it and the menu it opens.

  • JupyterHub opens the notebook on UCSD DataHub. Sign in with your UCSD email and select the course environment. If it isn’t listed, ask me.

  • Colab opens it with your Google account. Choose File → Save a copy in Drive so you can keep your edits, then click Connect. You don’t need a GPU.

Rocket icon and launch menu highlighted in magenta

Upload it yourself instead: if you already downloaded the .ipynb, either of these works:

  • DataHub: go to datahub.ucsd.edu, sign in, and select the course environment. Use the upload button in the file browser on the left, then double-click the notebook. Rename your copy and save it.

  • Colab: go to colab.research.google.com, choose File → Upload notebook, and select the file. Save a copy to Drive and click Connect.

Click the cell below and press Shift+Enter. Then change one of the numbers and run it again.

2 + 3

Code cells and text cells#

  • Double-click this cell

  • Text cells versus code cells

The cell you just ran is a code cell. This one is Markdown: text with formatting. Double-click it to see how it’s written, then press Shift+Enter to render it again. Use the toolbar to add a cell and choose Code or Markdown. Colab calls Markdown cells Text.

Add a Markdown cell with a heading and a sentence. You can use this as a starting point:

### My notes
This is **bold**, and this is `code`.

A notebook saves the code, text, and displayed results together. The kernel is the Python process running your code; Colab calls it a runtime. If a cell is still running, you’ll see a spinner or [*]. The stop button interrupts it.

Variables and arithmetic#

  • Assignment stores a value

  • Print versus the last expression

= assigns a value to a name. Once we’ve defined temperature_c, we can use it in another calculation. Here we’re converting Celsius to Fahrenheit.

Python runs each line in order. print shows a value; an expression on the last line of a cell also displays its result.

temperature_c = 20.0
temperature_f = temperature_c * 9 / 5 + 32
print(temperature_f)
  • Predict it, then run it

  • Parentheses change what happens first

Change temperature_c to 0 and run the cell again. You should get 32.

+, -, *, and / do arithmetic. ** raises a number to a power; ^ doesn’t. Parentheses control the order, and 1e-3 means 0.001. Try 2**3, (2 + 3) * 4, and 2 + 3 * 4 in a new code cell.

The order you run cells matters#

  • Change the input; leave the output

  • Now rerun the second cell

Run the next two cells. Then change number in the first cell and run only that cell. The second cell’s old output doesn’t update on its own. Run the second cell again to use the new value.

number = 5
print(number * 2)
  • Old output can still be visible

  • Restarting clears the variables

The kernel remembers variables from cells you’ve already run. Saving the notebook doesn’t save that running Python session. After a restart, you’ll need to run the definitions again.

If you get NameError, check the spelling and whether you’ve run the cell that defines the name. Don’t assume that visible output means the variable still exists.

Numbers, text, and comparisons#

  • Same digits, different types

  • Ask Python what type it is

Python distinguishes integers (int), decimal numbers (float), text (str), and true/false values (bool). type tells you which one you have. Quotation marks make text: "20" and 20 aren’t the same thing.

count = 6
reading = 20.5
sensor_name = "Sensor A"
above_limit = reading > 20

print(type(count), type(reading), type(sensor_name), type(above_limit))
  • A comparison gives True or False.

print(above_limit)
  • Predict: what does adding text do?

print("20" + "5")
  • Convert first. Then add.

print(float("20") + 5)
  • Put values into a sentence.

print(f"{sensor_name}: {reading:.1f} degrees C")
  • Printing fewer decimals changes the display

  • Assignment and comparison use different operators

The f before the last string lets us insert values inside {...}. :.1f displays one decimal place. It only changes how the number looks when printed.

float("20") converts text to a number, so + does addition instead of joining text. Text after # is a comment; Python doesn’t run it.

Use == to compare values, and = to assign them. Other comparisons are !=, <, <=, >, and >=. Try reading == 20.5 and reading < 20.

Lists#

  • Count indices from zero

  • The slice stops before that index

A list holds several values. Indexing starts at 0, so readings[0] is the first entry. [-1] is the last. A slice like [1:4] takes entries 1, 2, and 3; the stop index is excluded.

readings = [20.0, 21.1, 21.8, 23.2, 23.9, 25.1]
readings
  • First is 0. Last is -1.

print("First:", readings[0])
print("Last:", readings[-1])
  • Predict which entries survive the slice.

print("Slice:", readings[1:4])
  • Count the entries.

len(readings)
  • Add them up. Divide by the count.

sum(readings) / len(readings)
  • Six entries, indices zero through five

  • Rerun the definition to restore it

Try readings[:3] and readings[3:]. What happens if you ask for readings[6]? There are six readings, but their indices are 0 through 5. After seeing the error, remove that trial line or put # in front of it so Run All can finish.

You can replace an entry with readings[0] = 19.8, or add one with readings.append(26.0). Try both, then rerun the cell that defines readings to restore the list.

Loops and conditions#

  • Trace one reading at a time

  • Point out the colon and indentation

A for loop repeats its indented lines for each value. Here we use an if statement to print only the readings above 23. The colon and indentation are part of the syntax.

readings = [20.0, 21.1, 21.8, 23.2, 23.9, 25.1]
for reading in readings:
    if reading > 23:
        print(reading)
  • Flip the condition

  • Build a new list with append

Change the condition to print readings at or below 23. You can add an else: at the same indentation as if to do something when the condition is false.

Here’s a loop that builds a new list. append adds each converted value to the end.

fahrenheit_readings = []
for reading in readings:
    converted = reading * 9 / 5 + 32
    fahrenheit_readings.append(converted)
  • Look at what the loop built.

fahrenheit_readings
  • Where does the sequence stop?

  • Four values, starting at zero

Use range when you want a sequence of integers. range(4) gives 0, 1, 2, 3. It excludes the stop value, just like a slice.

for index in range(4):
    print(index, index**2)

Functions#

  • Define once; call with different inputs

  • Return a value you can reuse

We’ve written the temperature conversion twice. Put it in a function so we can call it with different inputs. def defines the function; return gives its result back to the code that called it.

def to_fahrenheit(celsius):
    return celsius * 9 / 5 + 32
  • Define once. Call with different inputs.

to_fahrenheit(0)
to_fahrenheit(100)
  • Keep the returned value.

converted = to_fahrenheit(20)
print(converted)
  • Write the reverse conversion

  • Check both known temperatures

Write to_celsius(fahrenheit) below. Subtract 32, then multiply by 5/9. Check that 32 °F gives 0 °C and 212 °F gives 100 °C.

Use return, not just print: we want to use the result in another calculation.

# Write your to_celsius function here, then call it with 32 and 212.
One way to write it
def to_celsius(fahrenheit):
    return (fahrenheit - 32) * 5 / 9

print(to_celsius(32))
print(to_celsius(212))

When a cell fails#

  • Read the last error line first

  • Check the indicated line

Read the last line of the error first, then look at the line it points to.

  • NameError: the name hasn’t been defined in this session, or it’s misspelled.

  • TypeError: check what kinds of values you’re combining. Text plus a number is a common one.

  • IndexError: the list or array doesn’t have the entry you requested.

  • SyntaxError or IndentationError: check brackets, colons, and indentation.

Python decimal arithmetic also has rounding error. Run the next two cells and compare the results.

0.1 + 0.2
  • Predict: will exact equality pass?

0.1 + 0.2 == 0.3
  • Small rounding differences are expected

  • Restart, then run from the top

Most decimals aren’t represented exactly in binary. The small difference here isn’t a reason to round every calculation. Below we’ll use NumPy’s isclose when comparing numbers.

Save your notebook. Restart the kernel from the Kernel menu in JupyterLab, or restart the session from Runtime in Colab. Run the Lab 01 cells from the top. If a name is missing, find where it should have been defined.