--- tags: Documentation title: Tables Functions Documentation --- <style type="text/css"> <-- Colton Rusch, Fall 2020 --> @import url('https://fonts.googleapis.com/css2?family=Fira+Mono&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap'); .pyret-text { font-family: 'Source Code Pro', monospace; font-size: 15px; border-top: 1px solid #99b; margin: 0; margin-top: 1em; margin-bottom: 1em; padding: 0.25em; padding-top: 0.3em; padding-bottom: 0.4em; background: linear-gradient(to bottom left, hsl(0, 0%, 99%) 0%, hsl(216, 62%, 95%) 100%); } </style> # Tables Functions Documentation Pyret has three different notations for manipulating Tables (each makes sense for someone starting Tables with a different goal or prior knowledge about programming). The version we are using, based on functions, is not covered in the Pyret documentation, but it is in the [textbook](https://dcic-world.org). This page summarizes the functions you can use to manipulate Tables. :::info Use this, not the Pyret Documentation, for working with Tables! ::: Always start by including these functions at the top of your file! ``` include shared-gdrive("dcic-2021", "1wyQZj_L0qqV9Ekgr9au6RX2iqt2Ga8Ep") ``` :::info Many of the examples given for the functions described below will be using the Table called `my-table` created in the section below, ["Creating a Table from Scratch."](#Creating-a-Table-from-Scratch) ::: --- ## Creating a Table from Scratch If we want to explicitly define a `Table`, we can write it using this syntax: ``` table: col0-name :: col0-type, col1-name :: col1-type, ... row: r0c0, r0c1, ... row: r1c0, r1c1, ... row: r2c0, r2c1, ... ... end ``` * **Example:** ``` my-table = table: name :: String, age :: Number, favorite-color :: String row: "Bob", 12, "blue" row: "Alice", 17, "green" row: "Eve", 13, "red" end ``` Evaluating `my-table` in the interactions window after running the program above will display a formatted version of the `Table`: ![table example](https://www.pyret.org/docs/latest/table-print.png) --- ## Accessing a Row or Value in a Table **Getting a row**: To get a specific row number from the table, use `row-n` from the standard Pyret documentation. * **Example:** ```>>> my-table.row-n(0)``` **Getting a value**: The syntax `my-row[col-name]` accesses a `Row` at a particular column, resulting in a particular value. e.g. `my-row["age"]`→`20`. To get a particular value in a `Table`, put these two together, e.g. `my-table.row-n(0)["age"]` would retrieve the value for the column "age" in the first row of the `Table`. * **Example:** ``` >>> my-table.row-n(0)["age"] 12 ``` ``` >>> alice-row = my-table.row-n(1) >>> alice-row["favorite-color"] "green" ``` --- ## Creating and Extracting Tables <div id="filter-with" class="pyret-text"><b>filter-with</b>(t :: Table, keep :: (Row -> Boolean)) -> Table</div> Given a `Table` and a predicate (e.g. lambda expression) on rows, returns a `Table` with only the rows for which the predicate returns `true`. * **Example:** Suppose we wanted to keep only rows of `my-table` that have an "age" value less than 15. We would write the expression: ``` filter-with(my-table, lam(r): r["age"] < 15 end) ``` ![Output: a table, name age favorite-color "Bob" 12 "blue" "Eve" 13 "red"](https://hackmd.io/_uploads/BylzYuDyT.png) <div id="order-by" class="pyret-text"><b>order-by</b>(t :: Table, colname :: String, sort-up :: Boolean) -> Table</div> Given a `Table` and the name of a column in that `Table`, return a `Table` with the same rows ordered based on the named column. If `sort-up` is `true`, the `Table` will be sorted in ascending order, otherwise it will be in descending order. * **Examples:** ![Input: order-by(my-table, "age", true) Output: a table, name age favorite-color "Bob" 12 "blue" "Eve" 13 "red" "Alice" 17 "green"](https://i.imgur.com/CghsqzE.png) ![Input: order-by(my-table, "name", false) Output: a table, name age favorite-color "Eve" 13 "red" "Bob" 12 "blue" "Alice" 17 "green"](https://i.imgur.com/ZcqfgvF.png) <div id="build-column" class="pyret-text"><b>build-column</b>(t :: Table, colname :: String, builder :: (Row -> A)) -> Table</div> Consumes an existing `Table` and produces a new `Table` containing an additional column with the given `colname`, using `builder` to produce the values for that column, once for each row. Here, `A` is the type of the new column, determined by the type of value the `builder` predicate produces. * **Example:** Suppose we wanted to create a column that tells us whether or not the value in each `Row`'s "age" column is in the 'teens' (i.e. thir*teen* to nine*teen*). Here is an example `builder` function: ``` build-column(my-table, "is-teenager", lam(r): (r["age"] > 12) and (r["age"] < 20) end) ``` ![a table](https://hackmd.io/_uploads/Hk_3YuwyT.png) <div id="add-row" class="pyret-text"><b>add-row</b>(t :: Table, r :: Row) -> Table</div> Consumes a `Table` and a `Row` to add, and produces a new `Table` with the rows from the original table followed by the given `Row`. * **Example:** Suppose we have this other table, inspiringly named `other-table`, and we want to add its second `Row` to our original table, `my-table`: ``` other-table = table: name :: String, age :: Number, favorite-color :: String row: "Julia", 21, "marigold" row: "Colton", 19, "blue" row: "Monica", 20, "purple" row: "Giselle", 21, "red" end ``` ![Input: new-row = get-row(other-table, 1) add-row(my-table, new-row) Output: a table, name age favorite-color "Bob" 12 "blue" "Alice" 17 "green" "Eve" 13 "red" "Colton" 19 "blue"](https://imgur.com/DgjpKE9.png) (*note: the get-row expression in the figure should be `other-table.row-n(1)`*) <div id="add-col" class="pyret-text"><b>add-col</b>(t :: Table, colname :: String, c-vals :: List<Any>) -> Table</div> Consumes a `String` representing a column name and a `List` of values and produces a new `Table` with the columns of the input `Table` followed by a column with the given name and values. Note that the length of `c-vals` must equal the length of the `Table`. * **Example:** Here's a `List<String>` representing hair colors, which we want to add to `my-table` as a column: ``` hair-color-c-vals = [list: "brown", "red", "blonde"] ``` ![Input: add-col(my-table, "hair-color", hair-color-c-vals) Output: a table, name age favorite-color hair-color "Bob" 12 "blue" "brown" "Alice" 17 "green" "red" "Eve" 13 "red" "blonde"](https://imgur.com/2kbZfoB.png) <div id="select-columns" class="pyret-text"><b>select-columns</b>(t :: Table, colnames :: List<String>) -> Table</div> Consumes a `Table` and a `List<String>` containing column names, and produces a new `Table` containing only those columns. The order of the columns is as given in the input `List`. * **Example:** ``` desired-colnames = [list: "name", "favorite-color"] ``` ![Input: select-columns(my-table, desired-colnames) Output: a table, name favorite-color "Bob" "blue" "Alice" "green" "Eve" "red"](https://imgur.com/UJXenmg.png) <div id="transform-column" class="pyret-text"><b>transform-column</b>(t :: Table, colname :: String, f :: (A -> B)) -> Table</div> Consumes a `Table`, a `String` representing a column name, and a transformation function and produces a new `Table` where the transformation function has been applied to all values in the named column. The values in the original column are of type `A` (the input type of the function) and values in the new column have type `B` (the output type of the function). * **Example:** Suppose the rows of `my-table` represent a family whose last name is "Smith." We want to change each name in the "name" column to whatever `String` is currently in the column plus the `String` " Smith" after it. Here is a transformation function for this example: ``` fun add-last-name(name :: String) -> String: doc: "consumes a String; returns that String + ' Smith'" name + ' Smith' end ``` ![Input: transform-column(my-table, "name", add-last-name) Output: a table, name age favorite-color "Bob Smith" 12 "blue" "Alice Smith" 17 "green" "Eve Smith" 13 "red"](https://imgur.com/Vt4zu9M.png) --- ## Extracting Data Through Table Methods Table methods are how we extract data from a table. Methods are similar in spirit to functions, but their notation (*table.operation(args)*) is more suggestive of going inside a table to extract data. <!--***t.row-n**(n :: Number) -> Row* For a table *t*, returns the *n*th row, where row numbers start at 0--> <div id=".length" class="pyret-text"><b>t.length</b>() -> Number</div> For the `Table` named `t`, returns a `Number` representing the number of rows in the `Table`. * **Example:** ``` >>> my-table.length() 3 ``` <div id=".get-column" class="pyret-text"><b>t.get-column</b>(colname :: String) -> List&lt;A&gt;</div> Returns a `List` of the values in the named column in the `Table` named `t`. `A` is the type of the data in the named column. * **Example:** ``` >>> my-table.get-column("name") [list: "Bob", "Alice", "Eve"] ``` <div id=".drop" class="pyret-text"><b>t.drop</b>(colname :: String) -> Table</div> Returns a `Table` that is the same as `Table` `t`, except without the column whose name is `colname`. * **Example:** ![Input: my-table.drop("age") Output: a table, name favorite-color "Bob" "blue" "Alice" "green" "Eve" "red"](https://imgur.com/ZHbjjJI.png) --- ## Summarizing Columns <div id="sum" class="pyret-text"><b>sum</b>(t :: Table, colname :: String) -> Number</div> Takes a `Table` and a `String` representing the name of a column in that `Table`. Returns a `Number` representing the sum of the values in the column. Note that the given column must contain `Number` values. * **Example:** ``` >>> sum(my-table, "age") 42 ``` <div id="mean" class="pyret-text"><b>mean</b>(t :: Table, colname :: String) -> Number</div> Takes a `Table` and a `String` representing the name of a column in that `Table`. Returns a `Number` representing the mean (average value) of values in the column. Note that the given column must contain `Number` values * **Example:** ``` >>> mean(my-table, "age") 14 ``` <div id="median" class="pyret-text"><b>median</b>(t :: Table, colname :: String) -> Number</div> Takes a `Table` and a `String` representing the name of a column in that `Table`. Returns a `Number` representing the median (middle value) of values in the column. Note that the given column must contain `Number` values. * **Example:** ``` >>> median(my-table, "age") 13 ``` <div id="modes" class="pyret-text"><b>modes</b>(t :: Table, colname :: String) -> List&lt;A&gt;</div> Takes a `Table` and a `String` representing the name of a column in that `Table`. Returns a `List<Number>` containing the modes (most frequently occurring values) in the given column, where `A` is the type of data in the given column. * **Examples:** ``` >>> modes(my-table, "age") [list: ] ``` ``` new-table = table: color :: String row: "blue" row: "blue" row: "red" end ``` ``` >>> modes(new-table, "color") [list: "blue"] ``` <div id="stdev" class="pyret-text"><b>stdev</b>(t :: Table, colname :: String) -> Number</div> Takes a `Table` and a `String` representing the name of a column in that `Table`. Returns a `Number` representing the standard deviation (a measure of how spread out values are) of the values in the given column. Note that the given column must contain `Number` values. :::warning **Warning:** `stdev` produces `Roughnum` values (Pyret's way of representing approximations of irrational numbers), which may not work with some operations (for example, `order-by` cannot be called on a column containing `Roughnums`). You can convert a `Roughnum` to a rational number using [`num-to-rational`](https://www.pyret.org/docs/latest/numbers.html#%28part._numbers_num-to-rational%29). ::: * **Example:** ``` >>> stdev(my-table, "age") ~2.160246899469287 ``` <div id="count" class="pyret-text"><b>count</b>(tab :: Table, colname :: String) -> Table</div> Takes a `Table` and a `String` representing the name of a column in that `Table`. Produces a `Table` that summarizes how many rows have each value in the given column. * **Example:** ![Input: count(my-table, "age") Output: a table, value count "Eve" 1 "Alice" 1 "Bob" 1](https://imgur.com/RGxWbPc.png) --- ## Plots and Charts In this section, we'll use the following table of heights and weights, `height-weight-table` to illustrate many of the following plot and chart functions: ``` height-weight-table = table: height :: Number, weight :: Number row: 74, 242 row: 69, 162 row: 74, 213 row: 72, 220 row: 70, 206 end ``` <div id="histogram" class="pyret-text"><b>histogram</b>(t :: Table, colname :: String, bin-width :: Number) -> Image</div> Displays an `Image` of a histogram of values in the named column, which must contain numeric data. `bin-width` indicates the width of bins in the histogram. * **Example:** ``` >>> histogram(height-weight-table, "height", 3) ``` ![Input: histogram of heights from height-weight-table](https://imgur.com/mUUmL98.png) <div id="scatter-plot" class="pyret-text"><b>scatter-plot</b>(t :: Table, xs :: String, ys :: String) -> Image</div> Displays an `Image` of a scatter plot from the given table. `xs` names the column in `t` to use for x-values, and `ys` names the column in `t` to use for y-values. Both columns must contain `Number` values. * **Example:** ``` >>> scatter-plot(height-weight-table, "height", "weight") ``` ![Input: scatter plot of heights and weights from heights-weights-table](https://imgur.com/fVlNN7v.png) <div id="lr-plot" class="pyret-text"><b>lr-plot</b>(t :: Table, xs :: String, ys :: String) -> Image</div> Like a call to `scatter-plot` with the same inputs. The difference is that a linear regression will be attempted on the elements of the plot, and a regression line will the be drawn over the data. * **Example:** ``` >>> lr-plot(height-weight-table, "height", "weight") ``` ![Input: linear regression plot of heights and weights from heights-weights-table](https://imgur.com/qmdd0QF.png) <div id="pie-chart" class="pyret-text"><b>pie-chart</b>(t :: Table, ls :: String, vs :: String) -> Image</div> Display an `Image` of a pie-chart from the given `Table` (one slice per row). `ls` is the label to use for the chart, and `vs` names the column of the `Table` to use for values in the pie chart. * **Example:** ``` cs111-syllabus-table = table: course-component :: String, grade-weight :: Number row: "Drills/Lecture Activities", 10 row: "Labs", 10 row: "Homeworks", 25 row: "Projects", 25 row: "Code Check-ins", 15 row: "Exams", 15 end ``` ``` >>> pie-chart(cs111-syllabus-table, "course-component", "grade-weight") ``` ![Input: pie chart of grade weights from cs111-syllabus-table](https://imgur.com/15HO1sr.png) <div id="bar-chart" class="pyret-text"><b>bar-chart</b>(t :: Table, ls :: String, vs :: String) -> Image</div> Displays an `Image` of a bar-chart from the given `Table` (one bar per row). `ls` names the column of the `Table` to use for labels, and `vs` names the column of the `Table` to use for values in the bar chart. * **Example:** ``` cs111-syllabus-table = table: course-component :: String, grade-weight :: Number row: "Drills/Lecture Activities", 10 row: "Labs", 10 row: "Homeworks", 25 row: "Projects", 25 row: "Code Check-ins", 15 row: "Exams", 15 end ``` ``` >>> bar-chart(cs111-syllabus-table, "course-component", "grade-weight") ``` ![Input: bar chart of grade weights from cs111-syllabus-table](https://imgur.com/5zpuyxQ.png) <div id="freq-bar-chart" class="pyret-text"><b>freq-bar-chart</b>(t :: Table, vs :: String) -> Image</div> Display an `Image` of a frequency bar-chart from the given `Table`. There is one bar for each unique value of the column with name `vs` (showing the number of occurrences of that value). * **Example:** ``` favorite-colors-table = table: color :: String row: "blue" row: "red" row: "green" row: "blue" row: "blue" row: "red" end ``` ``` >>> freq-bar-chart(favorite-colors-table, "color") ``` ![Input: frequency bar chart of colors from favorite-colors-table](https://imgur.com/D8cuoUI.png) <div id="box-plot" class="pyret-text"><b>box-plot</b>(t :: Table, vs :: String) -> Image</div> Produces an `Image` of a box plot of the values in the column named `vs` in the `Table`. A box plot shows the minimum, maximum, and median values of a column, as well as the first (lowest) and third quartiles of the dataset; this is helpful for seeing the variation in a dataset. * **Example:** ``` >>> box-plot(height-weight-table, "weight") ``` ![Input: box plot of weights from heights-weights-table](https://imgur.com/aHkWSwT.png)