Phys 238 : The Simple Pendulum

Reading .CSV Files With Mathematica

Getting Started

Mathematica remembers definitions, even if you delete them from the notebook.  This can sometimes be confusing, so it’s often a good idea to simply clear everything and start anew.  This is especially true if you use the Evaluation -> Evaluate Notebook menu item.

Clear["Global`*"] (* Clear all variable and function definitions *)

Reading a CSV file

Preliminaries

It is not always obvious where Mathematica will look for data files or export graphs.  It is often useful to keep your data in the same directory as the notebook.  The following command sets the default directory to be the same as the directory for this notebook.

SetDirectory[NotebookDirectory[]]

Initial Import

Mathematica has many different ways to read and interpret .csv (Comma Separated Values) files.  One high-level way is to use what Mathematica calls a “Dataset”, which is a structured object with its own special query language.  (In Python, an analogous approach is to use the Pandas library.)  Unfortunately, Mathematica’s Datasets do not work well with poorly structured CSV files, and multidimensional slices of Datasets can be challenging to use with some other Mathematica functions.  Both issues can arise in data we will encounter this semester.  Accordingly, this notebook will use a more basic, but more flexible, approach.

First, import all the data as a “CSV” file.  Use a semicolon at the end of the statement so that the entire data file isn’t printed out.

fulldata = Import["pendulum-20250129.csv", "CSV"];

‘fulldata’ is now an array containing all the contents of the file.  Before doing anything further, it is worthwhile to look at the first few elements of the data.  Use the double bracket notation to extract individual elements of the array.  For example, the first row is given by fulldata[[ 1 ]].  Note that the row is itself a list (in curly braces) of 3 elements, which are the titles for the columns of data.  There are 3 columns, Time, GateState, and Period.  GateState is either ‘1’ or ‘0’, depending on whether the photogate was blocked or not.

fulldata[[1]]

You can see more rows by replacing the single number ‘1’ by a list (in curly braces) of the rows you want to see.  For example, the first 6 rows are

fulldata[[{1, 2, 3, 4, 5, 6}]]

This is a nested list of lists.  There are 6 rows, each of which is a list of 3 items.    A useful way to display such a list of lists is as a Table, using the TableForm[ ] command.

TableForm[ fulldata[[{1, 2, 3, 4, 5, 6}]] ]

Finally, a quick shorthand for the 1-6 range is to use the Range function:

Range[6]

So the first 10 rows are

TableForm[ fulldata[[Range[10]]] ]

Extracting the Relevant Data

The data consists of 3 columns.  We are only interested in the period, which is in the third column.  For illustrative purposes, work with a short subset of the full data.

short = fulldata[[ Range[11] ]];
TableForm[short]

To extract a full row, you use the [[ ]] notation.  To extract a specific element within that row, you have to specify both the row and column.  For example, to extract the 3rd item of row 6, you would write

short[[6, 3]]

You can replace the ‘6’ by a list (in curly braces) of rows to extract:

short[[{6, 7, 8, 9, 10}, 3]]

The special entry “All” will extract all rows:

short[[ All, 3 ]]

It is not useful for this data set, but you can also select multiple columns in a similar way:

short[[6, {1,3}]] (* Extract row 6, columns 1 and 3 *)

short[[6, All]] (* Extract row 6, All columns *)

So here are the values from column 3 of our shortened data set, shown in Table format:

col3 = short[[ All, 3 ]];

TableForm[ col3 ]

Using the Select Function

The next challenge is to select the elements from the 3rd column that correspond to period values.  Mathematica has a function ‘NumberQ’ that tests if an element is a number.  Consider row 2 and row 6:

col3[[2]]

NumberQ[col3[[2]]]

col3[[6]]

NumberQ[col3[[6]]]

Next, we need to Select the elements from column 3 that are numbers.  Mathematica’s Select[ ] function does this.

Select[col3, NumberQ[#] &]

The Select function takes two arguments:  Select[data, criterion].  It steps through each individual element of ‘data’ and applies ‘criterion’ to each row.  Specifically, it sets the special variable ‘#’ equal to each element in turn, and returns only those elements for which ‘NumberQ’ returns true.  You have to include the ‘&’ sign so to apply the NumberQ function to the ‘#’ data element.  (See the help for Function for more details, but it is rather dense reading.)

So one way to get all the period values out of the full data set is

data = Select[fulldata[[All, 3]], NumberQ[#] &];

Looking at the first 20 periods:

data[[Range[20]]]

Saving the extracted data

For a future homework assignment, you will need the period values.  It is handy to export the values now with the ‘Export’ command.  This will create a data file with all the period values in a single column, suitable for easy import into another program.

Export["pendulum-20250129-period.csv", data]

Summary of Import:

For this data set,  here are the relevant commands,

SetDirectory[NotebookDirectory[]]

fulldata = Import["pendulum-20250129.csv", "CSV"];

data = Select[fulldata[[All,3]], NumberQ[#] &];

(Optional) Save the period data for later importing.

Export["pendulum-20250129-period.csv", data]

Statistical Analysis

Here is how to calculate various important statistics for the data set.  Most of the commands should be self-evident.

npts = Length[data]

T = Mean[data]

σT = StandardDeviation[data]

δT = σT/Sqrt[npts]

Mathematica can express this as a value with uncertainty using the Around[ ] function:

Around[T, δT]

Here is a plot of the data, with sensible labels.  Save the plot in the ‘Tplot’ variable to use later.

Tplot = ListPlot[data, LabelStyle->Larger, Frame -> True, FrameLabel -> {"Cycle", "Period (s)"}, ImageSize -> Scaled[0.8]]

Further explorations

We can illustrate the ±1 σ range on the plot.  Note that the ‘Show’ command combines graphics objects, in this case the data plot we made above, and a new plot showing the ±1 σ range.

TCompPlot = Show[{
Tplot, 
 Plot[{T + σT, T, T - σT}, {cycle, 1, Length[data]},
 PlotLegends -> {"+1 σ", "Mean", "-1 σ"}]
}]

Export["pendulum-period-plot.pdf", TCompPlot]

We can also count the numbers with a particular range with the Select[ ]  function.  This function steps through the ‘data’ array and assigns the special symbol ‘#’ to the current element of the array.  (The ‘&’ must also be included at the end of the comparison.)

within1 = Select[data, T - σT <= # <= T + σT &];
100. * Length[within1]/npts

within2 = Select[data, T - 2σT <= # <= T +2 σT &];
100. * Length[within2]/npts

within3 = Select[data, T - 3σT <= # <= T +3 σT &];
100. * Length[within3]/npts