Week 2: Introduction to Python, Data Visualization, Sampling/Aliasing#

Laboratory 1
Last updated Aug 29, 2023

00. Content #

Mathematics

  • Functions

  • Sampling

  • Aliasing

Programming Skills

  • Importing libraries

  • Importing files

  • NumPy Python library

  • Matplotlib Python library

  • Functions

  • Variables values, types and basic operations

  • Lists and arrays

  • Line plot, title, axes labels

  • For loops

Embedded Systems

  • N/A

0. Required Hardware #

  • N/A

Write your name and email below:

First Name, Last Name, Email

1. About Python and Jupyter #

Python is a programming language with a simple, easy to learn, and easy to read syntax. It is a free and open source software that includes many handy libraries for doing mathematics. The labs in this course use Python 3.

The document you are reading is a “Jupyter” file called a “Jupyter notebook.” Jupyter (formerly IPython) is a system that allows you to embed Python code within a web document. Jupyter is called a “REPL” system. REPL stands for “Read, Evaluate, Print, Loop.” In concrete terms, this means that Jupyter files are executed piece-by-piece. Each piece is put in a box. The user executes a box by pressing shift-enter. The output is returned to the user right below the box. This makes Jupyter notebooks interactive.

2. Python Libraries #

In this lab, two Python libraries will be heavily used, NumPy and Matplotlib.

NumPy supports multi-dimensional arrays and matrices, and provides numerous mathematical functions to be operated on these arrays and matrices.

Matplotlib is a plotting library, and in this lab, we will be mainly using matplotlib.pyplot, which provides a MATLAB-like way of plotting. You can refer to Pyplot Tutorial for more detailed instructions.

These libraries need to be imported before one can access the attributes and functions within these libraries. Let’s import these libraries. For simplicity, we will rename numpy as “np” and matplotlib.pyplot as “plt”. This is a common convention. Execute the following blocks by pressing (shift-enter) after clicking on the gray box of code below.

import numpy as np
import matplotlib.pyplot as plt

Notice that the modules were imported using the syntax \(\mathtt{\quad import\quad [module\_name] \quad as \quad [alias]}\). We used the alias “np” for numpy, and “plt” for matplotlib.pyplot. This means that, from now on, we can simply type “np” in place of numpy, and “plt” in place of matplotlib.pyplot.

Note that np and plt are the conventional aliases of NumPy and matplotlib.pyplot, respectively, and we will be following the conventions throughout this and the remaining labs.

In addition, we will need some functions that have been defined specifically for this lab. These are written inside a python file called lab1.py, which you can download by pressing shift+enter to execute the following block.

%%sh
wget -qN https://raw.githubusercontent.com/TheDataScienceLabs/DSLab_Calculus/main/book/labs/1_intro_to_notebooks/lab1.py

Now, let’s import the library we just downloaded. We will also need functions from the math library for this lab, so lets import that too

import math
import lab1 as lab1

Throughout the course of these labs, you’ll be given files which, like lab1.py, contain certain functions that you will need to complete the experiments. You should not need to edit the files, you will only be asked to import their functions and use them based on a specific syntax that will be given to you.

Please execute the following block of code. This will set some parameters for the plots you will produce below. It will also automatically reload all external modules. This will prevent you from having to reload lab1.py every time you use it.

# make sure the plot is displayed in this notebook
%matplotlib inline
# specify the size of the plot
plt.rcParams['figure.figsize'] = (16, 6)

# for auto-reloading external modules
%load_ext autoreload
%autoreload 2

3. Functions #

Functions are groups of code that always run together. When you call a function, you execute the code that is associated within that function. Functions can take inputs, manipulate the inputs, and return an output.

The file lab1.py contains a function named pyramid. The function simply takes an integer value x, displays a half pyramid of # symbols with x rows (using the value of x given), and returns the total number of #s in the half pyramid. In this case, the returned value is stored in a variable named k. In the example below, we inputted the value 4 into the function, created a half pyramid with the input value k=4 as the number of rows, and returned the resulting number of # symbols in the half pyramid.

You can view the content of the function pyramid by opening the lab1.py file. Take a look at it!

Now let’s evaluate the function pyramid and print the result.

k = lab1.pyramid(4)
print("The number of #s in the half pyramid is {}.".format(k))

Exercise 1 #

Question 1: What would the expected value of m be if the following code was given? How many #s would be on the 5th row?

m = lab1.pyramid(7)

