Problems: Python Basics#

Get this problem set

Download everything (Topic1.1-Python_Basics_Problems.zip) — the notebook and water_properties.csv, in a folder that is ready to run as-is.

The Download badge at the top of the page will also give you the notebook on its own. On Vocareum everything is already set up for you.

This is the first problem set of the course, so it does two jobs: it gets you started with Python and data files, and it shows you how every later problem set will be arranged.

How these problem sets work

Every set is worth 100 points and has the same three parts.

Part A — Skill Checks (30 pts). Short questions with one right answer. You assign your answer to a named variable, then run a check cell that tells you immediately whether it is accepted. You may resubmit as often as you like, so there is no reason to hand in a Part A that does not pass. The check cells look like this:

grader.check("q1")

Part B — Visualization (35 pts). Make a plot and say what it shows. Graded by your peers against a rubric, so there is usually more than one acceptable answer — but the rubric is specific about what has to be there.

Part C — Open Ended (35 pts). A question with no single right answer, where you are graded on the reasoning and on whether your conclusions follow from what you actually computed. Also peer graded.

The parts build on each other. Part A works out the syntax you need for Part B, and Part B produces the evidence you argue from in Part C, so do them in order.

Cells marked # YOUR CODE HERE are yours to fill in. Everything else is provided and should run as-is.

One convention worth knowing before you start: a line like n_rows = ... is a placeholder. The three dots are real Python — an object called Ellipsis that does nothing — and they mark the spot where your answer goes. Replace the ..., do not add to it. If you run the check cell without replacing it, the autograder will tell you the question is unanswered rather than marking it wrong.

Setup#

The dataset is data/water_properties.csv: four thermophysical properties of liquid water, tabulated every 2 °C from the freezing point to the boiling point at 1 bar. It comes from the NIST Chemistry WebBook, which serves the IAPWS-95 formulation — the international standard for the properties of water.

Water is worth starting with because you already know roughly how it behaves, so when the code gives you a number you can tell whether it is sensible. That is a habit worth forming now: the first question to ask of any computed result is whether it could possibly be right.

import numpy as np
import pandas as pd

df = pd.read_csv('data/water_properties.csv')
df.head(10)
temperature [C] density [kg/m^3] Cp [J/g/K] viscosity [Pa*s] thermal conductivity [W/m/K]
0 0.01 999.84 4.2194 0.001791 0.55567
1 2.01 999.94 4.2130 0.001673 0.56069
2 4.01 999.97 4.2075 0.001567 0.56549
3 6.01 999.94 4.2027 0.001471 0.57010
4 8.01 999.85 4.1987 0.001384 0.57453
5 10.01 999.70 4.1951 0.001306 0.57880
6 12.01 999.50 4.1921 0.001234 0.58291
7 14.01 999.25 4.1896 0.001168 0.58688
8 16.01 998.94 4.1874 0.001108 0.59072
9 18.01 998.60 4.1856 0.001052 0.59444

import numpy as np loads a library and gives it a short nickname, so every function from it is written np.something — this is why NumPy calls all look alike. pd.read_csv reads a comma-separated file into a DataFrame, a table that remembers its column names. df.head(10) shows the first ten rows, which is always worth doing before anything else: it is how you find out that the file is what you thought it was.

As in the chapter, .values converts the table into a NumPy array, and columns are selected by slicing:

X = df.values
print(X.shape)
print(df.columns.values)      # which column is which
(51, 5)
['temperature [C]' 'density [kg/m^3]' 'Cp [J/g/K]' 'viscosity [Pa*s]'
 'thermal conductivity [W/m/K]']

The five columns are, in order: temperature (°C), density (kg/m³), heat capacity \(C_p\) (J/g/K), viscosity (Pa·s), and thermal conductivity (W/m/K).

Reading NumPy indexing

An array is indexed X[row, column], in that order, and counting starts at zero. So the first column is X[:, 0] and the second is X[:, 1] — which is why density, the second column in the file, is index 1. Off-by-one errors here are the single most common mistake in this problem set.

The colon means “everything along this axis”, so:

  • X[:, 1] is all rows, column 1 — a whole column.

  • X[10, :] is row 10, all columns — a whole row.

  • X[10, 3] is one single number, the value at row 10 and column 3.

Negative indices count backwards from the end, so X[-1, 0] is the last temperature in the table without your needing to know how many rows there are.

To print a number readably, use an f-string: putting f in front of a string lets you drop a variable into it inside braces, and :.4f after the name rounds it to four decimals.

print(f"mean density = {mean_density:.4f} kg/m^3")

Run this once to load the autograder. It will not run inside the book — use the downloaded notebook.

import otter
grader = otter.Notebook()

Part A — Skill Checks (30 pts)#

Three questions, 10 points each. Each asks for a single number.

A1. Load the data and measure it (10 pts)#

Exercise 137

Using the array X created above, find how many rows the dataset has — that is, how many temperatures are tabulated.

X.shape returns the array’s dimensions as (rows, columns), so the number of rows is its first element.

Assign the number of rows to n_rows.

# YOUR CODE HERE
n_rows = ...
grader.check("q1")

