from cogent3 import load_table
table = load_table("data/stats.tsv")
table| Locus | Region | Ratio |
|---|---|---|
| NP_003077 | Con | 2.5386 |
| NP_004893 | Con | 121351.4264 |
| NP_005079 | Con | 9516594.9789 |
| NP_005500 | NonCon | 0.0000 |
| NP_055852 | NonCon | 10933217.7090 |
5 rows x 3 columns
dictdict.pandas.DataFramehead()tail()repr()dictdictpandas.DataFramestr() formatstr() formatto_string()to_string()Table handles tabular data, storing as columns in a, you guessed it, columns attribute. The latter acts like a dictionary, with the column names as the keys and the column values being numpy.ndarray instances. The table itself is iterable over rows.
Table is immutable at the level of the individual ndarray not being writable.
We load a tab separated data file using the load_table() function. The format is inferred from the filename suffix and you will note, in this case, it’s not actually a csv file.
| Locus | Region | Ratio |
|---|---|---|
| NP_003077 | Con | 2.5386 |
| NP_004893 | Con | 121351.4264 |
| NP_005079 | Con | 9516594.9789 |
| NP_005500 | NonCon | 0.0000 |
| NP_055852 | NonCon | 10933217.7090 |
5 rows x 3 columns
The known filename suffixes for reading are .csv, .tsv and .pkl or .pickle (Python’s pickle format).
If you invoke the static column types argument, i.e.load_table(..., static_column_types=True) and the column data are not static, those columns will be left as a string type.
The cogent3 load functions support loading from a url. We load the above .tsv file directly from GitHub.
Although unnecessary in this case, it’s possible to override the suffix by specifying the delimiter using the sep argument.
To create a table from the follow examples, you specify your header and use make_table().
load_delimited()This is just a standard parsing function which does not do any filtering or converting elements to non-string types.
[['chr1',
'29214',
'29566',
'chr1.1',
'626',
'.',
'0.0724',
'3.9',
'-1',
'159'],
['chr1',
'89933',
'90118',
'chr1.2',
'511',
'.',
'0.0313',
'1.59',
'-1',
'94'],
['chr1',
'545979',
'546193',
'chr1.3',
'543',
'.',
'0.0428',
'2.23',
'-1',
'100'],
['chr1',
'713797',
'714639',
'chr1.4',
'1000',
'.',
'0.3215',
'16.0',
'-1',
'380']]
FilteringParser[['chr1',
'29214',
'29566',
'chr1.1',
'626',
'.',
'0.0724',
'3.9',
'-1',
'159'],
['chr1',
'89933',
'90118',
'chr1.2',
'511',
'.',
'0.0313',
'1.59',
'-1',
'94'],
['chr1',
'545979',
'546193',
'chr1.3',
'543',
'.',
'0.0428',
'2.23',
'-1',
'100'],
['chr1',
'713797',
'714639',
'chr1.4',
'1000',
'.',
'0.3215',
'16.0',
'-1',
'380']]
The limit argument specifies the number of lines to read.
If you only want a subset of the contents of a file, use the FilteringParser. This allows skipping certain lines by using a callback function. We illustrate this with stats.tsv, skipping any rows with "Ratio" > 10.
| Locus | Region | Ratio |
|---|---|---|
| NP_003077 | Con | 2.5 |
| NP_005500 | NonCon | 0.0 |
2 rows x 3 columns
You can also negate a condition, which is useful if the condition is complex. In this example, it means keep the rows for which Ratio > 10.
Specify the columns by their names.
| Locus | Ratio |
|---|---|
| NP_003077 | 2.5386 |
| NP_004893 | 121351.4264 |
| NP_005079 | 9516594.9789 |
| NP_005500 | 0.0000 |
| NP_055852 | 10933217.7090 |
5 rows x 2 columns
Or, by their index.
| Locus | Ratio |
|---|---|
| NP_003077 | 2.5386 |
| NP_004893 | 121351.4264 |
| NP_005079 | 9516594.9789 |
| NP_005500 | 0.0000 |
| NP_055852 | 10933217.7090 |
5 rows x 2 columns
The negate argument does not affect the columns evaluated.
We just use FilteringParser.
We just display the first two lines.
The individual elements are all str.
dictFor a dict with key’s as column headers.
dict.A Table can be indexed like a dict if you designate a column as the index (and that column has a unique value for every row).
| Locus | Region | Ratio |
|---|---|---|
| NP_055852 | NonCon | 10933217.7090 |
1 rows x 3 columns
The index_name argument also applies when using make_table().
pandas.DataFramemake_table() is the utility function for creating Table objects from standard python objects.
from cogent3 import make_table
d2D = {
"edge.parent": {
"NineBande": "root",
"edge.1": "root",
"DogFaced": "root",
"Human": "edge.0",
},
"x": {
"NineBande": 1.0,
"edge.1": 1.0,
"DogFaced": 1.0,
"Human": 1.0,
},
"length": {
"NineBande": 4.0,
"edge.1": 4.0,
"DogFaced": 4.0,
"Human": 4.0,
},
}
table = make_table(
data=d2D,
)
table| edge.parent | x | length |
|---|---|---|
| root | 1.0000 | 4.0000 |
| root | 1.0000 | 4.0000 |
| root | 1.0000 | 4.0000 |
| edge.0 | 1.0000 | 4.0000 |
4 rows x 3 columns
This can be done when you create the table.
| a | b |
|---|---|
| 0 | a |
| 3 | c |
2 rows x 2 columns
It can be done by directly assigning to the corresponding attributes.
Table is a row oriented object. Iterating on the table returns each row as a new Table instance.
=============================
Locus Region Ratio
-----------------------------
NP_003077 Con 2.5386
-----------------------------
The resulting rows can be indexed using their column names.
The Table.shape attribute is like that of a numpy array. The first element (Table.shape[0]) is the number of rows.
Table.shape[1] is the number of columns. Using the table from above.
The Table.columns attribute is a Columns instance, an object with dict attributes.
Columns('Locus': <U9, 'Region': <U6, 'Ratio': float64)
So iteration is the same as for dicts.
| Locus | Region | Ratio |
|---|---|---|
| NP_003077 | Con | 2.5386 |
| NP_004893 | Con | 121351.4264 |
| NP_005079 | Con | 9516594.9789 |
| NP_005500 | NonCon | 0.0000 |
| NP_055852 | NonCon | 10933217.7090 |
5 rows x 3 columns
Slice using the column name.
We change the Ratio column to using scientific notation.
This can be done on table loading,
| Locus | Region | Ratio |
|---|---|---|
| NP_003077 | Con | 2.5 |
| NP_004893 | Con | 121351.4 |
| NP_005079 | Con | 9516595.0 |
| NP_005500 | NonCon | 0.0 |
| NP_055852 | NonCon | 10933217.7 |
5 rows x 3 columns
or, for spacing at least, by modifying the attributes
Wrapping generates neat looking tables whether or not you index the table rows. We demonstrate here
| name | A/C | A/G |
|---|---|---|
| tardigrade | 0.0425 | 0.1424 |
| A/T | C/A |
|---|---|
| 0.0226 | 0.0391 |
1 rows x 5 columns
head()| a | b |
|---|---|
| 0 | 0 |
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
Top 5 rows from 10 rows x 2 columns
You change how many rows are displayed.
The table shape is that of the original table.
tail()You change how many rows are displayed.
repr()| a | b |
|---|---|
| 0 | 0 |
| 1 | 1 |
| ... | ... |
| 7 | 7 |
| 8 | 8 |
| 9 | 9 |
Top 2 and bottom 3 rows from 10 rows x 2 columns
The ... indicates the break between the top and bottom rows.
The table header is immutable. Changing column headings is done as follows.
This can be used to take a single, or multiple columns and generate a new column of values. Here we’ll take 2 columns and return True/False based on a condition.
| Locus | Region | Ratio | LargeCon |
|---|---|---|---|
| NP_003077 | Con | 2.5386 | False |
| NP_004893 | Con | 121351.4264 | True |
| NP_005079 | Con | 9516594.9789 | True |
| NP_005500 | NonCon | 0.0000 | False |
| NP_055852 | NonCon | 10933217.7090 | False |
5 rows x 4 columns
Via the Table.to_list() method.
['NP_003077', 'NP_004893', 'NP_005079', 'NP_005500', 'NP_055852']
Or directly from the column array object.
table.columns["Locus"] is a numpy.ndarray, hence the different method call.
This returns a row oriented list.
[['Con', 'NP_003077'],
['Con', 'NP_004893'],
['Con', 'NP_005079'],
['NonCon', 'NP_005500'],
['NonCon', 'NP_055852']]
column name order dictates the element order per row
dictKeys in the resulting dict are the row indices, the value is a dict of column name, value pairs.
{0: {'Locus': 'NP_003077', 'Region': 'Con', 'Ratio': 2.5386013224378985},
1: {'Locus': 'NP_004893', 'Region': 'Con', 'Ratio': 121351.42635634111},
2: {'Locus': 'NP_005079', 'Region': 'Con', 'Ratio': 9516594.978886133},
3: {'Locus': 'NP_005500', 'Region': 'NonCon', 'Ratio': 7.382703020266491e-08},
4: {'Locus': 'NP_055852', 'Region': 'NonCon', 'Ratio': 10933217.708952725}}
dictKeys in the resulting dict are the column names, the value is a list.
{'Locus': ['NP_003077', 'NP_004893', 'NP_005079', 'NP_005500', 'NP_055852'],
'Region': ['Con', 'Con', 'Con', 'NonCon', 'NonCon'],
'Ratio': [2.5386013224378985,
121351.42635634111,
9516594.978886133,
7.382703020266491e-08,
10933217.708952725]}
pandas.DataFrame| Locus | Region | Ratio | |
|---|---|---|---|
| 0 | NP_003077 | Con | 2.538601e+00 |
| 1 | NP_004893 | Con | 1.213514e+05 |
| 2 | NP_005079 | Con | 9.516595e+06 |
| 3 | NP_005500 | NonCon | 7.382703e-08 |
| 4 | NP_055852 | NonCon | 1.093322e+07 |
You can also specify column(s) are categories
If our table consists of counts data, the Table can convert it into a CategoryCount instance that can be used for performing basic contingency table statistical tests, e.g. chisquare, G-test of independence, etc.. To do this, we must specify which column contains the row names using the index_name argument.
| Ts | Tv | |
|---|---|---|
| syn | 31 | 36 |
| nsyn | 58 | 138 |
2 rows x 3 columns
| Ts | Tv | |
|---|---|---|
| syn | 31 | 36 |
| nsyn | 58 | 138 |
| Ts | Tv | |
|---|---|---|
| syn | 22.6730 | 44.3270 |
| nsyn | 66.3270 | 129.6730 |
| Ts | Tv | |
|---|---|---|
| syn | 1.7488 | -1.2507 |
| nsyn | -1.0225 | 0.7312 |
| G | df | pvalue |
|---|---|---|
| 5.973 | 1 | 0.0145 |
| Ts | Tv | |
|---|---|---|
| nsyn | 58 | 138 |
| syn | 31 | 36 |
| Ts | Tv | |
|---|---|---|
| nsyn | 66.3270 | 129.6730 |
| syn | 22.6730 | 44.3270 |
| Ts | Tv | |
|---|---|---|
| nsyn | -1.0225 | 0.7312 |
| syn | 1.7488 | -1.2507 |
Alternatively, you could also specify the index_name of the category column as
Only for tables with the same columns.
Can be done without specifying a new column (set the first argument to appended to be None). Here we simply use the same table data.
| Locus | Region | Ratio |
|---|---|---|
| NP_003077 | Con | 2.5386 |
| NP_004893 | Con | 121351.4264 |
| NP_005079 | Con | 9516594.9789 |
| NP_005500 | NonCon | 0.0000 |
| NP_055852 | NonCon | 10933217.7090 |
| NP_003077 | Con | 2.5386 |
| NP_004893 | Con | 121351.4264 |
| NP_005079 | Con | 9516594.9789 |
| NP_005500 | NonCon | 0.0000 |
| NP_055852 | NonCon | 10933217.7090 |
10 rows x 3 columns
Specifying with a new column. In this case, the value of the table.title becomes the value for the new column.
| Data# | Locus | Region | Ratio |
|---|---|---|---|
| Data1 | NP_003077 | Con | 2.5386 |
| Data1 | NP_004893 | Con | 121351.4264 |
| Data1 | NP_005079 | Con | 9516594.9789 |
| Data1 | NP_005500 | NonCon | 0.0000 |
| Data1 | NP_055852 | NonCon | 10933217.7090 |
| Data2 | NP_003077 | Con | 2.5386 |
| Data2 | NP_004893 | Con | 121351.4264 |
| Data2 | NP_005079 | Con | 9516594.9789 |
| Data2 | NP_005500 | NonCon | 0.0000 |
| Data2 | NP_055852 | NonCon | 10933217.7090 |
10 rows x 4 columns
We assigned an empty string to title, otherwise the resulting table has the same title attribute as that of table1.
Because each column is just a numpy.ndarray, this also can be done directly via the array methods.
We define a strictly numerical table,
| A | B | C |
|---|---|---|
| 0 | 1 | 2 |
| 3 | 4 | 5 |
| 6 | 7 | 8 |
| 9 | 10 | 11 |
4 rows x 3 columns
and sum all columns (default condition)
and all rows
We define a table with mixed data, like a distance matrix.
| A | B | C |
|---|---|---|
| * | 1 | 2 |
| 3 | * | 5 |
| 6 | 7 | * |
3 rows x 3 columns
and sum all columns (default condition), ignoring non-numerical data
and all rows
We can do this by providing a reference to an external function
| Locus | Region | Ratio |
|---|---|---|
| NP_003077 | Con | 2.5386 |
| NP_005500 | NonCon | 0.0000 |
2 rows x 3 columns
or using valid python syntax within a string, which is executed
| Locus | Region | Ratio |
|---|---|---|
| NP_003077 | Con | 2.5386 |
| NP_005500 | NonCon | 0.0000 |
2 rows x 3 columns
You can also filter for values in multiple columns
We select only columns that have a sum > 20 from the all_numeric table constructed above.
This returns a CategoryCounter, a dict like class.
cogent3.maths.stats.number.CategoryCounter
For multiple columns.
CategoryCounter({('a', 'c'): 1, ('a', 'd'): 1, ('b', 'c'): 3})
Table.group_by() groups rows by one or more columns, returning a GroupBy object for aggregation.
| category | value | extra |
|---|---|---|
| a | 1 | 10 |
| b | 2 | 20 |
| a | 3 | 30 |
| b | 4 | 40 |
| a | 5 | 50 |
5 rows x 3 columns
Each aggregation is a (column, function) tuple. Result columns are automatically named "function(column)". Functions can be string names that map to numpy functions ("sum", "mean", "median", "min", "max", "std", "var", "count", "first", "last") or callables. "std" and "var" use ddof=1 (unbiased estimators).
You can pass any callable as the aggregation function. For example, math.fsum provides a numerically stable sum that avoids catastrophic cancellation, unlike numpy.sum.
We do a standard inner join here for a restricted subset. We must specify the columns that will be used for the join. Here we just use Locus.
| Locus | Region | Ratio | right_LargeCon |
|---|---|---|---|
| NP_004893 | Con | 121351.4264 | True |
| NP_005079 | Con | 9516594.9789 | True |
| NP_005500 | NonCon | 0.0000 | False |
| NP_055852 | NonCon | 10933217.7090 | False |
4 rows x 4 columns
If the tables have titles, column names are prefixed with those instead of right_.
The joined() method is just a wrapper for the inner_join() and cross_join() (row cartesian product) methods, which you can use directly.
| #OTU ID | 14SK041 | 14SK802 |
|---|---|---|
| -2920 | 332 | 294 |
| -1606 | 302 | 229 |
| -393 | 141 | 125 |
| -2109 | 138 | 120 |
4 rows x 3 columns
We require a new column heading for the current header data. We also need to specify which existing column will become the header.
str() formatUsing the method provides finer control over formatting.
| Locus | Region | Ratio |
|-----------|--------|---------------|
| NP_003077 | Con | 2.5386 |
| NP_004893 | Con | 121351.4264 |
| NP_005079 | Con | 9516594.9789 |
| NP_005500 | NonCon | 0.0000 |
| NP_055852 | NonCon | 10933217.7090 |
str() formatUsing the method provides finer control over formatting.
\begin{table}[htp!]
\centering
\begin{tabular}{ r r r }
\hline
\bf{Locus} & \bf{Region} & \bf{Ratio} \\
\hline
\hline
NP_003077 & Con & 2.5386 \\
NP_004893 & Con & 121351.4264 \\
NP_005079 & Con & 9516594.9789 \\
NP_005500 & NonCon & 0.0000 \\
NP_055852 & NonCon & 10933217.7090 \\
\hline
\end{tabular}
\end{table}
We use the justify argument to indicate the column justification.
| Locus | Region | Ratio |
|:---------:|:------:|--------------:|
| NP_003077 | Con | 2.5386 |
| NP_004893 | Con | 121351.4264 |
| NP_005079 | Con | 9516594.9789 |
| NP_005500 | NonCon | 0.0000 |
| NP_055852 | NonCon | 10933217.7090 |
\begin{table}[htp!]
\centering
\begin{tabular}{ c c r }
\hline
\bf{Locus} & \bf{Region} & \bf{Ratio} \\
\hline
\hline
NP_003077 & Con & 2.5386 \\
NP_004893 & Con & 121351.4264 \\
NP_005079 & Con & 9516594.9789 \\
NP_005500 & NonCon & 0.0000 \\
NP_055852 & NonCon & 10933217.7090 \\
\hline
\end{tabular}
\caption{Some stats.}
\label{tab:table1}
\end{table}
.. csv-table:: Some stats.
:header: "Locus", "Region", "Ratio"
NP_003077, Con, 2.5386
NP_004893, Con, 121351.4264
NP_005079, Con, 9516594.9789
NP_005500, NonCon, 0.0000
NP_055852, NonCon, 10933217.7090
+------------------------------------+
| Some stats. |
+-----------+--------+---------------+
| Locus | Region | Ratio |
+===========+========+===============+
| NP_003077 | Con | 2.5386 |
+-----------+--------+---------------+
| NP_004893 | Con | 121351.4264 |
+-----------+--------+---------------+
| NP_005079 | Con | 9516594.9789 |
+-----------+--------+---------------+
| NP_005500 | NonCon | 0.0000 |
+-----------+--------+---------------+
| NP_055852 | NonCon | 10933217.7090 |
+-----------+--------+---------------+
to_string()It is also possible to specify column alignment, table caption and other arguments.
\begin{table}[htp!]
\centering
\begin{tabular}{ r r r }
\hline
\bf{Locus} & \bf{Region} & \bf{Ratio} \\
\hline
\hline
NP_003077 & Con & 2.5386 \\
NP_004893 & Con & 121351.4264 \\
NP_005079 & Con & 9516594.9789 \\
NP_005500 & NonCon & 0.0000 \\
NP_055852 & NonCon & 10933217.7090 \\
\hline
\end{tabular}
\end{table}
to_string()This format allows display of annotation tracks on genome browsers. A small sample of a bigger table.
| chrom | start | end | value |
|---|---|---|---|
| 1 | 100 | 101 | 1.1230 |
| 1 | 101 | 102 | 1.1230 |
| 1 | 102 | 103 | 1.1230 |
| 1 | 103 | 104 | 1.1230 |
| 1 | 104 | 105 | 1.1230 |
Top 5 rows from 32 rows x 4 columns
Then converted.
Appending any of the following to a filename will cause that format to be used for writing.
The delimiter can be specified explicitly using the sep argument or implicitly via the file name suffix.
Table.write and Table.to_string both accept with_title and with_legend arguments for controlling whether the table title and legend are included in the output. For to_string, leaving them as None (the default) uses each format’s convention: shown for the simple, rst and latex formats, omitted for csv and tsv. Setting either to True or False overrides that for every format.
Some stats.
Locus,Region,Ratio
NP_003077,Con,2.5386
NP_004893,Con,121351.4264
NP_005079,Con,9516594.9789
NP_005500,NonCon,0.0000
NP_055852,NonCon,10933217.7090
+-----------+--------+---------------+
| Locus | Region | Ratio |
+===========+========+===============+
| NP_003077 | Con | 2.5386 |
+-----------+--------+---------------+
| NP_004893 | Con | 121351.4264 |
+-----------+--------+---------------+
| NP_005079 | Con | 9516594.9789 |
+-----------+--------+---------------+
| NP_005500 | NonCon | 0.0000 |
+-----------+--------+---------------+
| NP_055852 | NonCon | 10933217.7090 |
+-----------+--------+---------------+