Skip to content

Commit 57e61ca

Browse files
authored
Merge pull request #2096 from oesteban/enh/better-tsv-rendering
FIX+ENH: Beautify tabular data fences
2 parents 5f56233 + 295762d commit 57e61ca

File tree

10 files changed

+150
-40
lines changed

10 files changed

+150
-40
lines changed

mkdocs.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,21 @@ extra:
101101

102102
extra_javascript:
103103
- js/jquery-3.6.0.min.js
104+
extra_css:
105+
- css/tsv.css
104106
markdown_extensions:
105107
- toc:
106108
anchorlink: true
109+
- attr_list
107110
- pymdownx.superfences:
108111
preserve_tabs: true
109112
custom_fences:
110113
- name: tsv
111114
class: tsv
112115
format: !!python/name:bidsschematools.render.tsv.fence
116+
- name: tsvgz
117+
class: tsv
118+
format: !!python/name:bidsschematools.render.tsv.fence
113119
- admonition
114120
- pymdownx.details
115121
plugins:

src/common-principles.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -505,18 +505,18 @@ TSV files MUST be in UTF-8 encoding.
505505
506506
Example:
507507
508-
```Text
509-
onset duration response_time trial_type trial_extra
510-
200 20.0 15.8 word 中国人
511-
240 5.0 17.34e-1 visual n/a
508+
```tsv {linenums="1"}
509+
onset duration response_time trial_type trial_extra
510+
200 20.0 15.8 word 中国人
511+
240 5.0 17.34e-1 visual n/a
512512
```
513513

514514
!!! warning "Attention"
515515

516516
The TSV examples in this document (like the one above this note) are occasionally
517-
formatted using space characters instead of tabs to improve human readability.
518-
Directly copying and then pasting these examples from the specification
519-
for use in new BIDS datasets can lead to errors and is discouraged.
517+
formatted with the addition of the row indices as first column.
518+
Those indices are presented for visual reference and
519+
are not part of the tabular data file's content.
520520

521521
Tabular files MAY be optionally accompanied by a simple data dictionary
522522
in the form of a JSON [object](https://www.json.org/json-en.html)
@@ -627,6 +627,13 @@ Rules for formatting plain-text tabular files apply to TSVGZ files with three ex
627627
(for example, FSL, or PNM), and to facilitate the support for other file formats
628628
in the future.
629629

630+
The above example, if stored as a TSVGZ file would have the following decompressed content:
631+
632+
```tsvgz {linenums="1"}
633+
200 20.0 15.8 word 中国人
634+
240 5.0 17.34e-1 visual n/a
635+
```
636+
630637
### Key-value files (dictionaries)
631638

632639
JavaScript Object Notation (JSON) files MUST be used for storing key-value

src/css/tsv.css

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
.tsv-table {
2+
font-feature-settings:"kern";
3+
min-width: 100%;
4+
border-collapse: collapse;
5+
overflow: auto;
6+
display: block;
7+
}
8+
9+
.tsv-table th {
10+
color: var(--md-code-fg-color);
11+
font-family:var(--md-code-font-family);
12+
font-weight: 800;
13+
background-color: var(--md-code-bg-color);
14+
border-top: 1px solid var(--md-default-fg-color--light);
15+
font-size: 0.8em;
16+
padding: 0 10px 0 10px;
17+
}
18+
19+
.tsv-table.index tr th:first-child {
20+
background-color: var(--md-text-bg-color);
21+
border-top: 0;
22+
user-select: none;
23+
}
24+
25+
.tsv-table tr:last-child td {
26+
border-bottom: 1px solid var(--md-default-fg-color--light);
27+
}
28+
29+
.tsv-table tr:first-child td {
30+
border-top: 1px solid var(--md-default-fg-color--light);
31+
}
32+
33+
.tsv-table td {
34+
font-family:var(--md-code-font-family);
35+
font-size: 0.8em;
36+
text-align: center;
37+
vertical-align: middle;
38+
color: var(--md-code-fg-color);
39+
background-color: var(--md-code-bg-color);
40+
padding: 0 10px 0 10px;
41+
}
42+
43+
.tsv-table.index td:first-child {
44+
color:var(--md-default-fg-color--light);
45+
font-family:var(--md-text-font-family);
46+
font-size: 0.7em;
47+
background-color: var(--md-text-bg-color);
48+
padding-right: 15px;
49+
text-align: right;
50+
min-width: 25px;
51+
width: 35px;
52+
border-top: 0;
53+
user-select: none;
54+
}
55+
56+
.tsv-table.index tr:last-child td:first-child {
57+
border-bottom: 0;
58+
}

src/derivatives/imaging.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -524,21 +524,21 @@ and a guide for using macros can be found at
524524

525525
An example, custom `dseg.tsv` that defines three labels:
526526

527-
```Text
528-
index name abbreviation color mapping
529-
100 Gray Matter GM #ff53bb 1
530-
101 White Matter WM #2f8bbe 2
531-
102 Brainstem BS #36de72 11
527+
```tsv
528+
index name abbreviation color mapping
529+
100 Gray Matter GM #ff53bb 1
530+
101 White Matter WM #2f8bbe 2
531+
102 Brainstem BS #36de72 11
532532
```
533533

534534
The following example `dseg.tsv` defines regions that are not part of the
535535
standard BIDS labels:
536536

