In [1]:
%matplotlib notebook
import matplotlib.pyplot as plt
import numpy as np
import sympy as sy
import pandas as pd

PreCalculus with Jupyter and Python

Jacob Frias Koehler, PhD

New York University, The New School, Borough of Manhattan Community College

This talk gives a brief overview of my PreCalculus class this semester. We aimed to utilize the Jupyter notebooks running the Python language as a way to shift curricular content and the nature of student work.

The Traditional PreCalculus Curriculum

Functions and Trigonometry

The example problems below were taken from a large university's recent common PreCalculus final examination. I believe these are representative of typical tasks presented to students in a precalculus setting.

  • The graph of the function $y = f(x)$ is given below. Select the answer choice that represent the graph $y = f(x + 2) - 1$.
  • Find the range of the function $g(x) = -e^{x-a} + b$, where $a$ and $b$ are some positive integers.
  • Find $\cos(2\theta)$ if $\sin(\theta) = \displaystyle -\frac{3}{5}$

A Lagrangian Curriculum

This curriculum tends to focus on classical mathematical techniques involving manipulating polynomials and algebraic approaches to trigonmetric functions. I believe that these concepts are incredibly beautiful and powerful. A student of mathematics and physics could find wonderful insight and power understanding the contextual motivation for work with polynomials that arose in the seventeenth and eighteenth century. Lagrange, for example, offers such an algebraic approach to foundational problems in calculus that dominated the mathematicians at the turn of these centuries. Judith Grabiner details the algebraic heritage of analysis in The Origins of Cauchy's Rigorous Calculus.

"For instance, treating infinite series as if they were polynomials had led to important new results without a general theory of convergence; why then should mathematicians not go on treating infinite series in that way?--Grabiner, 21.

While these algebraic techniques may be important for the mathematician and scientist, the non-STEM major may be better served by alternative content.

Introduce Computing and Applications

Mathematical Modeling, Data, and Matrices

Rather than content focused on algebraic expression and manipulation, I sought alternative concepts that might be able to include the use of Jupyter notebooks and the Python computing language. In doing so, I hoped to introduce problems involving mathematical modeling, the use of real world data, and the array object in the place of polynomial manipulation. We focused on four big ideas in class as mathematical motivators:

  • Polynomial, Exponential, and Trigonometric Functions as models of real world situations and introductions to Python libraries

  • Using real world data to model using idealized functions using for loops, functions, and plotting

  • Fitting models to data with Numpy, Pandas, and scikitlearn

  • Matrices and Applications to Digital Images and Statistics

The Nature of Mathematical Tasks and Doing Mathematics

Poisson is a relic. He speaks of a time where the mathematician and his student were involved in a wholly different relationship. The nature of their interactions were more akin to a master apprentice model with an emerging curriculum having much to do with Poisson's own work. Sensitivity to this difference for me translates to share my interest in using open source computing tools to explore and play with mathematical concepts. Further, I aim to involve my students in more exploratory activities reliant on tool use and creativity.

"Life is good for only two things, discovering mathematics and teaching mathematics." -- Poisson

Mary K. Stein, Margaret Schwan Smith, and Marjorie Hennigsen's work on Mathematical Tasks

Many mathematics educators have engaged with the problem of classifying the nature of high quality mathematical tasks. Stein et al's work on mathematical tasks offers a starting place for considering the nature of high quality mathematical tasks. The rubric below is a summary of some of this work in terms of high quality mathematical tasks that are cognitively demanding. From low level memorization type tasks to high level tasks categorized as doing mathematics we find a continued removal of structure and direction in what these and other authors believe to be highly demanding mathematical work. Some important elements are:

  • Require complex and nonalgorithmic thinking a predictable, well-rehearsed approach or pathway is not explicitly suggested by the task, task instructions, or a worked-out example.

  • Demand self-monitoring or self regulation of one's own cognitive processes

  • Require students to analyze the task and actively examine task constraints that may limit possible solution strategies and solutions

  • Require considerable cognitive effort and may involve some level of anxiety for the student because of the unpredictable nature of the solution process required

Many of the characteristics these writers identify with Doing Mathematics seem inline with problems involving scientific computing in Python. The unpredictability, constant need to navigate prior experience with the tools, and frustrating nature of the tasks are particularly salient.

Starting the Class as Intro to Python and Jupyter

Connecting with the Mathematics Curriculum

The Pulpit Rock
From Leinhardt, Zaslavsky, and Stein(1990) *Functions, Graphs, and Graphing: Tasks, Learning, and Teaching*, Review of Educational Research, 60(1), 1-64.

This semester I began the class with an introduction to basic notebook use that aimed to combine the movement between representations of functions as words, tables, graphs, and equations. I coordinated this with onboarding students to the Jupyter notebook. The idea was to help students generate different representations

Words and Plots: Introducing the Jupyter notebook, markdown, and matplotlib.

Customizing Plots: Advanced customizations in matplotlib through the artist layer.

Section II: Discrete and Continuous Domains

The second section of the course focused on some traditional classes of functions in continuous and discrete form. We discussed situations that closed forms and knowledge about rates of chage provided insight into situations that we could then represent using matplotlib and our knowledge of the notebook from section I. Additionally, we wanted to understand these functions in the guise of recursively defined processes. Here, we were able to introduce the for loop as a tool for generating sequences.


Use the information from the graph above to model two scenarios for paying down debt:

Scenario A: Student A accrued average debt but their parents offered to bail them out in return for an equal payment of \$200 per month until the debt is paid off.