Question 2: Use the pyramid function to build a half-pyramid with 10 rows and compute the number of # symbols in the half pyramid.

Write Answers for Exercise 1 Question 1 Below

Write your answer here

Write Answers for Exercise 1 Question 2 Below

# Write your answer here 

Basic Operations#

Python 3 provides basic types including integers, floats, strings, and booleans. We can assign a value of any of these types to a variable.

For instance, if we want the variable called \(\mathtt{a}\) to hold the value of 5. This is referred to as initializing a variable with a value.

We can also use a function called \(\mathtt{print()}\) to print out a specified input.

a = 5                        # initialize a with the value of 5
print(a)                     # print out the value of a            

Basic operations like adding, subtracting, multiplying, and dividing can be used to manipulate these variables and/or values.

a = 5                         # initialize a with the value of 5
b = a + 10                    # assign a + 10 to b
c = a - 5                     # subtract a by 5
d = b * 4                     # multiply b by 4
e = 50 / a                    # divide 50 by a
f = b // 7                    # integer division, result is the division without the succeeding numbers after the decimal
g = a ** 2                    # a to the power of 2
h = (d + 3) ** 0.5            # add 3 to d and take it to the 0.5 power (that's a square root!)
i = f == 2                    # return True if f is 2, otherwise return False 
j = d % 13                    # d modulo 13, result is the remainder

print(a)
print(b)
print(c)
print(d)
print(e)
print(f)
print(g)
print(h)
print(i)
print(j)

Most of these operations are probably familiar to you, though the last two are typically only used in computing.

== tests if the term to its right has the same value as the term to its left. If they are the same, it gives the value True and if they are different it gives the value False.

% is the “modulo” function, which gives the remainder after division. For example, since 14/4 is three with a remainder of 2, the expression 14%4 gives the value 2.

Try some other operations on your own! For example, try printing the roots of \(ax^2+bx+c\) using the quadratic formula and some specified values for \(a,b\) and \(c\). This portion is a sandbox, and is not graded. Just play around a bit! Remember that you can do a square root by raising a number to the power 0.5.

Sandbox

# Sandbox

Exercise 2 #

Part 1

Code the following operations.

  1. Initialize the variable xyz to the value 9.

  2. Take the third power of xyz and store it in a new variable called abc.

  3. Create another variable called okay and copy the value of xyz to it.

  4. Multiply okay by 14 and store it in okay.

  5. Take the remainder of okay / 5 and store it in rem.

  6. Add together okay, xyz, rem, and abc and store it in a variable called sum.

  7. Print the value of sum.

Part 2

Answer the following questions.

Question 1: What is 8 % 9?
Question 2: What operation would help you decide whether a given number is even or odd?

Write Answers for Exercise 2 Part 1 Below

You may create additional boxes as needed by clicking the "+" sign in the menu above this window or by hovering your mouse at the bottom of a cell. This will create a box of code, by default. If you want to switch it to a box of Markdown, in order to write text, then select "Markdown" from the dropdown menu above this window.

Write your ansewr here

Write Answers for Exercise 2 Part 2 Below

Write your answer here

4. Formatting #

A variable can also be initialized by a string. A string can also be formatted for output. When formatting a string, the \(\mathtt{format()}\) function replaces \(\mathtt{\{\}}\) with its specified inputs.

j = "Hello World!"                             # assign j to a string
str1 = "The value of j is {}".format(j)
str2 = "The values of f and g are {} and {}, respectively.".format(f, g)
str3 = "The value of h is {:.3f}.".format(h)   # formats the value of h to be rounded to 3 decimal places
print("Data Science is cool!")
print(str1)
print(str2)
print(str3)

Exercise 3 #

When you analyzed the code in lab1.py earlier, you would have noticed that there are three additional functions in the file. Follow the instructions below to see what the mystery function does.

Part 1

Code the following operations.

  1. Call the mystery function from the file like we did earlier. The mystery function takes an integer as an input and returns an integer as an output. Assign the input to the value 7 and the output of the function to a variable named num.

  2. Manipulate the value of num in one line of code by first adding 51, then dividing that value by 7, and multiplying that value by 3. Assign this new number to the variable new_num. Don’t forget to use parentheses when appropriate.

  3. Print the value of num to 2 decimal places and the value of new_num to the 5th decimal. Follow the output of "The value of num is ___ and the value of new_num is ___.".

Part 2

Describe what the mystery function outputted. How did the value we inputted into the function get manipulated?

Write Answers for Exercise 3 Part 1 Below