537-
```Text
538-
index name abbreviation
539-
137 pars opercularis IFGop
540-
138 pars triangularis IFGtr
541-
139 pars orbitalis IFGor
537+
```tsv
538+
index name abbreviation
539+
137 pars opercularis IFGop
540+
138 pars triangularis IFGtr
541+
139 pars orbitalis IFGor
542542
```
543543

544544
<!-- Link Definitions -->

src/modality-specific-files/microscopy.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -418,10 +418,10 @@ when applicable.
418418
Additional optional columns MAY be used to describe other subjects' attributes.
419419

420420
`participants.tsv` example:
421-
```Text
422-
participant_id species strain strain_rrid
423-
sub-01 mus musculus C57BL/6J RRID:IMSR_JAX:000664
424-
sub-02 mus musculus C57BL/6J RRID:IMSR_JAX:000664
421+
```tsv
422+
participant_id species strain strain_rrid
423+
sub-01 mus musculus C57BL/6J RRID:IMSR_JAX:000664
424+
sub-02 mus musculus C57BL/6J RRID:IMSR_JAX:000664
425425
```
426426

427427
`participants.json` example:

src/modality-specific-files/near-infrared-spectroscopy.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ Note that upper-case is REQUIRED.
294294
### Example `*_channels.tsv`
295295

296296
```tsv
297-
Name type source detector wavelength_nominal units
297+
name type source detector wavelength_nominal units
298298
S1-D1 NIRSCWAMPLITUDE A1 Fz 760 V
299299
S1-D1 NIRSCWAMPLITUDE A1 Fz 850 V
300300
S1-D2 NIRSCWAMPLITUDE A1 Cz 760 V

src/modality-specific-files/physiological-recordings.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ A guide for using macros can be found at
8484

8585
(after decompression)
8686

87-
```tsv
87+
```tsvgz {linenums="1"}
8888
34 110 0
8989
44 112 0
9090
23 100 1

src/modality-specific-files/positron-emission-tomography.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -318,22 +318,22 @@ If recorded once per participant, these data SHOULD be included in the
318318

319319
For example:
320320

321-
```Text
322-
participant_id body_weight
323-
sub-01 58
324-
sub-02 96
325-
sub-03 72
321+
```tsv
322+
participant_id body_weight
323+
sub-01 58
324+
sub-02 96
325+
sub-03 72
326326
```
327327

328328
If multiple measurements are made, these data SHOULD be included in the
329329
[Sessions file](../modality-agnostic-files.md#sessions-file).
330330

331331
For example:
332332

333-
```Text
334-
session_id body_weight
335-
ses-01 58
336-
ses-02 59
333+
```tsv
334+
session_id body_weight
335+
ses-01 58
336+
ses-02 59
337337
```
338338

339339
## Blood recording data

src/modality-specific-files/task-events.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,11 @@ A guide for using macros can be found at
206206

207207
Example of the content of the TSV file:
208208

209-
```Text
210-
onset duration trial_type identifier database response_time
211-
1.2 0.6 afraid AF01AFAF kdef 1.435
212-
5.6 0.6 angry AM01AFAN kdef 1.739
213-
5.6 0.6 sad AF01ANSA kdef 1.739
209+
```tsv
210+
onset duration trial_type identifier database response_time
211+
1.2 0.6 afraid AF01AFAF kdef 1.435
212+
5.6 0.6 angry AM01AFAN kdef 1.739
213+
5.6 0.6 sad AF01ANSA kdef 1.739
214214
```
215215

216216
The `trial_type` and `identifier` columns from the `events.tsv` files might be described

tools/schemacode/src/bidsschematools/render/tsv.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,54 @@
1+
from __future__ import annotations
2+
13
import io
4+
import re
25

36
import pandas as pd
47
from markdown_it import MarkdownIt
58
from tabulate import tabulate
69

710

8-
def fence(source: str, language: str, css_class: str, options: dict, md, **kwargs) -> str:
11+
def fence(
12+
source: str,
13+
language: str,
14+
css_class: str,
15+
options: dict,
16+
md,
17+
classes: list[str],
18+
id_value="",
19+
attrs: dict | None = None,
20+
**kwargs,
21+
) -> str:
22+
attrs = attrs or {}
23+
linenums = attrs.get("linenums", "0") == "1"
24+
25+
if language == "tsvgz" and "header" not in attrs:
26+
attrs["noheader"] = True
27+
28+
classes[:0] = ["tsv-table", "index" if linenums else "noindex"]
29+
930
try:
10-
df = pd.read_csv(io.StringIO(source), sep="\t", dtype=str, keep_default_na=False)
11-
md_table = tabulate(df, headers="keys", tablefmt="github", showindex=False) # type: ignore
31+
df = pd.read_csv(
32+
io.StringIO(source),
33+
sep="\t",
34+
dtype=str,
35+
index_col=False,
36+
keep_default_na=False,
37+
header=None if "noheader" in attrs else "infer",
38+
)
39+
md_table = tabulate(
40+
df, # type: ignore
41+
tablefmt="github",
42+
showindex=linenums,
43+
headers="keys",
44+
numalign="right",
45+
)
1246
html = MarkdownIt("commonmark").enable("table").render(md_table)
47+
if "noheader" in attrs:
48+
html = re.sub("<thead>.+</thead>", "", html, flags=re.DOTALL)
49+
50+
html = html.replace("<table>", f'<table class="{" ".join(classes)}">')
51+
1352
# Remove newlines from HTML to prevent copy-paste from inserting spaces
1453
return html.replace("\n", "")
1554
except Exception:

0 commit comments

Comments
 (0)