opencode-bioresearcher 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +103 -0
- package/agents/bioresearcher-dr-worker.md +54 -0
- package/connector-meta.json +23 -0
- package/index.js +77 -0
- package/loader.js +3 -0
- package/package.json +42 -0
- package/skill-bundle.json +12 -0
- package/skills/bioresearcher-deep-research/SKILL.md +330 -0
- package/skills/bioresearcher-deep-research/references/analysis-methods.md +90 -0
- package/skills/bioresearcher-deep-research/references/article-literature.md +89 -0
- package/skills/bioresearcher-deep-research/references/best-practices.md +102 -0
- package/skills/bioresearcher-deep-research/references/citations.md +146 -0
- package/skills/bioresearcher-deep-research/references/clinical-trials.md +87 -0
- package/skills/bioresearcher-deep-research/references/diseases.md +94 -0
- package/skills/bioresearcher-deep-research/references/drugs.md +88 -0
- package/skills/bioresearcher-deep-research/references/ensembl-pdb.md +134 -0
- package/skills/bioresearcher-deep-research/references/functional-genomics.md +118 -0
- package/skills/bioresearcher-deep-research/references/genes.md +93 -0
- package/skills/bioresearcher-deep-research/references/optional-analysis.md +108 -0
- package/skills/bioresearcher-deep-research/references/patents.md +92 -0
- package/skills/bioresearcher-deep-research/references/rate-limiting-auth.md +95 -0
- package/skills/bioresearcher-deep-research/references/report-template.md +117 -0
- package/skills/bioresearcher-deep-research/references/tool-selection.md +142 -0
- package/skills/bioresearcher-deep-research/references/utility-config.md +116 -0
- package/skills/bioresearcher-deep-research/references/variants.md +109 -0
- package/skills/bioresearcher-deep-research/references/worker-protocol.md +110 -0
- package/skills/bioresearcher-deep-research/scripts/markdown-to-html.py +86 -0
- package/skills/bioresearcher-plot-making/SKILL.md +97 -0
- package/skills/bioresearcher-plot-making/references/literature-search-method-summary.md +163 -0
- package/skills/bioresearcher-plot-making/references/qa-gates-and-gotchas.md +156 -0
- package/skills/bioresearcher-plot-making/references/structural-biology-binder-visualization.md +206 -0
- package/skills/bioresearcher-plot-making/scripts/audit_figure_collisions.py +742 -0
- package/skills/bioresearcher-plot-making/scripts/audit_panel_alignment.py +935 -0
- package/skills/bioresearcher-plot-making/scripts/audit_pdf_text.py +152 -0
- package/skills/bioresearcher-plot-making/scripts/plot_helpers.py +177 -0
- package/skills/bioresearcher-pubmed-weekly/SKILL.md +223 -0
- package/skills/bioresearcher-pubmed-weekly/scripts/parse_updatefiles.py +272 -0
- package/skills/bioresearcher-pubmed-weekly/scripts/pubmed_weekly.py +493 -0
- package/skills/bioresearcher-python-setup-uv/SKILL.md +184 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Literature Search Method Summary Specification
|
|
2
|
+
|
|
3
|
+
This guide specifies the production of publication-grade figures that synthesize complex, heterogeneous biomedical literature, clinical case registers, and preclinical assay cascades into standardized vector graphics.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Provenance Architecture & Verification Protocol
|
|
8
|
+
|
|
9
|
+
Literature syntheses risk metric drift, recall errors, and false categorizations. Enforce strict verification before drawing:
|
|
10
|
+
|
|
11
|
+
1. **NCBI E-Utilities Primary Verification**:
|
|
12
|
+
- Verify every PMID against NCBI E-Utilities (`esummary` / `efetch`).
|
|
13
|
+
- Extract and cross-check official publication year, journal, author list, and compound identifiers.
|
|
14
|
+
- *Case Lesson*: LLM recall frequently confuses adjacent PMIDs (e.g. unrelated papers or case reports). Never transcribe PMIDs from memory.
|
|
15
|
+
2. **Evidence Balance Principle**:
|
|
16
|
+
- For every flagged safety risk or adverse event, include at least one well-tolerated benchmark or counterexample.
|
|
17
|
+
- For uncharacterized areas, include dedicated "evidence gap" indicators (gray markers) rather than omitting the domain.
|
|
18
|
+
3. **Information Partitioning**:
|
|
19
|
+
- **On-Figure**: High-level qualitative hazard descriptors, developmental stage markers, and compact PMID tags (`tag_right(ax, "PMIDs ...", y)`).
|
|
20
|
+
- **In Legends (`LEGENDS.md`)**: Full quantitative cohort sizes, trial names, percentage incidences, and detailed assay parameters.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 2. Declarative Data Contracts
|
|
25
|
+
|
|
26
|
+
Decouple literature curation from matplotlib scripts using structured TSV tables.
|
|
27
|
+
|
|
28
|
+
### Contract A: Developmental Case Register (`literature_cases.tsv`)
|
|
29
|
+
Represents clinical and preclinical benchmark cases mapped across development:
|
|
30
|
+
```tsv
|
|
31
|
+
entity_name structural_tag hazard_description development_stage status pmids
|
|
32
|
+
Agent_Alpha Kinase inhibitor (type II) Grade-3 hepatotoxicity; Phase 3 terminated phase 3 adverse_signal 00000001
|
|
33
|
+
Agent_Beta Kinase inhibitor (type I) Tolerated benchmark; 0% transaminase elevation approved no_signal 00000002
|
|
34
|
+
Agent_Gamma Proteolysis degrader Chronic tissue accumulation; under-reported preclinical under_reported 00000003
|
|
35
|
+
```
|
|
36
|
+
*Valid Stages*: `preclinical | phase 1 | phase 2 | phase 3 | approved`
|
|
37
|
+
*Valid Statuses*: `adverse_signal (red) | no_signal (green) | under_reported (gray)`
|
|
38
|
+
|
|
39
|
+
### Contract B: Preclinical Detection Cascade (`assay_cascade.tsv`)
|
|
40
|
+
Represents orthogonal screening assays arranged in a tiered detection matrix:
|
|
41
|
+
```tsv
|
|
42
|
+
assay_name readout method_family screening_stage pmids
|
|
43
|
+
Reporter gene panel Stress pathway activation flow cytometry preclinical 00000004
|
|
44
|
+
Viability panel Growth inhibition IC50 biochemical in vitro lead 00000005
|
|
45
|
+
Surface plasmon res Binding kinetics biochemical orthogonal screen 00000006
|
|
46
|
+
```
|
|
47
|
+
*Valid Method Families*: `in silico | proteomics | flow cytometry | biochemical | MS bioanalysis | imaging | in vivo`
|
|
48
|
+
|
|
49
|
+
### Contract C: Structured Evidence Matrix (`evidence_table.tsv`)
|
|
50
|
+
Represents single-panel literature landscapes:
|
|
51
|
+
```tsv
|
|
52
|
+
row_id scope_tag citation journal pmid test_system sample_matrix analytical_method readout
|
|
53
|
+
1 core Author 2025 Nat Commun 00000010 Engineered kinase inhibitor A549 cells Phosphoproteomics ERK pathway suppression
|
|
54
|
+
2 protocol Author 2016 Nat Protoc 00000011 Morphological assay HeLa cells High-content imaging Phenotypic feature matrix
|
|
55
|
+
3 transfer Author 2024 Bioorg Chem 00000012 Small-molecule reference HepG2 spheroids LC-MS/MS Off-target binding screen
|
|
56
|
+
```
|
|
57
|
+
*Valid Scope Tags*: `core (amber badge) | protocol (dagger †) | transfer (double dagger ‡) | benchmark`
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 3. Visual Archetype 1: The Three-Panel Composite (180 x 120 mm)
|
|
62
|
+
|
|
63
|
+
The Three-Panel Composite pairs a biological concept schematic with an empirical case register and an assay detection matrix:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
+------------------------------------------+-------------------------------------------+
|
|
67
|
+
| Panel a: Mechanistic Concept Diagram | Panel b: Developmental Case Register |
|
|
68
|
+
| [0.035, 0.355, 0.435, 0.585] | [0.525, 0.355, 0.440, 0.585] |
|
|
69
|
+
| - Topological cellular layout | - Interventions + structural tags |
|
|
70
|
+
| - Membrane bilayers & receptors | - Plain-language hazard summaries |
|
|
71
|
+
| - Compartments: cytosol, lysosome, mito | - Developmental timeline dot axis |
|
|
72
|
+
| - Directional trajectory of risk | - Tri-color status dots (red/green/gray) |
|
|
73
|
+
+------------------------------------------+-------------------------------------------+
|
|
74
|
+
| Panel c: Preclinical Detection Cascade Matrix Strip [0.035, 0.050, 0.930, 0.270] |
|
|
75
|
+
| - Columns: Assay | What it reads out | Method Family Chip (colored) | Typical Stage |
|
|
76
|
+
| - Alternating row banding (#F7F7F7) | Fixed column grid anchors |
|
|
77
|
+
+--------------------------------------------------------------------------------------+
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Layout Rules
|
|
81
|
+
- **Panel a (Mechanics)**: Maintain strict biological topology. Receptors must sit within lipid bilayers with lumen/extracellular orientation preserved. Intracellular routes must terminate in bounded organelle compartments.
|
|
82
|
+
- **Panel b (Cases)**: Position timeline stage columns with alternating baselines ($y = 9.50$ vs $8.98$) to prevent PDF text merging. Stagger rows with a pitch of $1.35$–$1.45$ data units. Directly above the provenance footer, always render the explicit status dot glyph legend:
|
|
83
|
+
```python
|
|
84
|
+
for x_pt, col, lbl in [(0.30, PALETTE["danger"], "adverse signal"),
|
|
85
|
+
(3.40, PALETTE["safe"], "no signal"),
|
|
86
|
+
(6.70, PALETTE["gap"], "under-reported")]:
|
|
87
|
+
axb.plot(x_pt, 0.85, "o", color=col, ms=4.0, mec="white", mew=0.5)
|
|
88
|
+
axb.text(x_pt + 0.25, 0.85, lbl, fontsize=5.2, color=col, fontweight="bold", va="center")
|
|
89
|
+
```
|
|
90
|
+
- **Panel c (Assays)**: Full-width strip with alternating row backgrounds (`#F7F7F7`). Method family chips use rounded boxes (`FancyBboxPatch`, rounding 0.10) with bold 5.2 pt white text. Always include the assay PMID provenance footer at valid data coordinate $y = 0.35$ (inside $[0, 10]$):
|
|
91
|
+
```python
|
|
92
|
+
tag_right(axc, "assay PMIDs: " + " · ".join(unique_pmids), 0.35)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 4. Visual Archetype 2: Single-Panel Structured Evidence Table (180 x 124–128 mm)
|
|
98
|
+
|
|
99
|
+
For emerging literature landscapes, synthesize heterogeneous study designs into an vector-rendered evidence table:
|
|
100
|
+
|
|
101
|
+
- **Single Axis**: `[0.030, 0.035, 0.940, 0.920]`
|
|
102
|
+
- **Header Banner**: Bold thematic title with scope qualification text.
|
|
103
|
+
- **Fixed Column Grid**: Allocate horizontal positions based on data complexity:
|
|
104
|
+
- Column 1: Row index / scope badge
|
|
105
|
+
- Column 2: Citation (`Author YYYY`), Journal, PMID
|
|
106
|
+
- Column 3: Test System / Compound
|
|
107
|
+
- Column 4: Sample Matrix / Cell Type
|
|
108
|
+
- Column 5: Analytical Workflow
|
|
109
|
+
- Column 6: Quantitative / Phenotypic Readout
|
|
110
|
+
- **Font-Aware Text Wrapping**: Wrap multi-line cell entries dynamically using `wrap_cell_text()` to prevent text from overflowing column bounds and failing collision audits.
|
|
111
|
+
- **Taxonomic Footnote**: Include explicit scope exclusions and sample boundaries at the bottom of the table.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 5. Low-Level Matplotlib Engineering Patterns
|
|
116
|
+
|
|
117
|
+
### Dynamic Text Spacing
|
|
118
|
+
Proportional fonts cause character-count heuristics to fail. Always compute inline spacing using `right_edge`:
|
|
119
|
+
```python
|
|
120
|
+
from plot_helpers import right_edge
|
|
121
|
+
|
|
122
|
+
t_name = axb.text(0.15, top - 0.34, case.entity_name, fontsize=6.2, fontweight="bold")
|
|
123
|
+
tag_x = right_edge(axb, t_name) + 0.30
|
|
124
|
+
axb.text(tag_x, top - 0.34, case.structural_tag, fontsize=5.2, color="#5A5A5A")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Provenance Edge Pinning
|
|
128
|
+
Pin citations flush against panel right edges using blended transforms:
|
|
129
|
+
```python
|
|
130
|
+
from plot_helpers import tag_right
|
|
131
|
+
|
|
132
|
+
tag_right(axa, "mechanistic anchors: PMIDs 12345678, 23456789", 0.22)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Eliminating PDF Baseline Merging
|
|
136
|
+
When multiple headers share identical vertical coordinates, PDF extraction tools merge adjacent words into single garbled text runs. Always alternate header baselines:
|
|
137
|
+
```python
|
|
138
|
+
stages = [
|
|
139
|
+
("preclinical", 5.95, 9.50),
|
|
140
|
+
("phase 1", 7.20, 8.98),
|
|
141
|
+
("phase 3", 8.40, 9.50),
|
|
142
|
+
("approved", 9.42, 8.98),
|
|
143
|
+
]
|
|
144
|
+
for name, x, y in stages:
|
|
145
|
+
axb.text(x, y, name, fontsize=5.2, color="#5A5A5A", fontweight="bold", ha="center")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 6. Literature Summary QA Gate Checklist
|
|
151
|
+
|
|
152
|
+
Before certifying any literature summary figure for release, verify:
|
|
153
|
+
|
|
154
|
+
- [ ] Every PMID is validated against NCBI E-Utilities (`esummary`/`efetch`).
|
|
155
|
+
- [ ] At least one tolerated counterexample and any evidence gaps are explicitly displayed.
|
|
156
|
+
- [ ] Script resolves paths via `Path(__file__).resolve().parent`.
|
|
157
|
+
- [ ] Biological topology is correct (bilayers, organelles, flow directions).
|
|
158
|
+
- [ ] Column header baselines are staggered to prevent PDF text merging.
|
|
159
|
+
- [ ] Inline text runs are spaced using `right_edge` dynamic metrics.
|
|
160
|
+
- [ ] Table cells are wrapped using `wrap_cell_text` (no column overflow).
|
|
161
|
+
- [ ] Figure passes `require_matplotlib_panel_alignment` with deviation $\le 1.5\text{ pt}$.
|
|
162
|
+
- [ ] Vector PDF passes `audit_figure_collisions.py` with 0 FAIL.
|
|
163
|
+
- [ ] All rendered text meets the $\ge 5.0\text{ pt}$ font size floor.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Quality Assurance Gates and Hard-Earned Gotchas
|
|
2
|
+
|
|
3
|
+
This guide details the three-layer quality assurance (QA) pipeline and provides the complete catalog of hard-earned scientific plotting gotchas.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. The Three-Layer Quality Assurance Architecture
|
|
8
|
+
|
|
9
|
+
Every figure produced under `bioresearcher-plot-making` must pass three independent verification layers before publication.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
+-----------------------------------------------------------------------------------+
|
|
13
|
+
| LAYER 1: STATIC SOURCE PREFLIGHT (Fast AST Check) |
|
|
14
|
+
| - Verifies rcParams: font.family='sans-serif', font floor >= 5.0 pt |
|
|
15
|
+
| - Verifies vector export: pdf.fonttype=42, svg.fonttype='none' |
|
|
16
|
+
| - Confirms explicit panel alignment gate call in script source |
|
|
17
|
+
+-----------------------------------------------------------------------------------+
|
|
18
|
+
│ PASS
|
|
19
|
+
▼
|
|
20
|
+
+-----------------------------------------------------------------------------------+
|
|
21
|
+
| LAYER 2: RENDER-TIME DETERMINISTIC GEOMETRY GATES |
|
|
22
|
+
| 1. Panel Alignment Gate (scripts/audit_panel_alignment.py): |
|
|
23
|
+
| - Measures panel bounding boxes; enforces max tolerance <= 1.5 pt on rows/cols |
|
|
24
|
+
| - Exports *.alignment.json audit trail and *.alignment.svg overlay |
|
|
25
|
+
| 2. Vector PDF Collision Audit (scripts/audit_figure_collisions.py): |
|
|
26
|
+
| - Detects text-text collisions, text-stroke crossings, canvas clipping |
|
|
27
|
+
| - Enforces 0 FAIL (contained chip/badge fills permitted with WARN review) |
|
|
28
|
+
| 3. Glyph Floor Stream Audit (scripts/audit_pdf_text.py): |
|
|
29
|
+
| - Decodes PDF FlateDecode streams; verifies all 'Tf' font operators >= 5.0 pt |
|
|
30
|
+
+-----------------------------------------------------------------------------------+
|
|
31
|
+
│ PASS
|
|
32
|
+
▼
|
|
33
|
+
+-----------------------------------------------------------------------------------+
|
|
34
|
+
| LAYER 3: VISION-MODEL PERCEPTUAL INSPECTION |
|
|
35
|
+
| - Single-question semantic verification queries |
|
|
36
|
+
| - Evaluates biological topology, pocket illumination, and unoccluded views |
|
|
37
|
+
+-----------------------------------------------------------------------------------+
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 2. Bundled Execution of Layer 2 QA Tools
|
|
43
|
+
|
|
44
|
+
The skill bundles three deterministic audit tools under `scripts/`:
|
|
45
|
+
|
|
46
|
+
### A. Panel Alignment Gate (`audit_panel_alignment.py`)
|
|
47
|
+
Verifies that multi-panel rows and columns align to within $1.5\text{ pt}$:
|
|
48
|
+
```python
|
|
49
|
+
from audit_panel_alignment import require_matplotlib_panel_alignment
|
|
50
|
+
|
|
51
|
+
# Multi-panel composite layout
|
|
52
|
+
require_matplotlib_panel_alignment(
|
|
53
|
+
fig,
|
|
54
|
+
json_out="figure.alignment.json",
|
|
55
|
+
overlay_svg="figure.alignment.svg",
|
|
56
|
+
tolerance_pt=1.5,
|
|
57
|
+
strict=True,
|
|
58
|
+
panel_ids={axa: "a", axb: "b", axc: "c"},
|
|
59
|
+
row_groups=[["a", "b"]],
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Single-panel table layout (invariant: provide panel_ids to generate audit trail)
|
|
63
|
+
require_matplotlib_panel_alignment(
|
|
64
|
+
fig,
|
|
65
|
+
json_out="table.alignment.json",
|
|
66
|
+
overlay_svg="table.alignment.svg",
|
|
67
|
+
tolerance_pt=1.5,
|
|
68
|
+
panel_ids={ax: "a"},
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### B. Vector PDF Collision Audit (`audit_figure_collisions.py`)
|
|
73
|
+
Extracts text and path geometry from exported PDFs using PyMuPDF to flag overlaps:
|
|
74
|
+
```bash
|
|
75
|
+
./.venv/bin/python skills/bioresearcher-plot-making/scripts/audit_figure_collisions.py figure.pdf --json-out figure.collision-audit.json
|
|
76
|
+
```
|
|
77
|
+
- **FAIL Criteria**: Uncontained text-text collisions, text-stroke crossings, or canvas clipping.
|
|
78
|
+
- **WARN Criteria**: Contained text overlays (e.g. text inside colored method family chips).
|
|
79
|
+
|
|
80
|
+
### C. Glyph Size Floor Audit (`audit_pdf_text.py`)
|
|
81
|
+
Parses low-level PDF font definitions to ensure no text falls below $5.0\text{ pt}$:
|
|
82
|
+
```bash
|
|
83
|
+
./.venv/bin/python skills/bioresearcher-plot-making/scripts/audit_pdf_text.py figure.pdf --min-pt 5.0
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 3. The Catalog of Hard-Earned Gotchas
|
|
89
|
+
|
|
90
|
+
### Process & Environment
|
|
91
|
+
1. **Silent CWD Audit Pass Trap**:
|
|
92
|
+
- *Failure*: Saving with relative paths (`fig.pdf`) writes to the process current working directory. Running from repo root writes outputs to root while QA scripts audit stale files in the subfolder.
|
|
93
|
+
- *Fix*: Always resolve paths via `Path(__file__).resolve().parent`.
|
|
94
|
+
2. **Silent Text Patch Failure**:
|
|
95
|
+
- *Failure*: Replacing text coordinates via regex or string replacement fails silently when surrounding lines drift, creating near-duplicate elements that trigger collision failures.
|
|
96
|
+
- *Fix*: Verify exact string replacements; rerun full QA suite after every edit.
|
|
97
|
+
|
|
98
|
+
### 3D Macromolecular Rendering
|
|
99
|
+
3. **Multi-Ligand Clutter**:
|
|
100
|
+
- *Failure*: Superimposing multiple full macromolecular binders completely buries the receptor.
|
|
101
|
+
- *Fix*: Prune binders to contact fragments: `byres ((ligand) within 8.0 of receptor) extend 3`.
|
|
102
|
+
4. **Dark Cavity & Back-Face Voids**:
|
|
103
|
+
- *Failure*: Transparent surfaces produce black internal faces and polygon clipping.
|
|
104
|
+
- *Fix*: Use an opaque soft-gray surface (`#CDCDD4`) with `two_sided_lighting 1`, `ambient 0.50`, and a $+18^\circ$ camera tilt.
|
|
105
|
+
5. **Distorted In-Scene Raster Labels**:
|
|
106
|
+
- *Failure*: PyMOL bitmap text (`cmd.label`) pixelates and scales unpredictably.
|
|
107
|
+
- *Fix*: Run a probe render pass to export 2D projected coordinates (`render_anchors.json`); render native vector text in Matplotlib.
|
|
108
|
+
6. **Multi-Ligand Crystal Mixing**:
|
|
109
|
+
- *Failure*: Co-crystal PDBs containing multiple binders aggregate improperly when filtered only by PDB ID.
|
|
110
|
+
- *Fix*: Key interface extraction on the tuple: `(pdb_id, copy_id, binder_id)`.
|
|
111
|
+
|
|
112
|
+
### Geometry & Axes Alignment
|
|
113
|
+
7. **`aspect='equal'` Letterbox Desync**:
|
|
114
|
+
- *Failure*: `aspect='equal'` letterboxes axes within declared rectangles; row panels silently drift in height by points.
|
|
115
|
+
- *Fix*: Panels sharing a row must have identical physical aspect ratios or use `equal=False`.
|
|
116
|
+
8. **Hidden Rounded-Corner Arcs**:
|
|
117
|
+
- *Failure*: `FancyBboxPatch` corners cut inward; text near rectangular edges collides with curvature strokes.
|
|
118
|
+
- *Fix*: Leave generous internal padding ($> 1.5 \times \text{rounding\_size}$).
|
|
119
|
+
9. **Unclipped Text Spills**:
|
|
120
|
+
- *Failure*: `Patch` artists are clipped to axes by default, but `Text` has `clip_on=False`.
|
|
121
|
+
- *Fix*: Never park text outside declared axes limits; labels spill into neighboring subplots.
|
|
122
|
+
10. **Curved Arrow Apex Bulges**:
|
|
123
|
+
- *Failure*: Curved arrows (`arc3,rad=0.2`) bulge outward; markers on paths get flagged as text-through-stroke.
|
|
124
|
+
- *Fix*: Place badges beside paths, not on them. Keep curvature radius minimal.
|
|
125
|
+
|
|
126
|
+
### Typography & Text Metrics
|
|
127
|
+
11. **Glyph Advance vs Ink Bbox**:
|
|
128
|
+
- *Failure*: `get_window_extent()` only measures drawn ink, ignoring font side bearings; inline text runs collide.
|
|
129
|
+
- *Fix*: Use `right_edge()` combining ink bbox and renderer advance width.
|
|
130
|
+
12. **PDF Text Run Merging**:
|
|
131
|
+
- *Failure*: Adjacent column headers sharing an identical vertical baseline get merged into garbled text runs by PDF parsers.
|
|
132
|
+
- *Fix*: Stagger vertical baselines alternately ($y = 9.50$ vs $8.98$).
|
|
133
|
+
13. **Legend Accumulation Drift**:
|
|
134
|
+
- *Failure*: Chaining dynamic text measurements sequentially across horizontal legends accumulates errors.
|
|
135
|
+
- *Fix*: For static legend items, use fixed relative offsets rather than chained dynamic measurements.
|
|
136
|
+
14. **Multi-Line Independent Centering Spill**:
|
|
137
|
+
- *Failure*: Multi-line text with `ha='center'` centers each line independently; one long line breaks container bounds and clips or collides with adjacent strokes.
|
|
138
|
+
- *Fix*: Keep line lengths balanced or compute explicit block centering using `wrap_cell_text()`.
|
|
139
|
+
|
|
140
|
+
### Data Synthesis & Quantitative Mechanics
|
|
141
|
+
15. **In-Plot Mean Box Collisions**:
|
|
142
|
+
- *Failure*: Placing a mean baseline text box inside a profile plot collides with high data spikes.
|
|
143
|
+
- *Fix*: Remove in-plot box; integrate mean label directly into y-axis tick labels (`f"{mean:.2f}\n(mean)"`).
|
|
144
|
+
16. **Manual Callout Coordinate Drift**:
|
|
145
|
+
- *Failure*: Manually placing peak callout arrows leads to arrows pointing at sub-peaks or background noise.
|
|
146
|
+
- *Fix*: Compute callout coordinates via algorithmic peak picking (`np.argmax(...)`).
|
|
147
|
+
|
|
148
|
+
### Vision Model Inspection
|
|
149
|
+
17. **Vision LLM Timeout on Complex Prompts**:
|
|
150
|
+
- *Failure*: Asking multiple visual questions in one prompt causes timeouts and hallucinations.
|
|
151
|
+
- *Fix*: Ask single-question, short prompts sequentially. Trust measured PDF coordinates for geometry.
|
|
152
|
+
|
|
153
|
+
### Synchronized Multi-Panel Plots
|
|
154
|
+
18. **`imshow` vs `barh` Vertical Inversion & Row Drift**:
|
|
155
|
+
- *Failure*: Matplotlib `imshow` defaults to top-to-bottom (`origin="upper"`), whereas `barh` plots bottom-to-top. Furthermore, default 5% axis margins cause horizontal bar centers to drift by multiple points from heatmap rows.
|
|
156
|
+
- *Fix*: Invert y-coordinates (`y_pos = np.arange(n)[::-1]`) AND explicitly set `ax.set_ylim(-0.5, n - 0.5)` to eliminate vertical row drift.
|
package/skills/bioresearcher-plot-making/references/structural-biology-binder-visualization.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Structural Biology Binder Visualization Specification
|
|
2
|
+
|
|
3
|
+
This guide specifies the production of publication-grade figures for protein–binder complexes, conformational plasticity, and multi-ligand interaction landscapes.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Domain Abstraction: The Entity-State-Topology-Matrix (ESTM) Model
|
|
8
|
+
|
|
9
|
+
To keep visualization pipelines target-agnostic, abstract concrete biological entities into four standardized roles:
|
|
10
|
+
|
|
11
|
+
1. **Target Receptor Entity**:
|
|
12
|
+
- **Primary Subunit**: Functional or catalytic chain carrying core interaction domains.
|
|
13
|
+
- **Secondary Subunit**: Heterodimer partner, invariant light chain, or structural scaffold.
|
|
14
|
+
- **Domain Architecture**: Contiguous residue intervals defining structural subdomains.
|
|
15
|
+
2. **Conformational & Dynamic States**:
|
|
16
|
+
- **Reference State**: Apo, resting, wild-type, or physiological baseline structure.
|
|
17
|
+
- **Perturbed State**: Holo, active, acidic/basic, mutant, or simulated conformation.
|
|
18
|
+
- **Displacement Metric**: Euclidean vector displacement ($\Delta r_i = \|\mathbf{r}_i^{\text{state}_2} - \mathbf{r}_i^{\text{state}_1}\|_2$) or root-mean-square fluctuation (RMSF).
|
|
19
|
+
3. **Binder Modality Registry**:
|
|
20
|
+
- Modalities: Monoclonal antibodies/Fabs, engineered scaffold proteins, cyclic/linear peptides, small molecules.
|
|
21
|
+
- Status: Active lead, preclinical benchmark, terminated/failed candidate, evidence gap.
|
|
22
|
+
4. **Interaction Hotspot Topology**:
|
|
23
|
+
- Consensus Sites: Spatially segregated binding pockets (e.g. Site 1, Site 2).
|
|
24
|
+
- Interaction Dimensions: Continuous buried surface area (BSA) and discrete non-covalent contacts (hydrogen bonds, salt bridges).
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Declarative Data Contracts
|
|
29
|
+
|
|
30
|
+
Decouple scientific data curation from rendering code by adhering to strict TSV/JSON schemas.
|
|
31
|
+
|
|
32
|
+
### Contract A: Conformer Dynamics (`conformer_rmsf.tsv`)
|
|
33
|
+
Stores per-residue C$\alpha$ displacement between structural states:
|
|
34
|
+
```tsv
|
|
35
|
+
resnum resname chain_id chain_role domain displacement_A b_factor
|
|
36
|
+
10 ALA A Primary Domain1 0.4500 42.10
|
|
37
|
+
11 GLY A Primary Domain1 0.3200 38.50
|
|
38
|
+
90 ASP A Primary Domain2 0.2150 22.40
|
|
39
|
+
2 VAL B Secondary Scaffold 0.4120 18.20
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Contract B: Binder Hotspot Matrix (`binder_hotspot_matrix.tsv`)
|
|
43
|
+
Composite column headers `<site>:<residue>` enable automatic generation of vertical partition dividers and site header chips. Cells use triple-encoding: `BSA_A2|HBOND_FLAG|SALTBRIDGE_FLAG`:
|
|
44
|
+
```tsv
|
|
45
|
+
binder_name modality target_site Site1:R101 Site1:D105 Site2:K201 Site2:E204
|
|
46
|
+
Binder_Fab_1 FAB Site1 112.5|1|0 84.2|1|0 0.0|0|0 0.0|0|0
|
|
47
|
+
Binder_Fc_2 FC Site1 46.3|1|0 107.7|0|0 0.0|0|0 0.0|0|0
|
|
48
|
+
Binder_Protein_3 PROTEIN Site2 0.0|0|0 0.0|0|0 188.3|1|0 0.0|0|0
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Contract C: Binder Summary Metrics (`binder_summary_data.tsv`)
|
|
52
|
+
Stores energetic metrics partitioned by receptor subunit:
|
|
53
|
+
```tsv
|
|
54
|
+
binder_id binder_name modality target_site bsa_primary bsa_secondary bsa_total n_hbonds n_saltbridges
|
|
55
|
+
PDB1 Binder_Fab_1 FAB Site1 520.0 80.0 600.0 4 0
|
|
56
|
+
PDB2 Binder_Fc_2 FC Site1 310.0 22.0 332.0 2 1
|
|
57
|
+
PDB3 Binder_Protein_3 PROTEIN Site2 640.0 90.0 730.0 6 2
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Contract D: Projected Chain Anchors (`render_anchors.json`)
|
|
61
|
+
Stores 2D projection coordinates $(c_x, c_y)$ extracted from PyMOL camera probe passes:
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"frame": [2200, 1500],
|
|
65
|
+
"chain_labels": {
|
|
66
|
+
"primary": {
|
|
67
|
+
"display_text": "Primary Subunit",
|
|
68
|
+
"cx": 0.85,
|
|
69
|
+
"cy": 0.50,
|
|
70
|
+
"side": "right"
|
|
71
|
+
},
|
|
72
|
+
"secondary": {
|
|
73
|
+
"display_text": "Secondary Subunit",
|
|
74
|
+
"cx": 0.15,
|
|
75
|
+
"cy": 0.50,
|
|
76
|
+
"side": "left"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 3. Headless PyMOL Orchestration Protocol
|
|
85
|
+
|
|
86
|
+
Run PyMOL directly from the project-local uv environment (`./uv venv .venv` once, then `VIRTUAL_ENV="$(pwd)/.venv" ./uv pip install pymol-open-source`).
|
|
87
|
+
Execution modes:
|
|
88
|
+
- **Python API**: Run scripts using `./.venv/bin/python script.py` with `from pymol import cmd`.
|
|
89
|
+
- **Virtualenv CLI**: Run standalone PyMOL scripts via `./.venv/bin/pymol -cq script.py`.
|
|
90
|
+
|
|
91
|
+
Adhere to these essential rendering rules:
|
|
92
|
+
|
|
93
|
+
### A. Contact-Fragment Pruning & Ligand Display
|
|
94
|
+
Superimposing full-length macromolecular complexes buries the receptor. Prune protein binders to contact interfaces:
|
|
95
|
+
```python
|
|
96
|
+
# Select residues within 8.0 Angstroms of receptor, extend by 3 residues for ribbon continuity
|
|
97
|
+
frag_sel = f"byres (({ligand_obj} and ({ligand_chains})) within 8.0 of ({receptor_obj}))"
|
|
98
|
+
cmd.select(f"frag_{code}", f"byres (({frag_sel}) extend 3)")
|
|
99
|
+
cmd.show("cartoon", f"frag_{code}")
|
|
100
|
+
|
|
101
|
+
# Small molecules / covalent inhibitors: show in sticks with element coloring (orange carbons)
|
|
102
|
+
cmd.show("sticks", f"{ligand_obj} and not polymer")
|
|
103
|
+
cmd.color("orange", f"{ligand_obj} and name C*")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### B. Camera Orientation Modes (Disentangled)
|
|
107
|
+
|
|
108
|
+
Disentangle the camera framing based on panel objective:
|
|
109
|
+
|
|
110
|
+
- **Mode A (Conformational Ribbon Superposition)**:
|
|
111
|
+
Used when comparing structural states (apo vs holo, active vs inactive) to view secondary structure without cavity foreshortening:
|
|
112
|
+
```python
|
|
113
|
+
cmd.orient("ref_structure")
|
|
114
|
+
cmd.turn("y", 20)
|
|
115
|
+
cmd.turn("x", -10)
|
|
116
|
+
cmd.zoom("ref_structure", buffer=2.5)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- **Mode B (Cavity Hotspot Surface)**:
|
|
120
|
+
Used when orienting an opaque receptor surface directly into an interior binding pocket:
|
|
121
|
+
```python
|
|
122
|
+
import numpy as np
|
|
123
|
+
|
|
124
|
+
c_site = np.array(cmd.centerofmass(site_selection))
|
|
125
|
+
c_rec = np.array(cmd.centerofmass(receptor_selection))
|
|
126
|
+
|
|
127
|
+
# Calculate outward normal vector
|
|
128
|
+
Z = (c_site - c_rec) / np.linalg.norm(c_site - c_rec)
|
|
129
|
+
up = np.array([0.0, 0.0, 1.0])
|
|
130
|
+
if abs(np.dot(up, Z)) > 0.9:
|
|
131
|
+
up = np.array([0.0, 1.0, 0.0])
|
|
132
|
+
X = np.cross(up, Z); X /= np.linalg.norm(X)
|
|
133
|
+
Y = np.cross(Z, X)
|
|
134
|
+
R = np.array([X, Y, Z])
|
|
135
|
+
|
|
136
|
+
# Apply transform with focal standoff distance and interior tilt
|
|
137
|
+
o = c_rec - 180.0 * Z
|
|
138
|
+
cmd.set_view(tuple(R.flatten().tolist() + o.tolist() + list(cmd.get_view()[12:])))
|
|
139
|
+
cmd.turn("x", 18) # 18-degree tilt illuminates binding pocket interior
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### C. Studio Lighting & Surface Geometry
|
|
143
|
+
Prevent black back-face artifacts and polygonal facets:
|
|
144
|
+
```python
|
|
145
|
+
cmd.set("antialias", 2)
|
|
146
|
+
cmd.set("cartoon_sampling", 2)
|
|
147
|
+
cmd.set("two_sided_lighting", 1) # Eliminates dark cavity back-faces
|
|
148
|
+
cmd.set("ray_shadows", 0) # Disables harsh interior drop-shadows
|
|
149
|
+
cmd.set("ambient", 0.50) # Fills deep pockets evenly
|
|
150
|
+
cmd.set("direct", 0.60)
|
|
151
|
+
cmd.set("hash_max", 300) # High tessellation prevents polygon facets
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### D. The Probe Render Pass for Vector Text Anchors
|
|
155
|
+
Never use PyMOL bitmap text (`cmd.label`) in final publication figures. Execute a labels-only probe pass to export 2D projected anchor coordinates (`render_anchors.json`), then render sharp vector text in Matplotlib within dedicated padding gutters (`LABEL_PAD = 210 px`).
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 4. 2D Matplotlib Compositing Architecture
|
|
160
|
+
|
|
161
|
+
### Layout Decoupling
|
|
162
|
+
1. **Header Strips**: Place panel letters (`a`, `b`) and state tags in dedicated thin header axes (`height 0.040`) above 3D views.
|
|
163
|
+
2. **Side Legend Columns**: Place color keys and modality chips in separate vertical axes flanking the 3D views.
|
|
164
|
+
3. **Content Bounding-Box Cropping**: Load transparent 3D renders using `load_render_cropped(png_path, pad=(210, 12, 210, 12))` to reserve lateral margins for vector labels while maximizing structural scale.
|
|
165
|
+
|
|
166
|
+
### Quantitative Plot Mechanics (Derived from Case Studies)
|
|
167
|
+
- **1D Profile with Peak Callouts**: Callout dots must be positioned at true mathematical local maxima using windowed argmax (`np.argmax(...)`). Mean baseline must be integrated into y-axis tick labels (`f"{mean:.2f}\n(mean)"`) to prevent collision with data spikes. Callout text must be offset sufficiently from shaded region boundaries to avoid text-fill-edge warnings.
|
|
168
|
+
- **Native Glyph Legend**: Bind glyphs directly to labels using Matplotlib's native legend placed beneath Panel c:
|
|
169
|
+
```python
|
|
170
|
+
axc.plot([], [], marker="o", color="#1A1A1A", ls="none", markersize=3.0, label="H-bond")
|
|
171
|
+
axc.plot([], [], marker="^", color="#1B6CA8", ls="none", markersize=3.5, label="Salt bridge")
|
|
172
|
+
axc.legend(loc="upper left", bbox_to_anchor=(0.0, -0.22), ncol=2, fontsize=5.2, frameon=False)
|
|
173
|
+
```
|
|
174
|
+
- **Horizontal Colorbar Inset**: Place colorbar horizontally beneath the matrix beside the glyph legend (never vertical across heatmap rows):
|
|
175
|
+
```python
|
|
176
|
+
cb_ax = fig.add_axes([0.32, 0.025, 0.15, 0.015])
|
|
177
|
+
cb = mpl.colorbar.ColorbarBase(cb_ax, cmap=cmap, norm=norm, orientation="horizontal")
|
|
178
|
+
cb_ax.text(1.06, 0.5, "BSA per residue (Ų)", transform=cb_ax.transAxes, fontsize=5.2, va="center", ha="left")
|
|
179
|
+
# Always pass cb_ax to exclude_axes in export_publication_figure
|
|
180
|
+
```
|
|
181
|
+
- **Gotcha 18: Heatmap & Bar Chart Row Synchronization**: Matplotlib `imshow` defaults to top-to-bottom (`origin="upper"`), whereas `barh` plots bottom-to-top. To keep horizontal bars aligned with heatmap rows and eliminate vertical row drift:
|
|
182
|
+
```python
|
|
183
|
+
y_pos_rev = np.arange(n)[::-1]
|
|
184
|
+
axd.barh(y_pos_rev, bsa_vals, ...)
|
|
185
|
+
axd.set_ylim(-0.5, n - 0.5) # Mandatory: prevents Matplotlib 5% margin row drift
|
|
186
|
+
```
|
|
187
|
+
- **Panel d Title & Labeling**: Set `axd.set_title("Total Interface BSA (Ų)", fontsize=6.5, fontweight="bold", pad=3)` and `axd.set_xlabel("Interface BSA (Ų)", fontsize=6.2)`.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 5. Structural Biology QA Gate Checklist
|
|
192
|
+
|
|
193
|
+
Before finalizing any binder visualization figure, verify:
|
|
194
|
+
|
|
195
|
+
- [ ] PDB structures, chain identifiers, and sequence indexing are confirmed against primary records.
|
|
196
|
+
- [ ] Working directory is resolved via `Path(__file__).resolve().parent`.
|
|
197
|
+
- [ ] Ray-traced PNGs are high-resolution ($\ge 2200 \times 1600\text{ px}$) with `antialias 2`.
|
|
198
|
+
- [ ] No titles, colorbars, or text labels sit inside 3D render panels.
|
|
199
|
+
- [ ] Chain annotations are rendered as vector text in Matplotlib using `render_anchors.json`.
|
|
200
|
+
- [ ] Macromolecular binders are pruned to contact fragments ($\le 8\text{ Å}$ from receptor $+ 3\text{ residues}$).
|
|
201
|
+
- [ ] Surface is opaque with `two_sided_lighting 1` and $+18^\circ$ camera tilt (no black back-faces).
|
|
202
|
+
- [ ] Peak callouts in sequence profiles use algorithmic windowed peak picking.
|
|
203
|
+
- [ ] Stacked BSA bar totals equal the exact sum of partitioned chain values.
|
|
204
|
+
- [ ] Figure passes `require_matplotlib_panel_alignment` with deviation $\le 1.5\text{ pt}$.
|
|
205
|
+
- [ ] Exported vector PDF passes `audit_figure_collisions.py` with 0 FAIL.
|
|
206
|
+
- [ ] Font size audit passes $\ge 5.0\text{ pt}$ floor across all text elements.
|