# Write your answer here

Write Answers for Exercise 3 Part 2 Below

Write your ansewr here

5. For Loops #

For loops help us iterate through a range of values or lists. These will be very helpful in analyzing data in future labs.

To help us understand for loops we will use a function called \(\mathtt{range()}\). This function creates a sequence of values given a set of numbers as its inputs. \(\mathtt{range(i, j, k)}\) where i is the closed interval start value, j is the open interval end value, and k is the stepping size.

for i in range(5):           # i begins from 0 as default, and ends at 4 (not 5). Interval of sequence is [0, 5) 
  print(i)
print("------------")
for j in range(13, 17, 1):   # j begins from 13 and increments by 1 until 16 (not 17). Interval of sequence is [13,17)
  print(j)
print("------------")
for k in range(0, 10, 2):    # k begins from 0 and increments by 2 until 8 (not 10). Interval of sequence is [0, 10)
  print(k)
print("------------")
for z in range(45, 40, -1):  # z begins from 45 and decrements by 1 until 41 (not 40). Interval of sequence is (40, 45]
  print(z)

Exercise 4 #

What would you expect the sequences for the following range() functions be?

Question 1: range(2, 14, 1)
Question 2: range(14, 2, -6)
Question 3: range(11)
Question 4: range(7, 15)

Write Answers for Exercise 4 Below

Write your answer here

6. Lists #

Lists are used to store multiple items in a single variable.

Lists are indexed by starting with 0. So, an element at index 0 of a list is the first element of the list, index 1 is the second element, index 2 is the third element,… and so on until the end of list.

Examples of some lists are shown below.

For accessing sections of the list, we can splice the list by indexing. Essentially, we are obtaining a sublist. The basic slicing syntax is list[i:j:k], where i is the starting index, j is the stopping index, and k is the step. If the starting index is \(\mathtt{0}\), it can be ignored. If the ending index is the length of the list, you can ignore it. If the step size is \(\mathtt{1}\), it can also be ignored. The indexing interval rules are similar to that of the \(\mathtt{range()}\) we had done earlier.

thislist = ["mango", "strawberry", "peach", "plum", "orange"]   # initialize thislist with strings
print(thislist[0])                                              # value of thislist at index 0 (first element)
print(thislist[2])                                              # value of thislist at index 2 (third element)
print(thislist[-1])                                             # 1st element from the end of list                      
print(thislist[-3])                                             # 3rd element from the end of list
sublist = thislist[1:4:2]                                       # sublist of every other element starting from index 1 to 3 
print(sublist)                                          
print(thislist[:3:1])                                           # sublist from index 0 to 2
print(thislist[3::1])                                           # sublist from index 3 to end of list
print(thislist[1:4])                                            # sublist from index 1 to 3

nextlist = [2, 4, 5, 7, 9]                                      # initialize nextlist with integers
num = 0
for m in nextlist:                                              # iterate through all the elements of nextlist
  num = num + m                                                 # sum all the elements of list together
  print(m)                                                      # print the current values of nextlist
print("The sum of the values of nextlist is stored in 'num' which is {}.".format(num))

When coding, there are “good practices” that people tend to follow. This includes naming conventions. In the case of lists, it’s good practice to not name them “list.” This is because it can mess up the program and cause it to get confused, especially if there’s more than one being used. This goes for other similar structures, such as arrays (“array”), variable types (integer “int,” string “string,” etc.), and really anything else that you can think of.

Remember to follow implement these good practices throughout this course and any other time you’re coding!

Exercise 5 #

Follow the instructions below:

Part 1

  • Initialize a list of integers with the values of 10, 45, 6, 90, 5, 87, 56.

  • Calculate the average of this list using a for loop.

  • Print the average. Format the average and have it rounded to the 2nd decimal point.

Part 2

  • Create a sublist of list that includes every other element starting from index 0, including the last element.

  • Print this sublist.

Part 3

  • Create a for loop that prints out the odd numbers between 1 and 21, including 1 and not including 21.

Part 4

  • Create a for loop that prints out the values 36, 29, 22, 15, 8 in this order.

Write Answers for Exercise 5 Part 1 Below

# Write your answer here

Write Answers for Exercise 5 Part 2 Below

# Write your answer here

Write Answers for Exercise 5 Part 3 Below

# Write your answer here

Write Answers for Exercise 5 Part 4 Below

# Write your answer here

7. Matplotlib Interface #

So now that we know how to create lists. We can now use these lists to create graphs.

