Skip to content

Commit afde5b6

Browse files
jcschaffclaude
andcommitted
feat(tutorials): reproduce the Pathway Commons tutorial
The oldest document in the set (2016) and the only one that depends on services outside VCell. The caution its storyline carried - check before investing - is now discharged: both services answer, and the tutorial runs end to end with 0 errors. search https://www.pathwaycommons.org/pc2/search live, API v14 import reactome.org/ReactomeRESTfulAPI/.../Level2/<id> live The script searches, previews a pathway, imports every entity, imports those into the physiology (7 reactions, 26 species, 21 molecules, 21 observables), and links a species of its own to a pathway entity - checking the link took rather than assuming it. The pathway diagram is avoidable, and the PDF says how. Steps 4 and 5 work on a custom canvas - "click a corner of the diagram, drag your cursor over all entities" - but two pages later the same document offers "click Pathway Objects to organize the entities into list form", with the same Physiology Links menu on it. The script takes the list. One thing is fragile enough to name in the storyline: the import uses Reactome's OLD RESTful API, superseded by ContentService, and it answers 400 to a stable R-HSA- identifier. It works only because extractReactomeId strips the prefix and passes the bare number. When the preview comes back empty, that is the URL to check - so the script says so. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019HAnpFxkzf9LmxBayDSANf
1 parent f787d5c commit afde5b6

3 files changed

Lines changed: 228 additions & 11 deletions

File tree

