Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Extend scRNA-seq developmental trajectories with BulkTrajBlend by generating intermediate cells from bulk RNA-seq, training beta-VAE and GNN models, and interpolating missing states.
.claude/skills/bulktrajblend-trajectory-interpolation/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | -4% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -20% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 12% | 0% |
| case-07 | ✗→✓ | ▲ Improved | -10% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 16% | 0% |
Invoke this skill when users need to bridge gaps in single-cell developmental trajectories using matched bulk RNA-seq. It follows t_bulktrajblend.ipynb, showcasing how BulkTrajBlend deconvolves PDAC bulk samples, identifies overlapping communities with a GNN, and interpolates "interrupted" cell states.
omicverse as ov, scanpy as sc, scvelo as scv, and helper functions like from omicverse.utils import mde; run ov.plot_set().scv.datasets.dentategyrus()) and raw bulk counts with ov.utils.read(...) followed by ov.bulk.Matrix_ID_mapping(...) for gene ID harmonisation.ov.bulk2single.BulkTrajBlend(bulk_seq=bulk_df, single_seq=adata, bulk_group=['dg_d_1','dg_d_2','dg_d_3'], celltype_key='clusters').bulk_group names correspond to raw bulk columns and the method expects unscaled counts.bulktb.vae_configure(cell_target_num=100) (or pass a dictionary) to define expected cell counts per cluster. Mention that omitting the argument triggers TAPE-based estimation.bulktb.vae_train(batch_size=512, learning_rate=1e-4, hidden_size=256, epoch_num=3500, vae_save_dir='...', vae_save_name='dg_btb_vae', generate_save_dir='...', generate_save_name='dg_btb').bulktb.vae_load('.../dg_btb_vae.pth') and the need to regenerate cells with consistent random seeds for reproducibility.bulktb.vae_generate(leiden_size=25) and inspect compositions with ov.bulk2single.bulk2single_plot_cellprop(...).adata.write_h5ad).bulktb.gnn_configure(max_epochs=2000, use_rep='X', neighbor_rep='X_pca', gpu=0, ...) to set hyperparameters.bulktb.gnn_train(); reload checkpoints with bulktb.gnn_load('save_model/gnn.pth').bulktb.gnn_generate().bulktb.nocd_obj.adata.obsm['X_mde'] = mde(bulktb.nocd_obj.adata.obsm['X_pca']).sc.pl.embedding(..., color=['clusters','nocd_n'], palette=ov.utils.pyomic_palette()) and filtered subsets excluding synthetic labels with hyphens.bulktb.interpolation('OPC') (replace with target lineage) to synthesise continuity, then preprocess the interpolated AnnData (HVG selection, scaling, PCA).mde, visualise with ov.utils.embedding, and compare to the original atlas.ov.single.pyVIA on both original and interpolated data to derive pseudotime, followed by get_pseudotime, sc.pp.neighbors, ov.utils.cal_paga, and ov.utils.plot_paga for topology validation.learning_rate or reduce hidden_size.gnn_train; regenerating cells changes the graph and can break checkpoint loading.cell_target_num thresholds or a smaller leiden_size filter to retain rare populations.t_bulktrajblend.ipynbomicverse_guide/docs/Tutorials-bulk2single/data/reference.md| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 17,982 | 11,147 | -38% | 1 | 1 | 0% | 3,696 | 3,532 | -4% | 0 | 0 | — |
case-02 | fail→pass | 17,146 | 8,832 | -48% | 1 | 1 | 0% | 3,410 | 2,718 | -20% | 0 | 0 | — |
case-03 | fail→pass | 15,765 | 11,738 | -26% | 1 | 1 | 0% | 3,255 | 3,659 | +12% | 0 | 0 | — |
case-04 | fail→fail | 15,635 | 10,991 | -30% | 1 | 1 | 0% | 2,668 | 3,754 | +41% | 0 | 0 | — |
case-05 | fail→fail | 15,080 | 8,647 | -43% | 1 | 1 | 0% | 2,859 | 2,908 | +2% | 0 | 0 | — |
case-06 | fail→fail | 17,881 | 11,062 | -38% | 1 | 1 | 0% | 3,286 | 3,353 | +2% | 0 | 0 | — |
case-07 | fail→pass | 15,655 | 5,462 | -65% | 1 | 1 | 0% | 2,511 | 2,269 | -10% | 0 | 0 | — |
case-08 | fail→pass | 9,592 | 4,810 | -50% | 1 | 1 | 0% | 1,815 | 2,097 | +16% | 0 | 0 | — |
case-09 | fail→pass | 7,928 | 2,622 | -67% | 1 | 1 | 0% | 1,564 | 1,750 | +12% | 0 | 0 | — |
case-10 | fail→pass | 13,255 | 2,779 | -79% | 1 | 1 | 0% | 2,459 | 1,691 | -31% | 0 | 0 | — |
case-11 | fail→pass | 9,603 | 1,980 | -79% | 1 | 1 | 0% | 1,685 | 1,575 | -7% | 0 | 0 | — |
case-12 | fail→pass | 17,131 | 6,189 | -64% | 1 | 1 | 0% | 2,823 | 2,287 | -19% | 0 | 0 | — |
case-13 | fail→pass | 20,018 | 2,773 | -86% | 1 | 1 | 0% | 1,558 | 1,725 | +11% | 0 | 0 | — |
case-14 | fail→fail | 7,600 | 2,720 | -64% | 1 | 1 | 0% | 1,565 | 1,713 | +9% | 0 | 0 | — |
case-15 | fail→fail | 14,182 | 5,628 | -60% | 1 | 1 | 0% | 2,487 | 2,210 | -11% | 0 | 0 | — |
case-16 | fail→fail | 13,902 | 5,777 | -58% | 1 | 1 | 0% | 2,528 | 2,336 | -8% | 0 | 0 | — |
case-17 | fail→pass | 14,921 | 5,464 | -63% | 1 | 1 | 0% | 2,438 | 2,219 | -9% | 0 | 0 | — |
case-18 | fail→pass | 12,254 | 2,641 | -78% | 1 | 1 | 0% | 2,414 | 1,754 | -27% | 0 | 0 | — |
case-19 | fail→pass | 13,754 | 3,117 | -77% | 1 | 1 | 0% | 2,486 | 1,775 | -29% | 0 | 0 | — |
case-20 | fail→pass | 9,652 | 2,159 | -78% | 1 | 1 | 0% | 1,805 | 1,481 | -18% | 0 | 0 | — |
case-21 | fail→pass | 8,231 | 1,820 | -78% | 1 | 1 | 0% | 1,301 | 1,579 | +21% | 0 | 0 | — |
case-22 | fail→pass | 15,201 | 3,153 | -79% | 1 | 1 | 0% | 2,615 | 1,818 | -30% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +73 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.