Earlier, we imported the Matplotlib library using the instructive, import matplotlib.pyplot as plt. Matplotlib is a low level graph plotting library. You will notice that matplotlib has an extension to it, pyplot. pyplot is a submodule of matplotlib that will help us plot our graphs.

Let’s look at how this can be done.

Often when we have a graph, we will have a set of x coordinates and a set of y coordinates. In this case, we are going to define x and y as lists. These lists have to be of equal length, and each coordinate value corresponds to the same indices. For instance, in the example below, the coordinates that will be graphed are (1,1), (2,2), (3,3), (4,4), (5,5), (6,6), and (7,7). When using the plt.plot() function, a line graph will be drawn. Remember that in future labs, you should be more descriptive in your variable names when describing the dependent and independent variables of a data set that you are plotting.

x = [1, 2, 3, 4, 5, 6, 7]                               # x coordinate list
y = [1, 2, 3, 4, 5, 6, 7]                               # y coordinate list

plt.plot(x, y)                                          # plots x by y
plt.title("X vs. Y")                                    # adds a title
plt.xlabel("X")                                         # adds a label on the x axis
plt.ylabel("Y")                                         # adds a label on the y axis
plt.show()                                              # displays the graph as an output

As default, plt.plot() graphs a line graph. However, you can change this graph to a scatter plot. We can do this by adding an additional input to the function, 'ro'. Let’s do this.

plt.plot(x, y, 'ro')                                    # plots x by y as a scatter plot
plt.show()                                              # displays the graph as an output

You will have noticed that the graph is now a scatter plot, but additionally, the markers are red in color. The first character signifies the color of the marker. In this case, r is red. And the second character signifies the shape of the marker. o gave us circle markers. Now that we can change the color and shape of the markers, we can add more data to our graphs. You can look here for different marker types and colors Matplotlib markers.

x = [1, 2, 3, 4, 5, 6, 7]                               # x coordinate list
y1 = [1, 2, 3, 4, 5, 6, 7]                              # y1 coordinate list
y2 = [2, 2.5, 3, 3.5, 4, 4.5, 5]                        # y2 coordinate list
y3 = [3, 3.75, 4.5, 5.25, 6, 6.75, 7.5]                 # y3 coordinate list

plt.plot(x, y1, 'ro', x, y2, 'b^', x, y3, 'g-')         # plots x by y as a scatter plot and a line graph
plt.legend(['y1', 'y2', 'y3'], loc="lower right")       # legend, in lower right position
plt.title("X vs. Y")                                    # adds a title
plt.xlabel("X")                                         # adds a label on the x axis
plt.ylabel("Y")                                         # adds a label on the y axis
plt.show()                                              # displays the graph as an output

Exercise 6 #

Part 1

Do the following exercises below to implement plotting using matplotlib.

  1. Create a list called x1 with the following values: 1, 1.5, 2, 2.5, 3, 2.5, 2, 1.5, 1.

  2. Create a list called x2 with the following values: 1.625, 1.625, 1.75, 1.75, 1.625.

  3. Create a list called x3 with the following values: 2.25, 2.25, 2.375, 2.375, 2.25.

  4. Create a list called x4 with the following values: 1.5, 2.5, 2.375, 1.625, 1.5.

  5. Create a list called y1 with the following values: 2, 2.5, 3, 2.5, 2, 1.5, 1, 1.5, 2.

  6. Create a list called y2 with the following values: 2.5, 2.25, 2.25, 2.5, 2.5.

  7. Create a list called y3 with the following values: 1.75, 1.75, 1.5, 1.5, 1.75.

  8. On the same graph, plot x1 by y1 as a solid yellow line, and x2 by y2, x3 by y2, and x4 by y3 as solid black lines. Hint: You can use the link about markers to find the appropriate colors and marker shapes.

  9. Make sure to show the plot as an output.

Follow the coordinates for the x1 by y1 plot. Notice that the values are drawn and connected in the order they show up in the list from left to right. Essentially, all we are doing is connecting the dots when drawing these graphs.

Part 2 (OPTIONAL)

Now that you know how to plot on matplotlib, In a similar manner as in Part 1, in a new block of code, draw your first initial in block letters. Make your output a line that is not solid and a color that we have not used already.

Write Answers for Exercise 6 Part 1 Below

# Write your answer here

Write Answers for Exercise 6 Part 2 Below (Optional)

# Write your answer here

8. NumPy Arrays #

