Skip to content

Commit 95fd870

Browse files
authored
Write documentation for common library (#26)
1 parent 3049d33 commit 95fd870

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

analyses/common/tables.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def save_table(styler: pandas.io.formats.style.Styler, filename: str, subdir: Op
9292
- Tuple[RuleLineIndex, RuleWidth]: Place a \midrule[RuleWidth] after the specified row.
9393
- Tuple[RuleLineIndex, Union[CmidruleSpec, List[CmidruleSpec]]] where, CmidruleSpec is Tuple[lstart: int, rstart: int, ltrim: TrimSpec, rtrim: TrimSpec] and TrimSpec is Union[bool, RuleWidth]:
9494
Place a (series of) \cmidrule(ltrim rtrim){lstart-rstart} after the specified row. ltrim is 'l' if true, 'l{width}' if a RuleWidth, similarly for rtrim.
95-
colsep (Optional[str]): If False, use default column separators. If a string, it is the column separator units. Defaults to False.
95+
colsep (Optional[str]): If None, use default column separators. If a string, it is the column separator units. Defaults to None.
9696
'''
9797
if colsep:
9898
colsepprefix = re.sub('[0-9]', '',

docs/research/common.md

+92-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,95 @@
22

33
The study template provides a common Python library to help researchers generate tables and figures from their analyses.
44

5-
TODO
5+
6+
## Data Management
7+
8+
The `common.df` library provides two functions for reading Boa output into a Pandas dataframe, these are `get_df` and `get_deduped_df`. These functions take similar basic arguments. These functions will read from a Parquet file if it has been generated, otherwise, they will read from CSV (and save to parquet for sped-up loading later on). Basic call syntax is below, with description of arguments following.
9+
10+
11+
```python title="Call Syntax"
12+
get_df(filename: str, subdir: Optional[str]=None, drop: Optional[List[str]]=None,
13+
precache_function: Optional[Callable[[pd.DataFrame], pd.DataFrame]]=None,
14+
**kwargs) -> pd.DataFrame
15+
16+
get_deduped_df(filename: str, subdir: Optional[str]=None, dupesdir: Optional[str]=None,
17+
drop: Optional[List[str]]=None,
18+
precache_function: Optional[Callable[[pd.DataFrame], pd.DataFrame]]=None,
19+
ts: bool=False, **kwargs) -> pd.DataFrame
20+
```
21+
22+
- `filename`: the name of the CSV data file, without `.csv`.
23+
- `subdir`: optional, the name of the sub-directory underneath `data/csv/` that `filename` is in (default `None`).
24+
- `dupesdir`: (`get_deduped_df` only): optional, the name of the sub-directory underneath `data/csv` containing the dupes file (default `None`).
25+
- `drop`: A list of column names to drop after loading.
26+
- `precache_function`: A function that takes a data frame, and transforms it in some way (e.g., creating new columns which are intensive to compute, or converting data types).
27+
- `ts` (`get_deduped_df` only): Pass `True` if the hash file also has file timestamps.
28+
- `**kwargs`: When reading from CSV, these are passed to [`pd.read_csv`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html), which see.
29+
30+
An example of the usage of `get_deduped_df` is shown below.
31+
32+
```python title="analyses/rq1.py" linenums="8"
33+
df = get_deduped_df('rq1', 'kotlin', 'kotlin', names=['var', 'project', 'file', 'astcount'])
34+
```
35+
36+
This will get a file-wise deduplicated dataframe from the results file `rq1.csv` in `data/csv/kotlin/`, using the `data/csv/kotlin/dupes.csv` file to provide duplication information, with the columns given the names `var`, `project`, `file`, and `astcount`.
37+
38+
### Deduplication
39+
40+
Since data duplication is a known problem in MSR studies (see [Lopes et al., 2017](https://dl.acm.org/doi/10.1145/3133908)), we provide the ability do deduplicate data. However, this deduplication is based on the AST Hash. This is done by calculating the hash of the AST of each file as it appears in the HEAD commit of each repository, and selecting one project/file pair for each value of the hash. A query for this is provided, see also [Defining Queries](add-query.md#defining-queries).
41+
42+
## Table Generation
43+
44+
Pandas can be used to generate LaTeX tables from query output and calculated data, however, much of this is routine and enabled by `common.tables`. In particular, `common.tables` will generate tables that use the [`booktabs`](https://ctan.org/pkg/booktabs/) package for formatting (following the ACM document class recommendations).
45+
46+
To do this, there are four major functions.
47+
48+
- `get_styler` which will return the [`Styler`](https://pandas.pydata.org/pandas-docs/stable/reference/style.html) object for a dataframe or series. Stylers are used to format data based on the values of each cell. In addition to the dataframe or series, it takes two keyword arguments: a number of `decimals` (default 2), and a `thousands` separator (default `,`).
49+
- `highlight_cols` and `highlight_rows`: These highlight the column and row headers, respectively of a table in a `Styler` object, as shown below on line 11.
50+
- `save_table` will save `Styler` to a LaTeX table. Its usage is somewhat more complex, and is described below.
51+
52+
```python title="analyses/rq1.py" linenums="11"
53+
style = highlight_rows(highlight_cols(get_styler(df)))
54+
save_table(style, 'rq1.tex', 'kotlin')
55+
```
56+
57+
### Using `save_table`
58+
59+
`save_table` takes two mandatory arguments, a `styler`, and a `filename` (which should include the `.tex` extension). It takes an optional `subdir` (underneath `tables/` to save the file in as well. Additionally, the keyword argument `colsep` is available to use a custom column separator width, if no argument (or `None`) is passed, defaults will be used, otherwise, the value should be the size of the column separator in LaTeX compatible units.
60+
61+
Additionally, a `mids` keyword argument is available to allow manual placement of mid-table rules. If `None`, no mid-table rules will be passed, otherwise, a rule specifier or a list of rule specifiers may be passed, as described below.
62+
63+
Rule Specifiers take the following form:
64+
65+
- A single integer $n$, which will place a `\midrule` after the $n$th line (one-based indexing).
66+
- A pair `(n, width)` will place `\midrule[width]` after the $n$th line.
67+
- A pair `(n, cmidrulespec)` or `(n, [cmidrulespec+])`, which will place the specified `cmidrules` after the $n$th line. A `cmidrulespec` is a tuple, `(start, end, left_trim, right_trim)`, where `start` and `end` are column indices, and `left_trim` and `right_trim` are either Booleans or LaTeX lengths. If they are False, no trim will be applied, if they are True, default trim will be applied, if they are a LaTeX length, a trim of that length will be applied.
68+
69+
Finally, additional keyword arguments may be passed to [`styler.to_latex`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.io.formats.style.Styler.to_latex.html), to further control generated appearance. Options of note include `multirow_align` to control the vertical alignment of row-spanning cells, `multicol_align` to control the horizontal alignment of column-spanning cells, and `siunitx` to enable [`siunitx`](https://ctan.org/pkg/siunitx)-style numerical alignment.
70+
71+
## Figure Generation
72+
73+
The `df.graphs` module provides a function, `setup_plots` to create a blank, pre-configured plot canvas for use. It takes an optional argument, `rcParams`, which is used to set the [`plt.rcParams`](https://matplotlib.org/stable/users/explain/customizing.html) parameters. In particular, the following are set by default:
74+
75+
- PDF and PS font types are set to 42, avoiding PostScript Type 3 fonts (for compliance with common submission requirements).
76+
- Figure size is set to 6"x4", with 600 DPI.
77+
- Font size is set to 24 pt.
78+
- Plots are set in a constrained layout (see [Matplotlib's constrained layout guide](https://matplotlib.org/stable/users/explain/axes/constrainedlayout_guide.html) for more information).
79+
80+
## Utilities
81+
82+
Finally, a few utilities are provided in `common.utils`. These are mostly intended for helping to simplify analyses, and are as follows:
83+
84+
- `_resolve_dir` will ensure that a relative directory will be relative to the study template root.
85+
- `_get_dir` will turn a directory or none into an appropriate string form (empty string if None, with a `/` if a regular string is passed).
86+
- `get_dataset` will take a filename base name and optional sub-directory name, and determine which Boa dataset the data came from.
87+
88+
## Loading Common Libraries
89+
90+
The common libraries described above can be loaded as normal in most cases. However, if analyses are arranged in various subdirectories, the following code can be used to allow import.
91+
92+
```python title="Code to import common from a subdirectory of 'analyses/'."
93+
from pathlib import Path
94+
import sys
95+
sys.path.append(str(Path(__file__).resolve().parent.parent)) # (additional calls to parent may be necessary for deeply-nested analyses)
96+
```

0 commit comments

Comments
 (0)