tools/debug-bridge/scenarios/tutorials/README.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ reproduces it against a current client through the [debug bridge](../../README.m
1515
| `FRAPBinding_7.2.pdf` | [frap-with-binding](storylines/frap-with-binding.md) | [`frap-with-binding.sh`](frap-with-binding.sh) | **reproduced** in full, 0 errors |
1616
| `PHGFP_7.2.pdf` | [phgfp](storylines/phgfp.md) | [`phgfp.sh`](phgfp.sh) | **reproduced** in full, 0 errors |
1717
| `MultiAppTransport_7.2.pdf` | [multi-app-transport](storylines/multi-app-transport.md) | [`multi-app-transport.sh`](multi-app-transport.sh) | **reproduced**, 0 errors, two documented substitutions |
18-
| `Tutorial06_PathwayCommons_6.0.pdf` | [pathway-commons](storylines/pathway-commons.md) | | depends on a third-party service |
18+
| `Tutorial06_PathwayCommons_6.0.pdf` | [pathway-commons](storylines/pathway-commons.md) | [`pathway-commons.sh`](pathway-commons.sh) | **reproduced**, 0 errors — both third-party services verified live |
1919
| `VCell_Quickstart_7_Biomodel.pdf` | [quickstart](storylines/quickstart.md) || reference guide, nothing to script |
2020
| `VCell6.1_Rule-Based_Tutorial.pdf` + `SingleCompartmentRuleBased.pdf` | [rule-based-egfr](storylines/rule-based-egfr.md) || **superseded by the 7.7 rewrite** |
2121
| `VCell6.1_Rule-Based_Ran_Transport_Tutorial.pdf` | [rule-based-ran-transport](storylines/rule-based-ran-transport.md) || **superseded by the 7.7 rewrite** |
@@ -31,6 +31,9 @@ tools/debug-bridge/scenarios/tutorials/simple-frap.sh # or moving-boundary.
3131
# Multi-app needs the image stack the PDF tells you to download:
3232
curl -O https://vcell.org/webstart/VCell_Tutorials/7.7/NeuroblastomaStack.tif
3333
tools/debug-bridge/scenarios/tutorials/multi-app-transport.sh ./NeuroblastomaStack.tif
34+
35+
# Pathway Commons needs a network, and two services outside VCell:
36+
tools/debug-bridge/scenarios/tutorials/pathway-commons.sh
3437
```
3538

3639
Each takes a couple of minutes, leaves a complete valid model on screen — and then **runs
@@ -122,6 +125,10 @@ What has no table equivalent, and so is genuinely out of reach:
122125
unmapped `Nuc_background_membrane`. Lowering the threshold takes in enough dim cytoplasm
123126
to enclose the nucleus, and the model then has no warnings at all - which is what the
124127
eraser is for in the PDF.
128+
- **Drawing on the Pathway Diagram** (`PathwayCommons`) — "click a corner of the diagram,
129+
drag your cursor over all entities and release". Avoidable, and the PDF itself says how,
130+
two pages later: *"Click Pathway Objects to organize the entities into list form"*, and
131+
from that list the same `Physiology Links > Import into Physiology…` menu.
125132
- **Drawing a flux reaction.** `Model.createFluxReaction` has exactly one interactive
126133
caller, `ReactionCartoonTool`; the Reactions table can only make SimpleReactions. A
127134
membrane reaction with the same participants is the way round it, and it resolves
@@ -224,6 +231,11 @@ failure — the script reported success and the model was wrong:
224231
for 10s instead of trusting a fixed `sleep`.
225232
- **`SpatialProcessPropertyPanel` called itself `"SpatialObjectPropertyPanel"`** — a
226233
copy-paste slip that gave two different panels the same name.
234+
- **`ctrl+A` had no equivalent for a table.** Several tutorials select a whole page of one
235+
and act on it — "press ctrl+a and click Import > Selected Only". The keystroke is a
236+
statement about the rows the table currently shows, so `trows <selector> 0-` says the
237+
same thing, over the whole table at once. That also disposes of the PDF's "if a pathway
238+
extends to multiple pages, click the right arrow icon and repeat".
227239
- **A pop-up could only be driven one level at a time, and that was not reliable.** A
228240
heavyweight pop-up window left from an earlier pick can stop the next submenu opening at
229241
all, so `Copy As > Spatial > Stochastic` failed at the first level with the pop-up
@@ -260,8 +272,9 @@ the ten shape fields in `AddShapeJPanel`, `EventsTable`, `EventActionsTable`,
260272
`PreviousButton`, `FinishButton`, `DomainRegionsList`, `AutoMergeButton`,
261273
`HistogramPanel`, `HistogramApplyButton`, `ParameterEstimationParametersTable`,
262274
`AddEstimationParameterButton`, `ParameterEstimationResultsTable`, `SolveByCopasiButton`,
263-
`ExperimentalDataMappingTable` and `NumberOfParticlesRadioButton`. `ScrollPaneTable` and
264-
`SortTable` were each used by eight or more panels.
275+
`ExperimentalDataMappingTable`, `NumberOfParticlesRadioButton`, `PathwayPreviewTable`,
276+
`PathwayPreviewImportButton`, `PathwayObjectsTable` and `PhysiologyLinksButton`.
277+
`ScrollPaneTable` and `SortTable` were each used by eight or more panels.
265278

266279
## A finding worth passing to whoever owns the tutorials
267280

@@ -270,6 +283,13 @@ the ten shape fields in `AddShapeJPanel`, `EventsTable`, `EventActionsTable`,
270283
a different solver (SundialsPDE rather than Fully-Implicit). Followed literally, the
271284
tutorial can produce a different simulation than the one it is teaching.
272285

286+
**Pathway Commons works, and the caution in its storyline is now discharged.** Both
287+
services answer: the search goes to the current `pc2` API (v14) and the import pulls BioPAX
288+
from Reactome. One thing is fragile enough to name: the import uses Reactome's *old*
289+
RESTful API, superseded by ContentService, and it answers 400 to a stable `R-HSA-`
290+
identifier — it works only because the client strips the prefix and passes the bare number.
291+
That is the most likely part of this tutorial to break next.
292+
273293
**PH-GFP's spatial half is built with every diffusion constant left at its default**, and
274294
the PDF never mentions them. That is not an omission the script should fix by inventing
275295
numbers, but it is worth an author's attention: the whole point of the spatial application
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#!/usr/bin/env bash
2+
#
3+
# VCell Tutorial: importing from Pathway Commons
4+
#
5+
# Reproduces the storyline of
6+
# vcell.org/webstart/VCell_Tutorials/Tutorial06_PathwayCommons_6.0.pdf.
7+
# See storylines/pathway-commons.md.
8+
#
9+
# The only tutorial in the set that depends on a third-party service staying up, and the
10+
# oldest document in it (2016). Both services it needs are alive: the search goes to
11+
# Pathway Commons' current pc2 API, and the import pulls BioPAX from Reactome.
12+
#
13+
set -euo pipefail
14+
. "$(cd "$(dirname "$0")" && pwd)/_common.sh"
15+
16+
# The search term. The PDF only ever shows screenshots, so this is a choice: "insulin"
17+
# is the example the client's own code comment uses, and it returns a page of small,
18+
# well-formed Reactome pathways.
19+
QUERY="${QUERY:-insulin}"
20+
PATHWAY="${PATHWAY:-Acetylcholine regulates insulin secretion}"
21+
22+
dismiss OK
23+
sleep 1
24+
25+
step "Search Pathway Commons for '$QUERY'"
26+
must tab name=LeftBottomTabbedPane "Pathway Comm" >/dev/null; sleep 2
27+
must settext name=PathwayCommonsSearchTextField "$QUERY" >/dev/null; sleep 1
28+
must click name=PathwayCommonsSearchButton >/dev/null
29+
30+
# A live third-party service, so wait for an answer rather than sleeping on a guess. The
31+
# client caps the search at a 10s connect and a 30s read; this allows for both plus the
32+
# tree being built.
33+
for i in $(seq 1 30); do
34+
sleep 2
35+
HITS=$("$B" findrow name=PathwayCommonsResponseTree "$PATHWAY" \
36+
| python3 -c 'import json,sys;print(json.load(sys.stdin)["row"])')
37+
[ "$HITS" -ge 0 ] && break
38+
done
39+
if [ "${HITS:--1}" -lt 0 ]; then
40+
echo "FATAL: no pathway matching '$PATHWAY' after searching for '$QUERY'." >&2
41+
echo " Pathway Commons is a third party; check that" >&2
42+
echo " https://www.pathwaycommons.org/pc2/search still answers." >&2
43+
exit 1
44+
fi
45+
echo " '$PATHWAY' is row $HITS" >&2
46+
47+
step "Preview it: the pathway's entities, as a table"
48+
must row name=PathwayCommonsResponseTree "$HITS" >/dev/null; sleep 2
49+
must click name=PathwayCommonsPreviewButton >/dev/null
50+
# The import pulls BioPAX Level 2 from Reactome, which is a second third-party service and
51+
# a second thing to wait for rather than sleep on.
52+
for i in $(seq 1 40); do
53+
sleep 2
54+
ROWS=$(curl -s "http://127.0.0.1:9123/tree" | python3 -c '
55+
import json, sys
56+
def walk(n):
57+
if n.get("name") == "PathwayPreviewTable" and n.get("table"):
58+
print(n["table"]["rowCount"]); raise SystemExit
59+
for c in n.get("children") or []:
60+
walk(c)
61+
for root in json.load(sys.stdin):
62+
walk(root)
63+
')
64+
[ "${ROWS:-0}" -gt 0 ] && break
65+
done
66+
if [ "${ROWS:-0}" -eq 0 ]; then
67+
echo "FATAL: the pathway preview stayed empty. The import reads BioPAX from" >&2
68+
echo " https://reactome.org/ReactomeRESTfulAPI/RESTfulWS/biopaxExporter/Level2/" >&2
69+
echo " - check that it still answers." >&2
70+
exit 1
71+
fi
72+
echo " $ROWS entities in '$PATHWAY'" >&2
73+
74+
step "Import every entity - what ctrl+A and Import > Selected Only mean"
75+
# The PDF says "hit ctrl+a" and, for a multi-page pathway, "click the right arrow icon and
76+
# repeat". The keystroke is about the rows the table currently shows, so saying the range
77+
# says the same thing - and it says it for the whole table at once, with no paging.
78+
must trows name=PathwayPreviewTable "0-" >/dev/null; sleep 2
79+
button_menu name=PathwayPreviewImportButton 'Selected Only'; sleep 10
80+
81+
IMPORTED=$("$B" readcell name=PathwayPreviewTable 0 'Imported?' \
82+
| python3 -c 'import json,sys; print(json.load(sys.stdin).get("value"))')
83+
if [ "$IMPORTED" != "true" ]; then
84+
echo "FATAL: the first entity still reads Imported? = $IMPORTED" >&2
85+
exit 1
86+
fi
87+
88+
step "Pathway Objects: the list form, not the diagram"
89+
# This is the whole reason this tutorial is reachable. Steps 4 and 5 of the PDF work on the
90+
# Pathway Diagram - "click a corner of the diagram, drag your cursor over all entities" -
91+
# which is a pixel gesture on a custom canvas. But the PDF itself offers the other route
92+
# two pages later: "click Pathway Objects to organize the entities into list form", and
93+
# from there the same Physiology Links menu. Same statement, addressable.
94+
navselect 'Pathway Objects'; sleep 4
95+
OBJECTS=$(curl -s "http://127.0.0.1:9123/tree" | python3 -c '
96+
import json, sys
97+
def walk(n):
98+
if n.get("name") == "PathwayObjectsTable" and n.get("table"):
99+
print(n["table"]["rowCount"]); raise SystemExit
100+
for c in n.get("children") or []:
101+
walk(c)
102+
for root in json.load(sys.stdin):
103+
walk(root)
104+
')
105+
echo " $OBJECTS pathway objects" >&2
106+
107+
step "Import into the physiology"
108+
must trows name=PathwayObjectsTable "0-" >/dev/null; sleep 2
109+
button_menu name=PhysiologyLinksButton 'Import into Physiology...'; sleep 8
110+
# The dialog lists every interaction and participant it is about to create, and lets the
111+
# expressions be edited first. The tutorial accepts them as they come.
112+
dialog_button 'Import into Physiology' OK; sleep 10
113+
# VCell then reports what it converted. Waiting for that notice is also how we know the
114+
# conversion finished.
115+
answer OK; sleep 8
116+
117+
# The model tree carries the counts in its own labels, which is the shortest honest way
118+
# to say "the physiology has something in it now".
119+
SPECIES=$(curl -s "http://127.0.0.1:9123/tree" | python3 -c '
120+
import json, sys
121+
def walk(n):
122+
if n.get("name") == "bioModelEditorTree" and n.get("tree"):
123+
for row in n["tree"]["rows"]:
124+
if str(row.get("text","")).startswith("Species ("):
125+
print(row["text"]); raise SystemExit
126+
for c in n.get("children") or []:
127+
walk(c)
128+
for root in json.load(sys.stdin):
129+
walk(root)
130+
')
131+
echo " physiology now has $SPECIES" >&2
132+
case "$SPECIES" in
133+
"Species (0)"|"") echo "FATAL: nothing was imported into the physiology" >&2; exit 1 ;;
134+
esac
135+
136+
step "Link a species of your own to a pathway entity"
137+
# The PDF adds this species with the species tool on the reaction diagram. The Species
138+
# table has an "(add new here)" row that does the same thing - it is offered because this
139+
# model has exactly one structure, which is the condition BioModelEditorSpeciesTableModel
140+
# puts on it.
141+
navselect 'Species'; sleep 3
142+
ADD_ROW=$(row name=SpeciesTable '(add new here)' --exact)
143+
must setcell name=SpeciesTable "$ADD_ROW" 0 "Ach_reporter" >/dev/null; sleep 3
144+
must trow name=SpeciesTable "$(row name=SpeciesTable 'Ach_reporter' --exact)" >/dev/null; sleep 3
145+
146+
button_menu name=ModelPathwayLinksButton 'Edit Pathway Links...'; sleep 5
147+
LINKS=$(dialog_table 'Edit Pathway Links')
148+
must setcell "$LINKS" "$(row "$LINKS" 'acetylcholine' --exact --in 'Entity Name')" \
149+
"$(col "$LINKS" 'Link')" true >/dev/null; sleep 2
150+
dialog_button 'Edit Pathway Links' Close; sleep 4
151+
152+
LINKED=$("$B" readcell name=SpeciesTable "$(row name=SpeciesTable 'Ach_reporter' --exact)" 'Link' \
153+
| python3 -c 'import json,sys; print(json.load(sys.stdin).get("value"))')
154+
echo " Ach_reporter is linked to: $LINKED" >&2
155+
if [ "$LINKED" != "acetylcholine" ]; then
156+
echo "FATAL: the pathway link did not take (Link column reads '$LINKED')" >&2
157+
exit 1
158+
fi
159+
160+
step "Done -- pathway searched, previewed, imported, and a species linked to it."

tools/debug-bridge/scenarios/tutorials/storylines/pathway-commons.md

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
- **Source:** `Tutorial06_PathwayCommons_6.0.pdf` (46 pp, 2016-11-01) — the oldest
44
document in the set.
55
- **Superseded by a 7.7 rewrite?** No.
6-
- **Status:** storyline extracted; not scripted, and needs verification before rewriting.
6+
- **Status:** reproduced by [`pathway-commons.sh`](../pathway-commons.sh), 0 errors.
7+
Both third-party services verified live, 2026-09-07.
78

89
## Objective
910

@@ -25,11 +26,47 @@ and link VCell species to pathway entities.
2526
`Pathway Links > Edit Pathway Links…` and the `Link` checkbox column.
2627
7. `Pathway Objects` lists everything imported in table form.
2728

28-
## Caution before reusing this
29+
## The third-party question, answered
2930

30-
This is the only tutorial in the set that depends on a **third-party service** staying up
31-
and keeping its API shape. The client still ships the `Pathway Comm` tab and a
32-
`PathwayCommonsResponseTree` component, so the feature is present — but whether the
33-
remote endpoint still answers was **not verified**, and a 2016 document is the most
34-
likely of the set to be describing something that no longer works. Check the service
35-
before investing in a rewrite.
31+
This is the only tutorial in the set that depends on services outside VCell, and the
32+
caution that used to stand here — *check before investing* — has now been checked. It
33+
needs **two** services, and both answer:
34+
35+
| Service | Endpoint | State |
36+
|---|---|---|
37+
| Pathway Commons search | `https://www.pathwaycommons.org/pc2/search` | live, API v14, 343 hits for `"insulin"` |
38+
| Reactome BioPAX export | `https://reactome.org/ReactomeRESTfulAPI/RESTfulWS/biopaxExporter/Level2/<numeric id>` | live |
39+
40+
The Reactome one is worth a note: that RESTful API is the *old* one, superseded by
41+
ContentService, and it answers **400** to a stable `R-HSA-` identifier. It works because
42+
`extractReactomeId` strips the prefix and passes the bare number, which is what that API
43+
has always taken. It is the most likely part of this tutorial to break next, so the script
44+
says which URL to check when the preview comes back empty.
45+
46+
The panel itself has already been modernised — the search targets the current `pc2` API,
47+
not the `webservice.do` endpoint the 2016 document was written against, and pathway links
48+
open Reactome detail pages. `PathwayCommonsRequest.defaultBaseURL` still names the retired
49+
`http://www.pathwaycommons.org/pc/webservice.do`, but nothing on this path uses it.
50+
51+
## Scripting it: the diagram is avoidable, and the PDF says so
52+
53+
Steps 4 and 5 work on the **Pathway Diagram** — "click a corner of the diagram, drag your
54+
cursor over all entities and release" — which is a pixel gesture on a custom canvas. But
55+
the document itself offers the other route two pages later: *"Click Pathway Objects to
56+
organize the entities into list form"*, and from that list the same
57+
`Physiology Links > Import into Physiology…` menu. The script takes the list.
58+
59+
Everything else is tables and menus:
60+
61+
- `ctrl+a` on a page of the preview table is a **row range** — and a range covers the whole
62+
table at once, so the PDF's "if a pathway extends to multiple pages, click the right
63+
arrow icon and repeat" is not needed.
64+
- the `Link` column in *Edit Pathway Links…* is a checkbox column, which `setCell` can now
65+
tick.
66+
- the species the PDF adds with the species tool comes from the Species table's
67+
`(add new here)` row instead — offered because this model has exactly one structure.
68+
69+
The one choice the script has to make is the search term: the PDF is all screenshots and
70+
never names one. It uses `insulin` (the example in the client's own code) and the pathway
71+
*Acetylcholine regulates insulin secretion*, which is small and well-formed. Both are
72+
overridable with `QUERY=` and `PATHWAY=`.

0 commit comments

Comments
 (0)