Arrays are very similar to lists. To build one-dimensional arrays we use the NumPy library that we had imported earlier: import numpy as np. To create an array, we can use the following code.

A = np.array([5, 3, 6, 8, 2, 1])     # initialize A with array [5, 3, 6, 8, 2, 1]
print("A = {}.".format(A))

You can also create arrays by using functions like arange(), zeros(), linspace().

arange() - creates an array between a range of values, similar to range()
zeros() - creates an array of zeros
linspace() - creates an array of linearly spaced values

A1 = np.arange(2, 10, 4)    # (start, stop, stepping size)
A2 = np.zeros(4)            # number of elements            
A3 = np.linspace(2, 10, 4)  # (start, stop, number of elements)

print("A1 =", A1)
print("A2 =", A2)
print("A3 =", A3)

We can find the length of the array by using the len() function.

length = len(A1)
print("The length of the array is {}.".format(length))

The indexing rules for an array are the same rules that we had used earlier for lists. Similar to lists, we can create subarrays with index manipulation. Here are some examples to corroborate this.

print(A[3])                         # 4th element in A, index 3
print(A[-3])                        # 3rd to last element in A, index 3 
print(A[1:5:1])                     # index 1-4
print(A[4:0:-2])                    # index 4, 2
v = A[3::1]
print("v =", v)                     # index 3, 4, 5

Why are we learning arrays when the same thing can be done with lists?

Arrays using NumPy are easier to manipulate. NumPy also includes additional functions for array manipulation.

It is also possible to use basic operations on an entire array. This is like evaluating functions at several points at once. This is easier than creating for loops.

V = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
V1 = V * 11                                           # y = x * 11
V2 = V ** 2                                           # y = x ^ 2
V3 = V == 5                                           
print("V multiplied by 11: {}".format(V1))
print("V squared: {}".format(V2))
print("Elements of V that equal 5: {}.".format(V3))

The addition with lists is different than addition with arrays.

Let’s test this.

list1 = [4, 6, 8]
list2 = [1, 3, 7]
array1 = np.array([4, 6, 8])
array2 = np.array([1, 3, 7])

list3 = list1 + list2
array3 = array1 + array2

print("Lists create join lists together called concatenation.")
print("The value of list3 is {}.".format(list3))
print("Arrays add the each corresponding elements together.")
print("The value of array3 is {}.".format(array3))

Try some other basic operations on arrays. What happens when you subtract arrays? When you divide an array by a scalar? When you multiply two arrays?

Sandbox

# Sandbox

Exercise 7 #

Part 1

The equation for calculating kinetic energy is given by

\[\begin{align*} KE = \frac{mv^2}{2} \end{align*}\]

where
KE is kinetic energy (J)
m is mass (kg),
v is velocity (m/s)

Given that an object has a mass of 20 kg, how much kinetic energy does this object have at the given velocities between the interval [0, 7] using 8 linearly-spaced points.

  1. Use a NumPy array to calculate the kinetic energy at the different velocities.

  2. Create a scatterplot plotting Velocity (m/s) by Kinetic Energy (J). Make sure to include an appropriate title and axes labels.

Part 2

In Exercise 5, we used lists to find and print the average of 10, 45, 6, 90, 5, 87, 56. Now, let’s use an array to find the average. Use this link NumPy Math Functions to find a function that may help you. You must use array notation, and do not use the average() function. Hint: think about what you need to do to find the average of a set of numbers step-by-step and see what function fits each step, if possible.

Part 3 (OPTIONAL)

Question 1: What kind of relationship do the variables have? Linear? Quadratic? Cubic? Exponential?

Question 2: Using your graph that you made, estimate what the kinetic energy of the object is when it is moving at a speed of 4.5 m/s.

Write Answers for Exercise 7 Part 1 Below

# Write your answer here

Write Answers for Exercise 7 Part 2 Below

Write your answer here

Write Answers for Exercise 7 Part 3 Below (Optional)

Write your answer here

9. Function Visualizations #

In Exercise 7, Part 1 we learned how to discretize an interval of a function using NumPy operations.

Let’s look at how the number of points we choose within an interval affects the output of a function. In this example, we are going to look at \(\mathtt{sin(x)}\) by dividing the interval [0, 2pi] into 5, 10, and 50 points.