A2. Average a column (10 pts)#

Exercise 138

Compute the mean density over all the tabulated temperatures, using np.mean.

Density is the second column, which is index 1, so X[:, 1] selects it — every row, column one.

Assign the result to mean_density. The units are kg/m³.

# YOUR CODE HERE
mean_density = ...
grader.check("q2")

A3. Convert units and check against something you know (10 pts)#

Exercise 139

Viscosity is the fourth column (index 3), and NIST reports it in Pa·s. Chemical engineers more often quote the centipoise, where 1 Pa·s = 1000 cP.

Row index 10 of the table is 20.01 °C. Take the viscosity there and convert it to centipoise.

Assign the result to viscosity_cP.

# YOUR CODE HERE
viscosity_cP = ...
grader.check("q3")

Part B — Visualization (35 pts)#

This is where matplotlib gets introduced properly. The chapter’s pattern is:

fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(x, y, marker='o', ls='none')
ax.set_xlabel('...')
ax.set_ylabel('...')

plt.subplots makes two things at once and hands them back together: a figure (fig), the canvas as a whole, and an axes (ax), the panel with the data on it. Everything after that is a method — a function that belongs to ax and is called by writing a dot after it, in the same way df.head() belonged to the DataFrame. So ax.plot draws on that panel and ax.set_xlabel labels it, and if you had two panels each would take its own commands. Axis limits work the same way, through ax.set_xlim and ax.set_ylim.

marker='o', ls='none' is how you get points with no connecting line. Arguments passed by name like this can be given in any order, and any you leave out fall back to a default.

Exercise 140

  1. Viscosity against temperature. Plot column 3 against column 0, with points rather than a connecting line. Label both axes, including units.

  2. Thermal conductivity against temperature. The same again for column 4, as a second figure.

  3. Zoom in. Redraw the viscosity plot restricted to 0–40 °C using ax.set_xlim, and choose a ax.set_ylim that makes that range fill the axes.

  4. In 3–4 sentences, describe the two curves. Is either one a straight line? Which changes more over the range, and roughly by what factor? Read the factor off your own plot rather than computing it — Part C will do the arithmetic.

An unlabeled axis is the most common way to lose points on a plot, in this course and afterwards. Units belong on both axes of every figure you make from here on.

# YOUR CODE HERE
fig, ax = plt.subplots(figsize=(10, 5))

Part C — Open Ended (35 pts)#

This part asks you to write your first function and your first loop, so here is the shape of each.

A function is defined with def, takes whatever you list in the parentheses, and hands a value back with return. The indented block underneath is the body — indentation is how Python knows where a block starts and stops, so it is not optional. A string on the first line of the body is the docstring, which is where you say what the function does.

def double(x):
    """Return twice x."""
    return 2 * x

A for loop repeats the indented block once for each item in a list, with the loop variable taking each value in turn. zip pairs up two lists so you can walk through both at once — useful when each column index has a name you want to print alongside it.

for j, name in zip([1, 2], ['density', 'Cp']):
    print(j, name)

Exercise 141

Part B suggested that water’s properties are not equally sensitive to temperature. Settle it for all four.

  1. Write a function. Define a function that takes a column index and returns the fractional change in that column from the first row to the last:

    \[ \text{fractional change} \;=\; \frac{v_\text{last} - v_\text{first}}{v_\text{first}} \]

    Give it a docstring saying what it does. X[0, j] is the first row of column j and X[-1, j] is the last.

  2. Apply it to all four property columns (1 through 4) and report the results as percentages. A for loop over the column indices is the natural way; zip is useful if you want to pair each index with a name.

  3. Plot all four together. Divide each property column by its own value in the first row, so every curve starts at 1, and plot all four against temperature on one set of axes. Curves on one axes need a legend: pass label='...' to each ax.plot call and then call ax.legend().

  4. One paragraph. Which property is most sensitive to temperature, and by how much? Pick one of these and say what your numbers imply for it:

    • pumping the water through a pipe, where pressure drop rises with viscosity;

    • heating it in a heat exchanger, where the heat needed depends on \(C_p\);

    • and say whether treating that property as constant over 0–100 °C would be reasonable.

You are not expected to know heat exchanger design. A sensible argument from your own numbers is the whole requirement.

# YOUR CODE HERE

Summary#

  • Part A loaded a real dataset, measured its size, averaged a column and converted units — and every answer was checkable against something already known about water, which is how you catch mistakes before they propagate.

  • Part B introduced matplotlib through the chapter’s pattern: plt.subplots to make a figure and axes, ax.plot to draw, ax.set_xlabel and ax.set_ylabel to label, and ax.set_xlim / ax.set_ylim to zoom.

  • Part C turned an impression from a plot into numbers by writing a function and looping over the columns, and found that water’s viscosity changes by 84% over the liquid range while its heat capacity changes by almost nothing.

Additional Reading#

  1. NIST Chemistry WebBook, Thermophysical Properties of Fluid Systems — the source of this dataset, and a useful reference throughout the course.

  2. The matplotlib gallery — worked examples with source code, the fastest way to find out how to draw something.