Scenario B: Student B accrued the same debt as Student A, however they will pay a normal credit card interest rate.

A sample solution follows.

a = 4000
N = 20
x = np.zeros(N+1)
x2 = np.zeros(N+1)
for i in range(N):
    x[0] = 5320
    x2[0] = 5320
    x[i+1] = x[i] - 200
    x2[i + 1] = x[i] - 200 + 0.023*x[i]
    print(x[i], x2[i])

A sample plot from a student utilized this framework and tweaked a few values based on additional information they found.

In [7]:
N = 24
x = np.zeros(N+1)
x2 = np.zeros(N+1)
for i in range(N):
    x[0] = 6500
    x2[0] = 6500
    x[i+1] = x[i] - 200
    x2[i + 1] = x[i] - 200 + 0.031*x[i]
plt.plot(x, '--o', color = "Blue",  alpha = 0.8, label = "Situation A")
plt.plot(x2, '--o', color = "Orange", alpha = 0.8, label = "Situation B")
plt.legend(loc = "best")
<matplotlib.text.Text at 0x1204a9f98>

Populations and Ecology

Later, we used these ideas to understand the relationship between problems of modeling biological populations in ecological contexts to the use of recursive sequences and linear, exponential, and quadratic functions. Specifically we examined problems with harvesting and equilibrium models. In the future, I would like to utilize more simulation tools to model the population dynamics in time. The potential for unpacking the mathematics and gathering some data around fishery models is certainly an interest of many students.


Section III: Data, Pandas, and Linear Regression Models

This section focused on fitting linear models to data. We had four primary conceptual aims:

  1. Understand the Method of Least Squares approach to fitting a line to data
  2. Use Python to implement linear regression with numpy.polyfit()
  3. Transform exponential models using logarithms and find lines of best fit
  4. Introduce Linear Regression in a Machine learning context with builtin datasets and scikitlearn

Understanding the mechanics of least squares and minimizing residuals squared is an easy constructive exercise to begin this work.

Further, the ease of plotting and model generation with np.polyfit() made the determination and plotting of lines quite simple. The following code demonstrates this simplicity.

In [3]:
t = [98, 99, 100, 101, 102, 103]
G = [48.0, 51.45, 54.04, 55.94, 60.49, 64.10]
In [5]:
dom2 = np.linspace(98, 104, 1000)
poly = np.polyfit(t, G, 1) #Get the Polynomial where Degree 1 is Linear
y_fit = np.polyval(poly, x ) #Evaluate the Line of Best Fit through larger domain

In the later part of the course, a student returned to these ideas to investigate the Gross Domestic Product in time through World Bank data. He compared the use of matrices in solving regression problems to using np.polyfit().

Section IV: Matrices and Images

In the final section of the class, we focused more on the matrix object and its applications to computer vision and statistics. An excellent example of a recent text demonstrating many of these introductory applications is Tim Chartier's Life is Linear and the accompanying EdX courses.

We aimed to introduce matrices and matrix operations as follows:

  • Matrix Dimension applied to image cropping and pasting

  • Matrix Addition and Scalar multiplication to blend and fade images

  • Matrix Multiplication, Inversion, and Transforms to solve linear regression problems

  • Matrices and Trigonometry to rotate and animate images

These problems were readily solved with Matplotlib and Numpy. Below I demonstrate the sequence of recognizing the connection to arrays and digital images as matrices and a simple crop, mask, and blend. The later problems lent themselves nicely to the use of patches in matplotlib.

One assignment was to go to the Metropolitan Museum of Art and take some picture with their cell phones to mess with. I use some images from the wonderful Picturing Math exhibit.

In [1]:
%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import as cm
import matplotlib.image as mpimg
In [2]:
geom = mpimg.imread('geometria.jpg')
In [11]:
array([[[240, 237, 228],
        [242, 242, 232],
        [241, 243, 230],
        [241, 238, 229],
        [241, 238, 229],
        [241, 238, 229]],

       [[244, 240, 231],
        [240, 240, 230],
        [238, 240, 229],
        [240, 237, 228],
        [240, 237, 228],
        [240, 237, 228]],

       [[245, 238, 230],
        [238, 235, 226],
        [235, 235, 225],
        [240, 237, 228],
        [240, 237, 228],
        [240, 237, 228]],

       [[241, 238, 229],
        [241, 238, 229],
        [241, 239, 227],
        [239, 236, 227],
        [239, 236, 227],
        [240, 237, 228]],

       [[242, 239, 230],
        [242, 239, 230],
        [242, 240, 228],
        [240, 237, 228],
        [240, 237, 228],
        [240, 237, 228]],

       [[243, 240, 231],
        [243, 240, 231],
        [242, 240, 228],
        [241, 238, 229],
        [241, 238, 229],
        [241, 238, 229]]], dtype=uint8)
In [12]:
plt.title("Geometria XXIIII, from E-Series Tarocchi Cards")
<matplotlib.text.Text at 0x115da6dd8>
In [20]:
lum_geom = geom[:,:,2]
plt.title("Geometria XXIIII, from E-Series Tarocchi Cards")
<matplotlib.text.Text at 0x1183c8940>
In [51]:
cropped = geom[0:150, 0:100]
In [52]:
<matplotlib.image.AxesImage at 0x11ad656d8>
In [44]:
mangrid = mpimg.imread("mangrid.jpg")
In [55]:
mangrid_crop = mangrid[150:300, 100:200]
In [56]:
blended = mangrid_crop + cropped
blended = blended[:,:,2]
In [57]:
plt.imshow(blended, cmap = 'hot')