{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python for Signal Processing\n", "Danilo Greco, PhD - danilo.greco@uniparthenope.it - University of Naples Parthenope" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lecture 3\n", "This lecture will provide an overview on Numpy mathematical library:\n", "\n", "1. installation, \n", "2. documentation, \n", "3. main functions and applications,\n", "4. practical examples." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### What is Numpy?\n", "[Numpy](https://numpy.org/) is a fundamental library for scientific computing in Python.\n", "\n", "It provides multidimensional array objects and an assortment of routines for fast operations on arrays, including \n", "\n", "* mathematical, \n", "* logical, \n", "* shape manipulation, \n", "* sorting, \n", "* selecting, \n", "* I/O, \n", "* discrete Fourier transforms, \n", "* basic linear algebra, \n", "* basic statistical operations, \n", "* random simulation \n", "\n", "and much more.\n", "\n", "Numpy is based on the ndarray object which encapsulates n-dimensional arrays of homogeneous data types.\n", "\n", "#### Differences from Python lists\n", "* ndarrays have fixed size, unlike lists which can grow dynamically\n", "* ndarrays require elements of the same data type, unless for arrays of objects where each object can be different\n", "* efficient execution of operations on large numbers of data\n", "* lots of python packages rely on ndarrays rather than lists\n", "* element-wise operations on ndarrays are faster than iterating over the list elements, thus avoiding useless loops\n", "\n", "The implicit element-by-element behavior of operations in numpy is termed [broadcasting](https://numpy.org/doc/stable/user/basics.broadcasting.html#module-numpy.doc.broadcasting)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Install\n", "It can be installed by executing the following command:\n", "\n", ">pip install numpy \n", "\n", "or \n", "\n", ">python -m pip install numpy\n", "\n", "#### NOTE: when installing with python version 3.x, replace pip or python with pip3 or python3 in the commands above.\n", "\n", "Alternative installation can be done by installing many other [scientific libraries](https://numpy.org/) that require numpy, such as [Scipy](https://scipy.org/), so that it get implicitly installed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Documentation\n", "The official numpy documentation is available on numpy [website](https://numpy.org/doc/stable/) and provides an extensive guide for both users and developers, including setup and absolute beginners tutorials.\n", "\n", "There is also an interesting book explaining how to use numpy for data analysis:\n", ">Wes McKinney, Python for Data Analysis: Data Wrangling with Pandas, NumPy, and IPython, O'Reilly Media\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Main functions and applications\n", "The first thing to do is inform the python interpreter that we are using the package. The following command tells python to import the library and use an alias for quicker references within our code:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An array is a grid of values and it contains information about the raw data, how to locate an element, and how to interpret an element. All elements have the same data type named dtype.\n", "\n", "An array can be created starting from lists or nested lists and its elements are located by a positional index starting at zero:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = np.array([1,2,3,4,5]) # from a list\n", "print(a[2])\n", "\n", "m = np.array([[1,2,3],[4,5,6],[7,8,9]]) # from a nested list\n", "print(m[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other ways for creating arrays make use of the following functions:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# create an array with all zeroes\n", "np.zeros(3) # specifying the number of elements in the array" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# create an array with all ones\n", "np.ones((2,3)) # passing the desired shape, that is a tuple with rows and columns for the array" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# create an empty array \n", "np.empty(3) # values in the array may vary" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# create an array with incremental values\n", "a = np.arange(5)\n", "print(a)\n", "# specify start, stop and step size\n", "np.arange(0.2, 1.0, 0.2)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0. , 2.5, 5. , 7.5, 10. ])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# create arrays of equally spaced values\n", "# requires start, stop and count\n", "np.linspace(0, 10, num=5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sorting the values of an array is pretty simple by using:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1 2 2 3 4]\n" ] } ], "source": [ "a = np.array([3,4,2,1,2])\n", "print(np.sort(a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and it's also possibile to obtain the sorted position of initial elements:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([3, 2, 4, 0, 1], dtype=int64)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.argsort(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To inquire the position of a searched element in an array, we can use:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[2],\n", " [4]], dtype=int64)" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.argwhere(a==2)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [3, 4],\n", " [5, 6],\n", " [7, 8]])" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([[1, 2],[3, 4]])\n", "b = np.array([[5, 6],[7, 8]])\n", "\n", "# concatenate arrays by rows\n", "np.concatenate((a, b),axis=0)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1 2 5 6]\n", " [3 4 7 8]]\n" ] } ], "source": [ "# concatenate arrays by columns\n", "c = np.concatenate((a, b),axis=1)\n", "print(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To inquire information on arrays, we can use the following:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Dimensions: 2, Total size: 8 elements, Shape: (2, 4)\n" ] } ], "source": [ "print(\"Dimensions: {}, Total size: {} elements, Shape: {}\".format(c.ndim,c.size,c.shape))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Arrays can also be reshaped in a very simple way:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [5, 6],\n", " [3, 4],\n", " [7, 8]])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.reshape((4,2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Note that these commands do not alter the original arrays: if you want to keep the transformation you must assign it to a variable" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1 2 5 6]\n", " [3 4 7 8]]\n", "[[1 2]\n", " [5 6]\n", " [3 4]\n", " [7 8]]\n" ] } ], "source": [ "d = c.reshape((4,2))\n", "print(c)\n", "print(d)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1 2 5 6]\n", "[2 6 4 8]\n" ] } ], "source": [ "print(c[0]) # displays row 0 of array\n", "print(d[:,1]) # displays all elements of column 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is possible to transform a 1D array into a 2D array:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([3, 4, 1, 2])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([3,4,1,2])\n", "a" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[3 4 1 2]]\n", "(1, 4)\n" ] } ], "source": [ "a_row = a[np.newaxis,:]\n", "print(a_row)\n", "print(a_row.shape)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[3]\n", " [4]\n", " [1]\n", " [2]]\n", "(4, 1)\n" ] } ], "source": [ "a_col = a[:,np.newaxis]\n", "print(a_col)\n", "print(a_col.shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Indexing and slicing with numpy arrays is the same as python lists:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[3 4 1 2]\n", "a[1]= 4\n", "a[1:3]= [4 1]\n", "a[-2:]= [1 2]\n" ] } ], "source": [ "print(a)\n", "print(\"a[1]= {}\".format(a[1]))\n", "print(\"a[1:3]= {}\".format(a[1:3]))\n", "print(\"a[-2:]= {}\".format(a[-2:]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Selection of elements that fulfill a given condition can be done as follows:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0 1 2 3 4 5 6 7]\n", "[0 1 2 3]\n", "[ True True True True False False False False]\n", "[0 2 4 6]\n", "[ True False True False True False True False]\n" ] } ], "source": [ "a = np.arange(8)\n", "print(a)\n", "\n", "print(a[a < 4]) # print all elements lower than 4\n", "print(a<4)\n", "print(a[a%2 == 0]) # print all elements divisible by two\n", "print(a%2 == 0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Multiple conditions can be specified with the logical operators & and |:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0 2]\n", "[0 1 2 3 4 6]\n" ] } ], "source": [ "print(a[(a < 4) & (a%2 == 0)])\n", "print(a[(a < 4) | (a%2 == 0)])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The conditions specified within the square brackets generate a boolean mask that is used when indexing the array:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mask = (a < 4) & (a%2 == 0)\n", "print(mask)\n", "print(a[mask])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Element-by-element operations are the default behavior for ndarrays:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(c)\n", "print(c[0]+c[1])\n", "print(c[0]-c[1])\n", "print(c[0]*c[1])\n", "print(c[0]/c[1])\n", "\n", "# we can multiply a vector by a scalar\n", "print(1.6*c[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can sum the elements or find maximum or minimum values of an array by rows or by columns depending on the axis parameter:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "c.sum(axis=0) # sum the rows in each column" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "c.sum(axis=1) # sum the columns in each row" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "c.min(axis=0) # find the minimum on each column " ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([6, 8])" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.max(axis=1) # find the maximum on each row" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "whereas if no axis is specified the result is across the whole array:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "36" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.sum()" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(8, 1)" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.max(),c.min()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Operator * performs element-wise vector product, whereas matrix multiplication can be computer with the @ operator, as of:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "m1 =\n", "[[3 1]\n", " [8 2]]\n", "m2 =\n", "[[6 1]\n", " [7 9]]\n", "[[18 1]\n", " [56 18]]\n", "[[25 12]\n", " [62 26]]\n" ] } ], "source": [ "m1 = np.array([[3,1],\n", " [8,2]])\n", "m2 = np.array([[6,1],\n", " [7,9]])\n", "print('m1 =')\n", "print(m1)\n", "print('m2 =')\n", "print(m2)\n", "print(m1 * m2)\n", "print(m1 @ m2)" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: total: 0 ns\n", "Wall time: 0 ns\n" ] }, { "data": { "text/plain": [ "array([[25, 12],\n", " [62, 26]])" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time \n", "m1 @ m2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's see how all elements of m1 @ m2 are calculated:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "25\n", "62\n", "12\n", "26\n" ] } ], "source": [ "print(np.dot(m1[0,:],m2[:,0]))\n", "print(np.dot(m1[1,:],m2[:,0]))\n", "print(np.dot(m1[0,:],m2[:,1]))\n", "print(np.dot(m1[1,:],m2[:,1]))" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: total: 0 ns\n", "Wall time: 0 ns\n" ] }, { "data": { "text/plain": [ "array([[25, 12],\n", " [62, 26]])" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", "np.array([[np.dot(m1[0,:],m2[:,0]),np.dot(m1[0,:],m2[:,1])],[np.dot(m1[1,:],m2[:,0]),np.dot(m1[1,:],m2[:,1])]])" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[25, 12],\n", " [62, 26]])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mat_prod = np.array([[np.dot(m1[0,:],m2[:,0]),np.dot(m1[0,:],m2[:,1])],[np.dot(m1[1,:],m2[:,0]),np.dot(m1[1,:],m2[:,1])]])\n", "mat_prod" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0., 1., 4., 9., 16.])" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dim = 5\n", "l = np.zeros(dim)\n", "for i in range(dim):\n", " l[i] = i*i\n", "\n", "l" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "loop = True\n", "l = list()\n", "while loop:\n", " value = float(input(\"Give me a number: \"))\n", " if value == 0.0:\n", " loop = False\n", " else:\n", " l.append(value)\n", " \n", "al = np.array(l)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "l,al" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "type(l),type(al)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The inverse of a matrix $A$ is a matrix $A^{-1}$ such that $A \\cdot A^{-1} = I$. \n", "\n", "Computing the inverse is easily done in numpy with np.linalg.inv and it can be very useful in solving linear equations." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m1i = np.linalg.inv(m1)\n", "print(m1)\n", "print(m1i)\n", "print(m1 @ m1i)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.eye(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Numpy allows to generate random vectors with a desired shape and float values in the half-open interval [0.0, 1.0):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.random.random((3,2,4))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.random.randint(4, size=(3,2)) # generates 3 by 2 random integer values lower than 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is often necessary to obtain a list of elements with duplicates removed and some additional information about element count and positions. This can be achieved by the np.unique function:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "r = np.random.randint(4,size=10)\n", "r" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.unique(r)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "values, indexes = np.unique(r,return_index=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "values,indexes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def retmulti(a,b):\n", " return a,b\n", "\n", "ra, rb = retmulti(3,4)\n", "print(ra,rb)\n", "ra, _ = retmulti(3.8,6.7)\n", "print(ra,rb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The given Python code demonstrates the use of the zip() function to iterate over multiple lists simultaneously. \n", "Let's break down what the code does step by step:\n", "Three lists, x, y, and z, are initialized with some values:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = [0, 1, 2]\n", "y = [3, 4, 5]\n", "z = [6, 7, 8]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The zip() function is then used to combine the three lists element-wise. It takes the corresponding elements from each list and returns an iterator of tuples, where each tuple contains the corresponding elements from all the lists. In this case, the resulting iterator will yield tuples (0, 3, 6), (1, 4, 7), and (2, 5, 8).\n", "\n", "A for loop is used to iterate over the tuples obtained from zip(). The loop assigns the values from each tuple to the variables k, l, and m:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for k, l, m in zip(x, y, z):\n", " print(k, l, m)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = [0,1,2]\n", "y = [3,4,5]\n", "z = [6,7,8]\n", "for k,l,m in zip(x,y,z):\n", " print(k,l,m)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for v, i in zip(values,indexes):\n", " print('First occurence of {} is position {}'.format(v,i))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "values, counts = np.unique(r,return_counts=True)\n", "for v, i in zip(values,counts):\n", " print('Number of occurences of {} is {}'.format(v,i))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Array transposition can be done in two possible ways:\n", "* using the .T property of the class\n", "* using the .transpose() method which allows more complex transformations on the axes.\n", "\n", "In the vast majority of cases, the property is the required option." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(c) # the original matrix\n", "print(c.T) # using the transpose property of the class\n", "print(c.transpose()) # using the transpose method of the class" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# An interesting example on mathematical formulas\n", "If we need to calculate the MSE between our predicted data and the real ones, we should apply:\n", "\n", "$$\n", "MSE = \\frac{1}{n}\\sum_{i=1}^n{(predVal_i - realVal_i)^2}\n", "$$\n", "\n", "While in most languages this formula would require an iterative loop to solve, it gets quite easy in numpy and can be done in at least two ways that do not imply explicit iterations:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "predVal = np.random.random(5)\n", "realVal = np.random.random(5)\n", "\n", "print('predVal {}'.format(predVal))\n", "print('realVal {}'.format(realVal))\n", "\n", "%timeit 1/predVal.shape[0]*np.sum(np.square(predVal-realVal)) # with the sum of squares\n", "MSE = 1/predVal.shape[0]*np.sum(np.square(predVal-realVal)) # with the sum of squares\n", "\n", "print('MSE SS= {:.3f}'.format(MSE))\n", "\n", "%timeit 1/predVal.shape[0]*np.dot(predVal-realVal,predVal-realVal) # using dot product\n", "MSE = 1/predVal.shape[0]*np.dot(predVal-realVal,predVal-realVal) # using dot product\n", "\n", "print('MSE DP= {:.3f}'.format(MSE))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Data can be loaded and saved with numpy specific routines but it isn't worth going into these functions because we will be learning a better way of dealing with data input with the Pandas library." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basic plotting example\n", "This example gives only a quick overview on how to plot data with numpy support, bearing in mind that a detailed description on data plotting will be given in lecture 4." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "# Compute the x and y coordinates for points on a sine curve\n", "x = np.arange(0, 4 * np.pi, 0.1)\n", "y = np.sin(x)\n", "x,y" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Plot the points using matplotlib\n", "plt.plot(x, y)\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.16" } }, "nbformat": 4, "nbformat_minor": 2 }