t5 = np.linspace(0, 2 * math.pi, 5)                          # 5 linearly-spaced elements within the interval of [0, 2pi]
sin5 = np.sin(t5)                                            # Map these 5 points to sin(x)
t10 = np.linspace(0, 2 * math.pi, 10)                        # 10 linearly-spaced elements within the interval of [0, 2pi]
sin10 = np.sin(t10)                                          # Map these 10 points to sin(x) 
t50 = np.linspace(0, 2 * math.pi, 50)                        # 50 linearly-spaced elements within the interval of [0, 2pi]
sin50 = np.sin(t50)                                          # Map these 50 points to sin(x)

# Graph for 5 points
plt.plot(t5, sin5, 'r-')
plt.title("sin(x) discretized at 5 points")
plt.xlabel("x")
plt.ylabel("y")
plt.show()
# Graph for 10 points
plt.plot(t10, sin10, 'g-')
plt.title("sin(x) discretized at 10 points")
plt.xlabel("x")
plt.ylabel("y")
plt.show()
# Graph for 50 points
plt.plot(t50, sin50, 'b-')
plt.title("sin(x) discretized at 50 points")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

Through this, we can see that choosing a valid number of points to graph a function is very important.

For the next example, we are going to analyze how an ordered x-coordinate list differs from an unordered list. Run the following code.

x1 = np.array([1, 2, 3, 4, 5, 6, 7])       # Ordered
x2 = np.array([3, 4, 6, 7, 2, 1, 5])       # Unordered

# y = x ^3
y1 = x1 ** 3
y2 = x2 ** 3

# Ordered Graph
plt.plot(x1, y1, 'm-')
plt.title("Ordered x-coordinates")
plt.xlabel("x")
plt.ylabel("y")
plt.show()
# Unordered Graph
plt.plot(x2, y2, "c-")
plt.title("Unordered x-coordinates")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

Now let’s graph the same plots, but instead of a line graph, let’s use a scatter plot.

# Ordered Graph
plt.plot(x1, y1, 'mo')
plt.title("Ordered x-coordinates")
plt.xlabel("x")
plt.ylabel("y")
plt.show()
# Unordered Graph
plt.plot(x2, y2, "co")
plt.title("Unordered x-coordinates")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

Exercise 8 #

Part 1

Consider the function \(y = \sin(100 x)\).

  1. What is the period of the function?

  2. What is the frequency of the function?

  3. If we graph this function on the interval \([0, \pi]\), how many oscillations will we see? Describe in words how you expect the plot to look.

  4. Run the cell below, which creates a graph of the equation between the interval [\(\mathtt{0, \pi}\)].

  5. Does the graph match what you expected it to be? Why or why not?

In the next part we will explore what went wrong here.

x = np.linspace(0, np.pi)
y = np.sin(100*x)
plt.plot(x, y)
plt.show()

Write Answers for Exercise 8 Part 1 Below

Write your answer here

Part 2

To better understand what went wrong in Part 2, let’s zoom in on just the first tenth of the graph. We can do this without changing the plot in any other way, simply by changing the x limits. In order to see exactly which points are shown, let’s make this a scatter plot as well.

plt.plot(x, y, 'o')
plt.xlim(0, np.pi/10)
plt.show()

Now we see that there are only five points being drawn in the first tenth of the interval! We expect there to be ten oscillations here, so that just is not enough. Let’s make an additional plot on top of this one, but sampling at way more points. In the following cell, assign a number to number_of_samples. Start with 200, and increase it until the graph shows a smooth, sinusoidal shape.

number_of_samples = # You need to fill this in.
x_detailed = np.linspace(0, np.pi, number_of_samples)
y_detailed = np.sin(100 * x_detailed)

plt.plot(x, y, 'o')
plt.plot(x_detailed, y_detailed)
plt.xlim(0, np.pi/10)
plt.show()

Now we can see what was going on: the points are coming from the correct function, but they are being sampled in a way which gives a misleading picture. Let’s see the same plot, but zoomed out to show the whole interval.

plt.plot(x, y, 'o')
plt.plot(x_detailed, y_detailed)
plt.show()

This phenomenon is called aliasing. There are actually lots of things called aliasing; it means a different thing in computer programming, and a different thing in radio engineering. This is what aliasing means in computer graphics and signal processing: if you sample a periodic function at too low a frequency, you can get a very misleading effect. You have to be careful to avoid this, by always ensuring that you have a high enough number of samples.

Now answer the following question.

  1. We did not specify how many samples to take in our initial plot. Why were there only five points in our zoomed-in plot? Hint: look up the function linspace in the official NumPy documentation here: https://numpy.org/doc/stable/

Write Answers for Exercise 8 Part 2 Below

Write your answer here