medsci-skills 4.1.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.
Files changed (702) hide show
  1. package/LICENSE +50 -0
  2. package/README.md +602 -0
  3. package/README_FIRST.md +27 -0
  4. package/bin/medsci-skills.js +159 -0
  5. package/installers/install-macos.command +19 -0
  6. package/installers/install-windows.cmd +26 -0
  7. package/installers/install-windows.ps1 +17 -0
  8. package/installers/install.py +218 -0
  9. package/metadata/skills_catalog.json +452 -0
  10. package/package.json +48 -0
  11. package/skills/academic-aio/SKILL.md +408 -0
  12. package/skills/academic-aio/references/case_studies/kjr_mllm_2025.md +82 -0
  13. package/skills/academic-aio/references/checklists/AIO_GENERAL.md +354 -0
  14. package/skills/academic-aio/references/journal_summarybox_templates.yaml +126 -0
  15. package/skills/academic-aio/references/oac_funding_checklist.yaml +129 -0
  16. package/skills/academic-aio/references/reporting_guideline_mapping.md +39 -0
  17. package/skills/academic-aio/references/schema_markup_templates/CodeRepository.jsonld +32 -0
  18. package/skills/academic-aio/references/schema_markup_templates/Dataset.jsonld +36 -0
  19. package/skills/academic-aio/references/schema_markup_templates/Person.jsonld +30 -0
  20. package/skills/academic-aio/references/schema_markup_templates/README.md +43 -0
  21. package/skills/academic-aio/references/schema_markup_templates/ScholarlyArticle.jsonld +55 -0
  22. package/skills/academic-aio/scripts/batch_metadata_audit.py +169 -0
  23. package/skills/academic-aio/scripts/validate_schema.py +118 -0
  24. package/skills/academic-aio/skill.yml +36 -0
  25. package/skills/academic-aio/templates/aio_audit_checklist.md.j2 +108 -0
  26. package/skills/add-journal/SKILL.md +482 -0
  27. package/skills/add-journal/skill.yml +33 -0
  28. package/skills/analyze-stats/SKILL.md +598 -0
  29. package/skills/analyze-stats/references/analysis_guides/missing_data.md +109 -0
  30. package/skills/analyze-stats/references/analysis_guides/nhis_icd10_mapping.md +247 -0
  31. package/skills/analyze-stats/references/analysis_guides/propensity_score.md +132 -0
  32. package/skills/analyze-stats/references/analysis_guides/regression.md +115 -0
  33. package/skills/analyze-stats/references/analysis_guides/repeated_measures.md +160 -0
  34. package/skills/analyze-stats/references/analysis_guides/survey_weighted.md +366 -0
  35. package/skills/analyze-stats/references/analysis_guides/test_selection.md +86 -0
  36. package/skills/analyze-stats/references/style/figure_style.mplstyle +69 -0
  37. package/skills/analyze-stats/references/style/theme_publication.R +147 -0
  38. package/skills/analyze-stats/references/table-standards/journal-profiles/ajr.yaml +51 -0
  39. package/skills/analyze-stats/references/table-standards/journal-profiles/european_radiology.yaml +55 -0
  40. package/skills/analyze-stats/references/table-standards/journal-profiles/jama.yaml +66 -0
  41. package/skills/analyze-stats/references/table-standards/journal-profiles/lancet.yaml +57 -0
  42. package/skills/analyze-stats/references/table-standards/journal-profiles/nejm.yaml +51 -0
  43. package/skills/analyze-stats/references/table-standards/journal-profiles/radiology.yaml +66 -0
  44. package/skills/analyze-stats/references/table-standards/table-standards.md +287 -0
  45. package/skills/analyze-stats/references/table-standards/table-types/diagnostic_accuracy.md +36 -0
  46. package/skills/analyze-stats/references/table-standards/table-types/meta_analysis.md +58 -0
  47. package/skills/analyze-stats/references/table-standards/table-types/model_comparison.md +36 -0
  48. package/skills/analyze-stats/references/table-standards/table-types/regression_results.md +50 -0
  49. package/skills/analyze-stats/references/table-standards/table-types/table1_demographics.md +51 -0
  50. package/skills/analyze-stats/references/table-standards/tool-comparison.md +79 -0
  51. package/skills/analyze-stats/references/templates/agreement_analysis.py +436 -0
  52. package/skills/analyze-stats/references/templates/dca_plot.R +237 -0
  53. package/skills/analyze-stats/references/templates/diagnostic_accuracy.py +401 -0
  54. package/skills/analyze-stats/references/templates/dta_meta_analysis.R +384 -0
  55. package/skills/analyze-stats/references/templates/forest_plot.py +412 -0
  56. package/skills/analyze-stats/references/templates/likert_summary.py +356 -0
  57. package/skills/analyze-stats/references/templates/meta_analysis.R +365 -0
  58. package/skills/analyze-stats/references/templates/propensity_score.py +478 -0
  59. package/skills/analyze-stats/references/templates/regression.py +425 -0
  60. package/skills/analyze-stats/references/templates/repeated_measures.py +434 -0
  61. package/skills/analyze-stats/references/templates/sample_size.R +382 -0
  62. package/skills/analyze-stats/references/templates/survey_weighted_analysis.py +411 -0
  63. package/skills/analyze-stats/references/templates/survival_analysis.py +325 -0
  64. package/skills/analyze-stats/references/templates/table1_demographics.py +287 -0
  65. package/skills/analyze-stats/scripts/check_generated_code.py +335 -0
  66. package/skills/analyze-stats/skill.yml +38 -0
  67. package/skills/analyze-stats/tests/fixtures/gen_bad.R +16 -0
  68. package/skills/analyze-stats/tests/fixtures/gen_bad.py +24 -0
  69. package/skills/analyze-stats/tests/fixtures/gen_clean.py +21 -0
  70. package/skills/analyze-stats/tests/test_generated_code.sh +59 -0
  71. package/skills/analyze-stats/tests/test_survival_template.sh +53 -0
  72. package/skills/author-strategy/SKILL.md +117 -0
  73. package/skills/author-strategy/analyze_patterns.py +303 -0
  74. package/skills/author-strategy/fetch_pubmed.py +374 -0
  75. package/skills/author-strategy/skill.yml +34 -0
  76. package/skills/batch-cohort/SKILL.md +223 -0
  77. package/skills/batch-cohort/references/base_template_knhanes.R +210 -0
  78. package/skills/batch-cohort/references/batch_template_generator.R +222 -0
  79. package/skills/batch-cohort/references/variable_coding_registry.md +136 -0
  80. package/skills/batch-cohort/skill.yml +35 -0
  81. package/skills/calc-sample-size/SKILL.md +491 -0
  82. package/skills/calc-sample-size/references/formulas.md +655 -0
  83. package/skills/calc-sample-size/references/observational_cohort.md +49 -0
  84. package/skills/calc-sample-size/skill.yml +51 -0
  85. package/skills/check-reporting/SKILL.md +534 -0
  86. package/skills/check-reporting/references/LICENSES.md +41 -0
  87. package/skills/check-reporting/references/checklists/AMSTAR2.md +54 -0
  88. package/skills/check-reporting/references/checklists/ARRIVE_2.md +234 -0
  89. package/skills/check-reporting/references/checklists/CARE.md +102 -0
  90. package/skills/check-reporting/references/checklists/CLAIM_2024.md +128 -0
  91. package/skills/check-reporting/references/checklists/CLEAR.md +113 -0
  92. package/skills/check-reporting/references/checklists/CONSORT.md +86 -0
  93. package/skills/check-reporting/references/checklists/COSMIN_RoB.md +136 -0
  94. package/skills/check-reporting/references/checklists/GRRAS.md +61 -0
  95. package/skills/check-reporting/references/checklists/MI_CLEAR_LLM.md +167 -0
  96. package/skills/check-reporting/references/checklists/MOOSE.md +85 -0
  97. package/skills/check-reporting/references/checklists/NOS.md +88 -0
  98. package/skills/check-reporting/references/checklists/PRISMA_2020.md +135 -0
  99. package/skills/check-reporting/references/checklists/PRISMA_DTA.md +36 -0
  100. package/skills/check-reporting/references/checklists/PRISMA_P.md +56 -0
  101. package/skills/check-reporting/references/checklists/PROBAST.md +75 -0
  102. package/skills/check-reporting/references/checklists/PROBAST_AI.md +130 -0
  103. package/skills/check-reporting/references/checklists/QUADAS2.md +77 -0
  104. package/skills/check-reporting/references/checklists/QUADAS_C.md +131 -0
  105. package/skills/check-reporting/references/checklists/ROBINS_E.md +179 -0
  106. package/skills/check-reporting/references/checklists/ROBINS_I.md +87 -0
  107. package/skills/check-reporting/references/checklists/ROBIS.md +114 -0
  108. package/skills/check-reporting/references/checklists/ROB_ME.md +126 -0
  109. package/skills/check-reporting/references/checklists/RoB2.md +79 -0
  110. package/skills/check-reporting/references/checklists/RoB_NMA.md +96 -0
  111. package/skills/check-reporting/references/checklists/SPIRIT.md +112 -0
  112. package/skills/check-reporting/references/checklists/SQUIRE_2.md +68 -0
  113. package/skills/check-reporting/references/checklists/STARD.md +129 -0
  114. package/skills/check-reporting/references/checklists/STARD_AI.md +211 -0
  115. package/skills/check-reporting/references/checklists/STROBE.md +80 -0
  116. package/skills/check-reporting/references/checklists/SWiM.md +33 -0
  117. package/skills/check-reporting/references/checklists/TRIPOD.md +157 -0
  118. package/skills/check-reporting/references/checklists/TRIPOD_AI.md +140 -0
  119. package/skills/check-reporting/references/step4c_registration_timing.md +93 -0
  120. package/skills/check-reporting/references/step4d_prisma_figure_audit.md +137 -0
  121. package/skills/check-reporting/scripts/check_checklist_exists.py +183 -0
  122. package/skills/check-reporting/scripts/check_checklist_version.py +168 -0
  123. package/skills/check-reporting/scripts/check_framework_naming.py +206 -0
  124. package/skills/check-reporting/scripts/check_prisma_figure.py +209 -0
  125. package/skills/check-reporting/scripts/prisma_cascade_check.py +274 -0
  126. package/skills/check-reporting/skill.yml +41 -0
  127. package/skills/check-reporting/tests/fixtures/framework_bad.md +8 -0
  128. package/skills/check-reporting/tests/fixtures/framework_clean.md +7 -0
  129. package/skills/check-reporting/tests/test_checklist_fail_fast.sh +77 -0
  130. package/skills/check-reporting/tests/test_checklist_version.sh +72 -0
  131. package/skills/check-reporting/tests/test_framework_naming.sh +45 -0
  132. package/skills/check-reporting/tests/test_prisma_cascade.sh +104 -0
  133. package/skills/clean-data/SKILL.md +180 -0
  134. package/skills/clean-data/references/cleaning_patterns.md +299 -0
  135. package/skills/clean-data/references/profiling_template.py +304 -0
  136. package/skills/clean-data/scripts/check_structural_zero.py +174 -0
  137. package/skills/clean-data/skill.yml +35 -0
  138. package/skills/clean-data/tests/fixtures/smoking.csv +8 -0
  139. package/skills/clean-data/tests/test_structural_zero.sh +49 -0
  140. package/skills/cross-national/SKILL.md +264 -0
  141. package/skills/cross-national/skill.yml +37 -0
  142. package/skills/define-variables/SKILL.md +146 -0
  143. package/skills/define-variables/references/common_definitions.md +190 -0
  144. package/skills/define-variables/skill.yml +34 -0
  145. package/skills/define-variables/templates/variable_operationalization.md +64 -0
  146. package/skills/deidentify/SKILL.md +203 -0
  147. package/skills/deidentify/deidentify.py +1224 -0
  148. package/skills/deidentify/locales/_template.json +45 -0
  149. package/skills/deidentify/locales/au.json +43 -0
  150. package/skills/deidentify/locales/ca.json +44 -0
  151. package/skills/deidentify/locales/cn.json +47 -0
  152. package/skills/deidentify/locales/de.json +48 -0
  153. package/skills/deidentify/locales/fr.json +48 -0
  154. package/skills/deidentify/locales/in.json +48 -0
  155. package/skills/deidentify/locales/jp.json +48 -0
  156. package/skills/deidentify/locales/kr.json +48 -0
  157. package/skills/deidentify/locales/uk.json +45 -0
  158. package/skills/deidentify/locales/us.json +43 -0
  159. package/skills/deidentify/references/date_shift_guide.md +82 -0
  160. package/skills/deidentify/references/hipaa_18_identifiers.md +48 -0
  161. package/skills/deidentify/references/korean_phi_patterns.md +135 -0
  162. package/skills/deidentify/skill.yml +43 -0
  163. package/skills/deidentify/tests/README.md +26 -0
  164. package/skills/deidentify/tests/test_clean.csv +16 -0
  165. package/skills/deidentify/tests/test_edge_cases.csv +11 -0
  166. package/skills/deidentify/tests/test_phi_korean.csv +11 -0
  167. package/skills/design-ai-benchmarking/SKILL.md +214 -0
  168. package/skills/design-ai-benchmarking/references/benchmark_export_schema.json +69 -0
  169. package/skills/design-ai-benchmarking/references/elicitation_rubric_template.md +37 -0
  170. package/skills/design-ai-benchmarking/skill.yml +38 -0
  171. package/skills/design-study/SKILL.md +298 -0
  172. package/skills/design-study/skill.yml +33 -0
  173. package/skills/fill-icmje-coi/SKILL.md +216 -0
  174. package/skills/fill-icmje-coi/scripts/fill_icmje_coi.py +140 -0
  175. package/skills/fill-icmje-coi/skill.yml +35 -0
  176. package/skills/fill-icmje-coi/templates/icmje_coi_seed_synthetic.docx +0 -0
  177. package/skills/fill-protocol/SKILL.md +248 -0
  178. package/skills/fill-protocol/examples/example_irb_template.yaml +53 -0
  179. package/skills/fill-protocol/references/best_practices.md +121 -0
  180. package/skills/fill-protocol/scripts/doc_to_docx.py +111 -0
  181. package/skills/fill-protocol/scripts/fill_form.py +611 -0
  182. package/skills/fill-protocol/scripts/inspect_template.py +61 -0
  183. package/skills/fill-protocol/setup.sh +162 -0
  184. package/skills/fill-protocol/skill.yml +37 -0
  185. package/skills/find-cohort-gap/SKILL.md +309 -0
  186. package/skills/find-cohort-gap/references/cohort_profile_template.md +93 -0
  187. package/skills/find-cohort-gap/references/onepager_template.md +84 -0
  188. package/skills/find-cohort-gap/references/pattern_scoring_rubric.md +169 -0
  189. package/skills/find-cohort-gap/references/saturation_query_templates.md +143 -0
  190. package/skills/find-cohort-gap/skill.yml +35 -0
  191. package/skills/find-journal/POLICY.md +87 -0
  192. package/skills/find-journal/SKILL.md +340 -0
  193. package/skills/find-journal/references/journal_profiles/AJNR.md +29 -0
  194. package/skills/find-journal/references/journal_profiles/AJR.md +30 -0
  195. package/skills/find-journal/references/journal_profiles/Abdominal_Radiology.md +30 -0
  196. package/skills/find-journal/references/journal_profiles/Academic_Radiology.md +30 -0
  197. package/skills/find-journal/references/journal_profiles/Annals_of_Internal_Medicine.md +33 -0
  198. package/skills/find-journal/references/journal_profiles/Artificial_Intelligence_in_Medicine.md +28 -0
  199. package/skills/find-journal/references/journal_profiles/BMC_Medicine.md +31 -0
  200. package/skills/find-journal/references/journal_profiles/British_Journal_of_Radiology.md +39 -0
  201. package/skills/find-journal/references/journal_profiles/CVIR.md +30 -0
  202. package/skills/find-journal/references/journal_profiles/Chest.md +39 -0
  203. package/skills/find-journal/references/journal_profiles/Clinical_Radiology.md +30 -0
  204. package/skills/find-journal/references/journal_profiles/Clinical_and_Molecular_Hepatology.md +32 -0
  205. package/skills/find-journal/references/journal_profiles/Diabetes_Metabolism_Journal.md +36 -0
  206. package/skills/find-journal/references/journal_profiles/Diagnostic_and_Interventional_Radiology.md +32 -0
  207. package/skills/find-journal/references/journal_profiles/Endocrinology_and_Metabolism.md +37 -0
  208. package/skills/find-journal/references/journal_profiles/European_Journal_of_Preventive_Cardiology.md +39 -0
  209. package/skills/find-journal/references/journal_profiles/European_Radiology.md +29 -0
  210. package/skills/find-journal/references/journal_profiles/Hepatology_Communications.md +40 -0
  211. package/skills/find-journal/references/journal_profiles/Hepatology_International.md +37 -0
  212. package/skills/find-journal/references/journal_profiles/IEEE_JBHI.md +28 -0
  213. package/skills/find-journal/references/journal_profiles/IEEE_TMI.md +28 -0
  214. package/skills/find-journal/references/journal_profiles/INSI.md +29 -0
  215. package/skills/find-journal/references/journal_profiles/Investigative_Radiology.md +25 -0
  216. package/skills/find-journal/references/journal_profiles/JACC_Advances.md +41 -0
  217. package/skills/find-journal/references/journal_profiles/JACC_Asia.md +30 -0
  218. package/skills/find-journal/references/journal_profiles/JACR.md +28 -0
  219. package/skills/find-journal/references/journal_profiles/JAMA.md +40 -0
  220. package/skills/find-journal/references/journal_profiles/JAMA_Network_Open.md +30 -0
  221. package/skills/find-journal/references/journal_profiles/JCSM.md +39 -0
  222. package/skills/find-journal/references/journal_profiles/JKMS.md +32 -0
  223. package/skills/find-journal/references/journal_profiles/JMIR.md +29 -0
  224. package/skills/find-journal/references/journal_profiles/JMIR_Medical_Education.md +29 -0
  225. package/skills/find-journal/references/journal_profiles/JNIS.md +35 -0
  226. package/skills/find-journal/references/journal_profiles/JVIR.md +31 -0
  227. package/skills/find-journal/references/journal_profiles/Journal_of_Biomedical_Informatics.md +29 -0
  228. package/skills/find-journal/references/journal_profiles/Journal_of_Clinical_Endocrinology_and_Metabolism.md +40 -0
  229. package/skills/find-journal/references/journal_profiles/Journal_of_Magnetic_Resonance_Imaging.md +30 -0
  230. package/skills/find-journal/references/journal_profiles/Journal_of_Nuclear_Medicine.md +31 -0
  231. package/skills/find-journal/references/journal_profiles/Journal_of_Stroke.md +32 -0
  232. package/skills/find-journal/references/journal_profiles/KJR.md +38 -0
  233. package/skills/find-journal/references/journal_profiles/Korean_Circulation_Journal.md +38 -0
  234. package/skills/find-journal/references/journal_profiles/Korean_Journal_of_Internal_Medicine.md +36 -0
  235. package/skills/find-journal/references/journal_profiles/Lancet_Diabetes_and_Endocrinology.md +40 -0
  236. package/skills/find-journal/references/journal_profiles/Lancet_Gastroenterology_and_Hepatology.md +49 -0
  237. package/skills/find-journal/references/journal_profiles/Lancet_Infectious_Diseases.md +38 -0
  238. package/skills/find-journal/references/journal_profiles/Lancet_Neurology.md +39 -0
  239. package/skills/find-journal/references/journal_profiles/Lancet_Oncology.md +40 -0
  240. package/skills/find-journal/references/journal_profiles/Lancet_Psychiatry.md +38 -0
  241. package/skills/find-journal/references/journal_profiles/Lancet_Public_Health.md +30 -0
  242. package/skills/find-journal/references/journal_profiles/Lancet_Respiratory_Medicine.md +39 -0
  243. package/skills/find-journal/references/journal_profiles/Liver_International.md +33 -0
  244. package/skills/find-journal/references/journal_profiles/Medical_Image_Analysis.md +28 -0
  245. package/skills/find-journal/references/journal_profiles/NEJM.md +33 -0
  246. package/skills/find-journal/references/journal_profiles/Nature_Machine_Intelligence.md +31 -0
  247. package/skills/find-journal/references/journal_profiles/Nature_Medicine.md +39 -0
  248. package/skills/find-journal/references/journal_profiles/Neuroradiology.md +31 -0
  249. package/skills/find-journal/references/journal_profiles/Nutrition_Metabolism_and_Cardiovascular_Diseases.md +39 -0
  250. package/skills/find-journal/references/journal_profiles/PLOS_Medicine.md +32 -0
  251. package/skills/find-journal/references/journal_profiles/RYAI.md +28 -0
  252. package/skills/find-journal/references/journal_profiles/Radiology.md +29 -0
  253. package/skills/find-journal/references/journal_profiles/Skeletal_Radiology.md +31 -0
  254. package/skills/find-journal/references/journal_profiles/Stroke.md +37 -0
  255. package/skills/find-journal/references/journal_profiles/The_BMJ.md +31 -0
  256. package/skills/find-journal/references/journal_profiles/The_Lancet.md +31 -0
  257. package/skills/find-journal/references/journal_profiles/The_Lancet_Digital_Health.md +29 -0
  258. package/skills/find-journal/references/journal_profiles/World_Journal_of_Hepatology.md +53 -0
  259. package/skills/find-journal/references/journal_profiles/npj_Digital_Medicine.md +29 -0
  260. package/skills/find-journal/skill.yml +34 -0
  261. package/skills/fulltext-retrieval/SKILL.md +174 -0
  262. package/skills/fulltext-retrieval/fetch_oa.py +433 -0
  263. package/skills/fulltext-retrieval/pdf_to_md.py +160 -0
  264. package/skills/fulltext-retrieval/skill.yml +41 -0
  265. package/skills/generate-codebook/SKILL.md +155 -0
  266. package/skills/generate-codebook/references/codebook_schema.md +76 -0
  267. package/skills/generate-codebook/scripts/generate_codebook.py +278 -0
  268. package/skills/generate-codebook/skill.yml +35 -0
  269. package/skills/generate-codebook/tests/test_generate_codebook.sh +76 -0
  270. package/skills/grant-builder/SKILL.md +251 -0
  271. package/skills/grant-builder/skill.yml +34 -0
  272. package/skills/humanize/SKILL.md +251 -0
  273. package/skills/humanize/references/ai_patterns.md +571 -0
  274. package/skills/humanize/skill.yml +33 -0
  275. package/skills/intake-project/SKILL.md +264 -0
  276. package/skills/intake-project/skill.yml +34 -0
  277. package/skills/lit-sync/SKILL.md +448 -0
  278. package/skills/lit-sync/references/locale/ko/note_templates.md +110 -0
  279. package/skills/lit-sync/skill.yml +52 -0
  280. package/skills/lit-sync/tests/test_poll_logic.sh +92 -0
  281. package/skills/ma-scout/SKILL.md +640 -0
  282. package/skills/ma-scout/references/project_readme_template.md +95 -0
  283. package/skills/ma-scout/references/project_readme_template_ko.md +82 -0
  284. package/skills/ma-scout/skill.yml +33 -0
  285. package/skills/make-figures/SKILL.md +957 -0
  286. package/skills/make-figures/references/critic_rubrics/data_plot.md +166 -0
  287. package/skills/make-figures/references/critic_rubrics/flow_diagram.md +169 -0
  288. package/skills/make-figures/references/design_principles.md +181 -0
  289. package/skills/make-figures/references/exemplar_diagrams/README.md +65 -0
  290. package/skills/make-figures/references/exemplar_diagrams/consort/README.md +15 -0
  291. package/skills/make-figures/references/exemplar_diagrams/consort/template_input.yaml +37 -0
  292. package/skills/make-figures/references/exemplar_diagrams/consort/template_output.pdf +0 -0
  293. package/skills/make-figures/references/exemplar_diagrams/consort/template_output.png +0 -0
  294. package/skills/make-figures/references/exemplar_diagrams/consort/template_output_600.png +0 -0
  295. package/skills/make-figures/references/exemplar_diagrams/other/other_02.meta.yaml +4 -0
  296. package/skills/make-figures/references/exemplar_diagrams/other/other_02.png +0 -0
  297. package/skills/make-figures/references/exemplar_diagrams/other/other_02_why.md +13 -0
  298. package/skills/make-figures/references/exemplar_diagrams/pipeline/README.md +15 -0
  299. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_01.meta.yaml +4 -0
  300. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_01.png +0 -0
  301. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_01_why.md +13 -0
  302. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_03.meta.yaml +4 -0
  303. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_03.png +0 -0
  304. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_03_why.md +13 -0
  305. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_04.meta.yaml +4 -0
  306. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_04.png +0 -0
  307. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_04_why.md +13 -0
  308. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_05.meta.yaml +4 -0
  309. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_05.png +0 -0
  310. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_05_why.md +13 -0
  311. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_06.meta.yaml +4 -0
  312. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_06.png +0 -0
  313. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_06_why.md +13 -0
  314. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_07.meta.yaml +4 -0
  315. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_07.png +0 -0
  316. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_07_why.md +13 -0
  317. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_08.meta.yaml +4 -0
  318. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_08.png +0 -0
  319. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_08_why.md +13 -0
  320. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_09.meta.yaml +4 -0
  321. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_09.png +0 -0
  322. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_09_why.md +13 -0
  323. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_10.meta.yaml +4 -0
  324. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_10.png +0 -0
  325. package/skills/make-figures/references/exemplar_diagrams/pipeline/pipeline_10_why.md +13 -0
  326. package/skills/make-figures/references/exemplar_diagrams/prisma/README.md +15 -0
  327. package/skills/make-figures/references/exemplar_diagrams/prisma/template_input.yaml +47 -0
  328. package/skills/make-figures/references/exemplar_diagrams/prisma/template_output.pdf +0 -0
  329. package/skills/make-figures/references/exemplar_diagrams/prisma/template_output.png +0 -0
  330. package/skills/make-figures/references/exemplar_diagrams/prisma/template_output_600.png +0 -0
  331. package/skills/make-figures/references/exemplar_diagrams/stard/README.md +15 -0
  332. package/skills/make-figures/references/exemplar_diagrams/stard/template_input.yaml +40 -0
  333. package/skills/make-figures/references/exemplar_diagrams/stard/template_output.pdf +0 -0
  334. package/skills/make-figures/references/exemplar_diagrams/stard/template_output.png +0 -0
  335. package/skills/make-figures/references/exemplar_diagrams/stard/template_output_600.png +0 -0
  336. package/skills/make-figures/references/exemplar_diagrams/strobe/template_input.yaml +43 -0
  337. package/skills/make-figures/references/exemplar_diagrams/strobe/template_input_pptx.yaml +43 -0
  338. package/skills/make-figures/references/exemplar_diagrams/strobe/template_output.pdf +0 -0
  339. package/skills/make-figures/references/exemplar_diagrams/strobe/template_output.png +0 -0
  340. package/skills/make-figures/references/exemplar_diagrams/strobe/template_output.pptx +0 -0
  341. package/skills/make-figures/references/exemplar_diagrams/strobe/template_output_600.png +0 -0
  342. package/skills/make-figures/references/figure_specs.md +291 -0
  343. package/skills/make-figures/references/flow_diagram_lessons.md +164 -0
  344. package/skills/make-figures/references/jacc_central_illustration_principles.md +91 -0
  345. package/skills/make-figures/references/medical_illustration_sources.md +98 -0
  346. package/skills/make-figures/references/pipeline_concepts_medical_ai.md +240 -0
  347. package/skills/make-figures/references/reporting_guideline_figure_map.md +104 -0
  348. package/skills/make-figures/references/visual_abstract_templates/european_radiology.pptx +0 -0
  349. package/skills/make-figures/references/visual_abstract_templates/jacc_central_illustration.pptx +0 -0
  350. package/skills/make-figures/references/visual_abstract_templates/medsci_default.pptx +0 -0
  351. package/skills/make-figures/references/visual_abstract_templates/template_guide.md +114 -0
  352. package/skills/make-figures/scripts/build_jacc_template.py +77 -0
  353. package/skills/make-figures/scripts/build_prisma2020_template.py +371 -0
  354. package/skills/make-figures/scripts/build_strobe_template.py +351 -0
  355. package/skills/make-figures/scripts/critic_figure.py +264 -0
  356. package/skills/make-figures/scripts/derive_figure_legend_counts.py +138 -0
  357. package/skills/make-figures/scripts/extract_exemplar_from_pdf.py +186 -0
  358. package/skills/make-figures/scripts/fetch_official_templates.sh +88 -0
  359. package/skills/make-figures/scripts/fill_prisma_template.py +142 -0
  360. package/skills/make-figures/scripts/generate_flow_diagram.R +133 -0
  361. package/skills/make-figures/scripts/generate_image.py +99 -0
  362. package/skills/make-figures/scripts/generate_visual_abstract.py +438 -0
  363. package/skills/make-figures/scripts/validate_pptx_mac_compat.py +233 -0
  364. package/skills/make-figures/skill.yml +52 -0
  365. package/skills/make-figures/templates/official/NOTES.md +62 -0
  366. package/skills/make-figures/templates/official/consort2010/CONSORT_2025_editable_checklist.docx +0 -0
  367. package/skills/make-figures/templates/official/consort2010/CONSORT_2025_flow_diagram.docx +0 -0
  368. package/skills/make-figures/templates/official/prisma2020/PRISMA_2020_flow_new_v1.pptx +0 -0
  369. package/skills/make-figures/templates/official/prisma2020/PRISMA_2020_flow_new_v2.pptx +0 -0
  370. package/skills/make-figures/templates/official/prisma2020/PRISMA_2020_flow_updated_v2.pptx +0 -0
  371. package/skills/make-figures/templates/official/spirit2013/SPIRIT_2025_editable_checklist.docx +0 -0
  372. package/skills/make-figures/templates/official/spirit2013/SPIRIT_2025_participant_timeline.docx +0 -0
  373. package/skills/make-figures/templates/official/stard2015/STARD_2015_checklist.docx +0 -0
  374. package/skills/make-figures/templates/official/stard2015/STARD_2015_flow_diagram.pdf +0 -0
  375. package/skills/make-figures/tests/fixtures/figure1_flow.yaml +8 -0
  376. package/skills/make-figures/tests/fixtures/manuscript_ok.md +9 -0
  377. package/skills/make-figures/tests/fixtures/manuscript_stale.md +4 -0
  378. package/skills/make-figures/tests/test_legend_reconcile.sh +36 -0
  379. package/skills/manage-project/SKILL.md +358 -0
  380. package/skills/manage-project/references/pre_submission_checklist.md +53 -0
  381. package/skills/manage-project/references/project_state_template.json +37 -0
  382. package/skills/manage-project/references/scaffold_templates.md +118 -0
  383. package/skills/manage-project/references/status_output_format.md +44 -0
  384. package/skills/manage-project/references/timeline_example.md +20 -0
  385. package/skills/manage-project/skill.yml +36 -0
  386. package/skills/manage-project/templates/SSOT.yaml.template +41 -0
  387. package/skills/manage-refs/LICENSE.zotero-mcp +21 -0
  388. package/skills/manage-refs/NOTICE.md +29 -0
  389. package/skills/manage-refs/SKILL.md +289 -0
  390. package/skills/manage-refs/citation_styles/README.md +40 -0
  391. package/skills/manage-refs/citation_styles/american-journal-of-roentgenology.csl +211 -0
  392. package/skills/manage-refs/citation_styles/cardiovascular-and-interventional-radiology.csl +19 -0
  393. package/skills/manage-refs/citation_styles/european-radiology.csl +19 -0
  394. package/skills/manage-refs/citation_styles/journal-of-cachexia-sarcopenia-and-muscle.csl +150 -0
  395. package/skills/manage-refs/citation_styles/journal-of-korean-medical-science-strict.csl +533 -0
  396. package/skills/manage-refs/citation_styles/journal-of-korean-medical-science.csl +16 -0
  397. package/skills/manage-refs/citation_styles/korean-journal-of-radiology.csl +155 -0
  398. package/skills/manage-refs/citation_styles/nature.csl +189 -0
  399. package/skills/manage-refs/citation_styles/nlm-citation-sequence.csl +535 -0
  400. package/skills/manage-refs/citation_styles/radiology.csl +228 -0
  401. package/skills/manage-refs/citation_styles/springer-basic-brackets.csl +187 -0
  402. package/skills/manage-refs/citation_styles/springer-vancouver-brackets.csl +276 -0
  403. package/skills/manage-refs/citation_styles/vancouver-superscript.csl +536 -0
  404. package/skills/manage-refs/citation_styles/vancouver.csl +535 -0
  405. package/skills/manage-refs/references/REFERENCE_STYLE_SPECS.md +59 -0
  406. package/skills/manage-refs/references/check_xref_symptoms.md +35 -0
  407. package/skills/manage-refs/scripts/_vendor_citation_writer.py +600 -0
  408. package/skills/manage-refs/scripts/check_citation_keys.py +112 -0
  409. package/skills/manage-refs/scripts/check_csl_render.py +102 -0
  410. package/skills/manage-refs/scripts/check_xref.py +633 -0
  411. package/skills/manage-refs/scripts/fill_journal_abbrev.py +104 -0
  412. package/skills/manage-refs/scripts/inject_zotero_cwyw.py +133 -0
  413. package/skills/manage-refs/scripts/md_marker_convert.py +193 -0
  414. package/skills/manage-refs/scripts/pre_submission_gate.sh +238 -0
  415. package/skills/manage-refs/scripts/render_pandoc.sh +88 -0
  416. package/skills/manage-refs/skill.yml +70 -0
  417. package/skills/manage-refs/tests/fixtures/pre_submission_gate/README.md +32 -0
  418. package/skills/manage-refs/tests/fixtures/pre_submission_gate/manuscript.md +10 -0
  419. package/skills/manage-refs/tests/fixtures/pre_submission_gate/refs.bib +34 -0
  420. package/skills/manage-refs/tests/fixtures/pre_submission_gate/run.sh +117 -0
  421. package/skills/manage-refs/tests/test_vN_docx_check.sh +145 -0
  422. package/skills/meta-analysis/SKILL.md +739 -0
  423. package/skills/meta-analysis/references/LICENSES.md +21 -0
  424. package/skills/meta-analysis/references/PROSPERO_template.md +221 -0
  425. package/skills/meta-analysis/references/ai_pre_screening_template.py +245 -0
  426. package/skills/meta-analysis/references/checklists/JBI_Case_Series.md +45 -0
  427. package/skills/meta-analysis/references/checklists/NOS.md +88 -0
  428. package/skills/meta-analysis/references/checklists/PRISMA_DTA.md +36 -0
  429. package/skills/meta-analysis/references/checklists/PROBAST.md +75 -0
  430. package/skills/meta-analysis/references/checklists/QUADAS2.md +77 -0
  431. package/skills/meta-analysis/references/checklists/ROBINS_I.md +87 -0
  432. package/skills/meta-analysis/references/checklists/RoB2.md +79 -0
  433. package/skills/meta-analysis/references/data_integrity_checklist.md +57 -0
  434. package/skills/meta-analysis/references/icmje_coi_guide.md +181 -0
  435. package/skills/meta-analysis/references/phase10_recovery.md +136 -0
  436. package/skills/meta-analysis/references/phase4_km_composite.md +58 -0
  437. package/skills/meta-analysis/references/phase6_statistical_synthesis.md +148 -0
  438. package/skills/meta-analysis/references/phase9_circulation.md +84 -0
  439. package/skills/meta-analysis/references/post_submission_release_ops.md +41 -0
  440. package/skills/meta-analysis/references/r_templates.md +132 -0
  441. package/skills/meta-analysis/references/review_orchestration.md +40 -0
  442. package/skills/meta-analysis/references/submission_package_drift.md +71 -0
  443. package/skills/meta-analysis/scripts/check_pool_consistency.py +201 -0
  444. package/skills/meta-analysis/scripts/cohort_overlap_check.py +242 -0
  445. package/skills/meta-analysis/scripts/dta_extraction_qc.py +137 -0
  446. package/skills/meta-analysis/scripts/screening_reconcile.py +160 -0
  447. package/skills/meta-analysis/skill.yml +47 -0
  448. package/skills/meta-analysis/templates/FINAL_POOL_LOCK.yaml.template +70 -0
  449. package/skills/meta-analysis/templates/extraction_form_v2.md +129 -0
  450. package/skills/meta-analysis/templates/supplementary_8file_checklist.md +94 -0
  451. package/skills/meta-analysis/tests/test_pool_consistency.sh +123 -0
  452. package/skills/orchestrate/SKILL.md +501 -0
  453. package/skills/orchestrate/references/dialogue_nodes.md +196 -0
  454. package/skills/orchestrate/references/report_template.md +109 -0
  455. package/skills/orchestrate/references/report_template_ko.md +88 -0
  456. package/skills/orchestrate/skill.yml +44 -0
  457. package/skills/peer-review/SKILL.md +381 -0
  458. package/skills/peer-review/references/aczel_2021_reviewer2_patterns.md +88 -0
  459. package/skills/peer-review/references/domain-probes/ai_overclaiming.md +47 -0
  460. package/skills/peer-review/references/domain-probes/narrative_review.md +44 -0
  461. package/skills/peer-review/references/domain-probes/observational_confounding.md +48 -0
  462. package/skills/peer-review/references/domain-probes/radiomics.md +38 -0
  463. package/skills/peer-review/references/domain-probes/sr_ma.md +87 -0
  464. package/skills/peer-review/references/domain-probes/survival_prognostic.md +68 -0
  465. package/skills/peer-review/references/exemplar_reviews/README.md +43 -0
  466. package/skills/peer-review/references/exemplar_reviews/ai_overclaiming.md +47 -0
  467. package/skills/peer-review/references/exemplar_reviews/calibration_missing.md +44 -0
  468. package/skills/peer-review/references/exemplar_reviews/data_leakage.md +48 -0
  469. package/skills/peer-review/references/exemplar_reviews/reference_standard_validity.md +45 -0
  470. package/skills/peer-review/references/narrative_review_audit.md +67 -0
  471. package/skills/peer-review/references/reviewer_calibration/README.md +34 -0
  472. package/skills/peer-review/references/reviewer_calibration/compliance_floor.md +52 -0
  473. package/skills/peer-review/references/reviewer_profiles/AJR.md +82 -0
  474. package/skills/peer-review/references/reviewer_profiles/EURE.md +64 -0
  475. package/skills/peer-review/references/reviewer_profiles/INSI.md +57 -0
  476. package/skills/peer-review/references/reviewer_profiles/KJR.md +100 -0
  477. package/skills/peer-review/references/reviewer_profiles/README.md +32 -0
  478. package/skills/peer-review/references/reviewer_profiles/RYAI.md +86 -0
  479. package/skills/peer-review/skill.yml +39 -0
  480. package/skills/present-paper/SKILL.md +675 -0
  481. package/skills/present-paper/references/critic_rubrics/slide.md +155 -0
  482. package/skills/present-paper/references/generate_pptx_templates.py +604 -0
  483. package/skills/present-paper/references/medical_presentation_templates.md +277 -0
  484. package/skills/present-paper/references/slide_design_principles.md +202 -0
  485. package/skills/present-paper/references/slide_visual_styles/nature_lancet.md +168 -0
  486. package/skills/present-paper/references/workflow-checklist.md +109 -0
  487. package/skills/present-paper/scripts/extract_pdf_figures.py +243 -0
  488. package/skills/present-paper/scripts/inject_pronunciation_notes.py +178 -0
  489. package/skills/present-paper/scripts/inject_speaker_notes.py +133 -0
  490. package/skills/present-paper/scripts/strip_notes_for_sharing.py +140 -0
  491. package/skills/present-paper/scripts/trim_caption.py +271 -0
  492. package/skills/present-paper/skill.yml +41 -0
  493. package/skills/present-paper/templates/build_pptx_nature_lancet.py +688 -0
  494. package/skills/publish-skill/SKILL.md +370 -0
  495. package/skills/publish-skill/references/license-compatibility-matrix.md +132 -0
  496. package/skills/publish-skill/references/pii-patterns.md +130 -0
  497. package/skills/publish-skill/scripts/audit_skill.sh +278 -0
  498. package/skills/publish-skill/skill.yml +35 -0
  499. package/skills/render-pdf-doc/SKILL.md +146 -0
  500. package/skills/render-pdf-doc/references/known_pitfalls.md +53 -0
  501. package/skills/render-pdf-doc/references/pandoc_korean_cheatsheet.md +77 -0
  502. package/skills/render-pdf-doc/scripts/check_deps.sh +42 -0
  503. package/skills/render-pdf-doc/scripts/infer_colwidths.py +164 -0
  504. package/skills/render-pdf-doc/scripts/render_pdf.sh +98 -0
  505. package/skills/render-pdf-doc/skill.yml +57 -0
  506. package/skills/render-pdf-doc/templates/anchor-doc.md +27 -0
  507. package/skills/render-pdf-doc/templates/anchor-doc_ko.md +25 -0
  508. package/skills/render-pdf-doc/templates/briefing-handout.md +33 -0
  509. package/skills/render-pdf-doc/templates/briefing-handout_ko.md +31 -0
  510. package/skills/render-pdf-doc/templates/proposal-cover.md +33 -0
  511. package/skills/render-pdf-doc/templates/proposal-cover_ko.md +31 -0
  512. package/skills/render-pdf-doc/templates/reference-table.md +22 -0
  513. package/skills/render-pdf-doc/templates/reference-table_ko.md +20 -0
  514. package/skills/replicate-study/SKILL.md +150 -0
  515. package/skills/replicate-study/references/harmonization_3country.csv +47 -0
  516. package/skills/replicate-study/references/harmonization_knhanes_nhanes.csv +68 -0
  517. package/skills/replicate-study/references/methodology_extraction_template.md +134 -0
  518. package/skills/replicate-study/skill.yml +37 -0
  519. package/skills/review-paper/SKILL.md +104 -0
  520. package/skills/review-paper/references/macro_skeleton.md +6 -0
  521. package/skills/review-paper/skill.yml +25 -0
  522. package/skills/revise/SKILL.md +515 -0
  523. package/skills/revise/references/r2r_voice.md +346 -0
  524. package/skills/revise/skill.yml +43 -0
  525. package/skills/search-lit/SKILL.md +443 -0
  526. package/skills/search-lit/references/parse_pubmed.py +326 -0
  527. package/skills/search-lit/references/pubmed_eutils.sh +111 -0
  528. package/skills/search-lit/skill.yml +46 -0
  529. package/skills/self-review/SKILL.md +1045 -0
  530. package/skills/self-review/references/domain-probes/ai_overclaiming.md +47 -0
  531. package/skills/self-review/references/domain-probes/narrative_review.md +44 -0
  532. package/skills/self-review/references/domain-probes/observational_confounding.md +48 -0
  533. package/skills/self-review/references/domain-probes/radiomics.md +38 -0
  534. package/skills/self-review/references/domain-probes/sr_ma.md +87 -0
  535. package/skills/self-review/references/domain-probes/survival_prognostic.md +68 -0
  536. package/skills/self-review/references/exemplar_findings/README.md +43 -0
  537. package/skills/self-review/references/exemplar_findings/cohort_arithmetic_mismatch.md +35 -0
  538. package/skills/self-review/references/exemplar_findings/estimand_drift_posthoc_primary.md +39 -0
  539. package/skills/self-review/references/exemplar_findings/scope_overreach_cross_sectional.md +35 -0
  540. package/skills/self-review/references/exemplar_findings/unadjusted_confounder.md +36 -0
  541. package/skills/self-review/references/panel_review_template.md +177 -0
  542. package/skills/self-review/scripts/check_artifact_coverage.py +301 -0
  543. package/skills/self-review/scripts/check_claim_artifact.py +248 -0
  544. package/skills/self-review/scripts/check_classical_style.py +185 -0
  545. package/skills/self-review/scripts/check_cohort_arithmetic.py +481 -0
  546. package/skills/self-review/scripts/check_confounding_completeness.py +287 -0
  547. package/skills/self-review/scripts/check_panel_diversity.py +336 -0
  548. package/skills/self-review/scripts/check_reference_adequacy.py +392 -0
  549. package/skills/self-review/scripts/check_reviewer_team_consistency.py +412 -0
  550. package/skills/self-review/scripts/check_scope_coherence.py +177 -0
  551. package/skills/self-review/skill.yml +47 -0
  552. package/skills/self-review/tests/fixtures/claim_manuscript.md +17 -0
  553. package/skills/self-review/tests/fixtures/claim_prereg.md +6 -0
  554. package/skills/self-review/tests/fixtures/cohort_bad.md +21 -0
  555. package/skills/self-review/tests/fixtures/cohort_clean.md +21 -0
  556. package/skills/self-review/tests/fixtures/cohort_partition.csv +5 -0
  557. package/skills/self-review/tests/fixtures/coverage_analysis/31_delong_nested_added_value.csv +3 -0
  558. package/skills/self-review/tests/fixtures/coverage_analysis/table1_demographics.csv +3 -0
  559. package/skills/self-review/tests/fixtures/coverage_clean.md +13 -0
  560. package/skills/self-review/tests/fixtures/coverage_manuscript.md +11 -0
  561. package/skills/self-review/tests/fixtures/panel_collapse.json +27 -0
  562. package/skills/self-review/tests/fixtures/panel_good.json +32 -0
  563. package/skills/self-review/tests/fixtures/panel_monoculture.json +32 -0
  564. package/skills/self-review/tests/fixtures/refadeq_letter.md +13 -0
  565. package/skills/self-review/tests/fixtures/refadeq_original_fixed.md +42 -0
  566. package/skills/self-review/tests/fixtures/refadeq_original_uncited.md +40 -0
  567. package/skills/self-review/tests/fixtures/scope_bad.md +9 -0
  568. package/skills/self-review/tests/fixtures/scope_clean.md +8 -0
  569. package/skills/self-review/tests/fixtures/scope_surrogate.md +8 -0
  570. package/skills/self-review/tests/fixtures/style_bad.md +13 -0
  571. package/skills/self-review/tests/fixtures/style_clean.md +11 -0
  572. package/skills/self-review/tests/fixtures/table1_by_exposure.csv +11 -0
  573. package/skills/self-review/tests/test_artifact_coverage.sh +44 -0
  574. package/skills/self-review/tests/test_claim_artifact.sh +50 -0
  575. package/skills/self-review/tests/test_classical_style.sh +44 -0
  576. package/skills/self-review/tests/test_cohort_arithmetic.sh +49 -0
  577. package/skills/self-review/tests/test_confounding_completeness.sh +66 -0
  578. package/skills/self-review/tests/test_panel_diversity.sh +55 -0
  579. package/skills/self-review/tests/test_panel_mode.sh +69 -0
  580. package/skills/self-review/tests/test_reference_adequacy.sh +68 -0
  581. package/skills/self-review/tests/test_reviewer_team_consistency.sh +138 -0
  582. package/skills/self-review/tests/test_scope_coherence.sh +46 -0
  583. package/skills/setup-medsci/SKILL.md +110 -0
  584. package/skills/setup-medsci/references/setup-checklist.md +51 -0
  585. package/skills/setup-medsci/skill.yml +30 -0
  586. package/skills/sync-submission/SKILL.md +382 -0
  587. package/skills/sync-submission/scripts/author_registry_example.yaml +36 -0
  588. package/skills/sync-submission/scripts/blind_sweep.py +203 -0
  589. package/skills/sync-submission/scripts/check_asset_anonymization.py +300 -0
  590. package/skills/sync-submission/scripts/check_cross_artifact_stale.py +211 -0
  591. package/skills/sync-submission/scripts/cover_letter_drift_check.py +451 -0
  592. package/skills/sync-submission/scripts/cross_document_n_check.py +486 -0
  593. package/skills/sync-submission/scripts/detect_copy_divergence.py +136 -0
  594. package/skills/sync-submission/scripts/preflight_gate.py +458 -0
  595. package/skills/sync-submission/scripts/scope_drift_check.py +362 -0
  596. package/skills/sync-submission/scripts/sync_submission.py +169 -0
  597. package/skills/sync-submission/skill.yml +43 -0
  598. package/skills/sync-submission/tests/fixtures/copy_ok.md +5 -0
  599. package/skills/sync-submission/tests/fixtures/copy_stale.md +5 -0
  600. package/skills/sync-submission/tests/fixtures/ssot.md +5 -0
  601. package/skills/sync-submission/tests/test_asset_anonymization.sh +99 -0
  602. package/skills/sync-submission/tests/test_copy_divergence.sh +44 -0
  603. package/skills/sync-submission/tests/test_cross_artifact_stale.sh +80 -0
  604. package/skills/sync-submission/tests/test_cross_document_n.sh +132 -0
  605. package/skills/sync-submission/tests/test_preflight_gate.sh +112 -0
  606. package/skills/sync-submission/tests/test_scope_drift.sh +122 -0
  607. package/skills/sync-submission/tests/test_vN_docx_assertion.sh +51 -0
  608. package/skills/verify-refs/SKILL.md +177 -0
  609. package/skills/verify-refs/references/manual_checkpoint_guide.md +100 -0
  610. package/skills/verify-refs/scripts/verify_cli.sh +62 -0
  611. package/skills/verify-refs/scripts/verify_refs.py +782 -0
  612. package/skills/verify-refs/skill.yml +44 -0
  613. package/skills/verify-refs/tests/fixtures/pagination_placeholder.bib +17 -0
  614. package/skills/verify-refs/tests/test_pagination_placeholder.sh +42 -0
  615. package/skills/version-dataset/SKILL.md +143 -0
  616. package/skills/version-dataset/references/manifest_schema.md +72 -0
  617. package/skills/version-dataset/scripts/version_dataset.py +242 -0
  618. package/skills/version-dataset/skill.yml +35 -0
  619. package/skills/version-dataset/tests/test_version_dataset.sh +52 -0
  620. package/skills/write-paper/SKILL.md +1148 -0
  621. package/skills/write-paper/references/exemplar_methods/README.md +38 -0
  622. package/skills/write-paper/references/exemplar_methods/ai_validation_tripod_claim.md +47 -0
  623. package/skills/write-paper/references/exemplar_methods/diagnostic_accuracy_stard.md +50 -0
  624. package/skills/write-paper/references/exemplar_methods/observational_cohort_strobe.md +43 -0
  625. package/skills/write-paper/references/journal_profiles/AJNR.md +185 -0
  626. package/skills/write-paper/references/journal_profiles/AJR.md +149 -0
  627. package/skills/write-paper/references/journal_profiles/Abdominal_Radiology.md +139 -0
  628. package/skills/write-paper/references/journal_profiles/Academic_Radiology.md +90 -0
  629. package/skills/write-paper/references/journal_profiles/Annals_of_Internal_Medicine.md +150 -0
  630. package/skills/write-paper/references/journal_profiles/Artificial_Intelligence_in_Medicine.md +82 -0
  631. package/skills/write-paper/references/journal_profiles/British_Journal_of_Radiology.md +161 -0
  632. package/skills/write-paper/references/journal_profiles/CVIR.md +157 -0
  633. package/skills/write-paper/references/journal_profiles/Chest.md +270 -0
  634. package/skills/write-paper/references/journal_profiles/Clinical_Radiology.md +160 -0
  635. package/skills/write-paper/references/journal_profiles/Clinical_and_Molecular_Hepatology.md +147 -0
  636. package/skills/write-paper/references/journal_profiles/Diabetes_Metabolism_Journal.md +163 -0
  637. package/skills/write-paper/references/journal_profiles/Diagnostic_and_Interventional_Radiology.md +216 -0
  638. package/skills/write-paper/references/journal_profiles/Endocrinology_and_Metabolism.md +167 -0
  639. package/skills/write-paper/references/journal_profiles/European_Journal_of_Preventive_Cardiology.md +192 -0
  640. package/skills/write-paper/references/journal_profiles/European_Radiology.md +159 -0
  641. package/skills/write-paper/references/journal_profiles/Hepatology_Communications.md +110 -0
  642. package/skills/write-paper/references/journal_profiles/Hepatology_International.md +106 -0
  643. package/skills/write-paper/references/journal_profiles/IEEE_TMI.md +180 -0
  644. package/skills/write-paper/references/journal_profiles/INSI.md +163 -0
  645. package/skills/write-paper/references/journal_profiles/Investigative_Radiology.md +86 -0
  646. package/skills/write-paper/references/journal_profiles/JACC_Advances.md +197 -0
  647. package/skills/write-paper/references/journal_profiles/JACC_Asia.md +168 -0
  648. package/skills/write-paper/references/journal_profiles/JACR.md +87 -0
  649. package/skills/write-paper/references/journal_profiles/JAMA.md +188 -0
  650. package/skills/write-paper/references/journal_profiles/JAMA_Network_Open.md +170 -0
  651. package/skills/write-paper/references/journal_profiles/JCSM.md +266 -0
  652. package/skills/write-paper/references/journal_profiles/JKMS.md +201 -0
  653. package/skills/write-paper/references/journal_profiles/JMIR.md +88 -0
  654. package/skills/write-paper/references/journal_profiles/JMIR_Medical_Education.md +86 -0
  655. package/skills/write-paper/references/journal_profiles/JNIS.md +227 -0
  656. package/skills/write-paper/references/journal_profiles/JVIR.md +158 -0
  657. package/skills/write-paper/references/journal_profiles/Journal_of_Clinical_Endocrinology_and_Metabolism.md +191 -0
  658. package/skills/write-paper/references/journal_profiles/Journal_of_Stroke.md +176 -0
  659. package/skills/write-paper/references/journal_profiles/KJR.md +185 -0
  660. package/skills/write-paper/references/journal_profiles/Korean_Circulation_Journal.md +184 -0
  661. package/skills/write-paper/references/journal_profiles/Korean_Journal_of_Internal_Medicine.md +178 -0
  662. package/skills/write-paper/references/journal_profiles/Lancet_Gastroenterology_and_Hepatology.md +127 -0
  663. package/skills/write-paper/references/journal_profiles/Liver_International.md +165 -0
  664. package/skills/write-paper/references/journal_profiles/Medical_Image_Analysis.md +147 -0
  665. package/skills/write-paper/references/journal_profiles/NEJM.md +147 -0
  666. package/skills/write-paper/references/journal_profiles/Nature_Medicine.md +181 -0
  667. package/skills/write-paper/references/journal_profiles/Neuroradiology.md +151 -0
  668. package/skills/write-paper/references/journal_profiles/Nutrition_Metabolism_and_Cardiovascular_Diseases.md +184 -0
  669. package/skills/write-paper/references/journal_profiles/PLOS_Medicine.md +166 -0
  670. package/skills/write-paper/references/journal_profiles/RYAI.md +124 -0
  671. package/skills/write-paper/references/journal_profiles/Radiology.md +173 -0
  672. package/skills/write-paper/references/journal_profiles/Skeletal_Radiology.md +135 -0
  673. package/skills/write-paper/references/journal_profiles/Stroke.md +210 -0
  674. package/skills/write-paper/references/journal_profiles/The_BMJ.md +121 -0
  675. package/skills/write-paper/references/journal_profiles/The_Lancet.md +112 -0
  676. package/skills/write-paper/references/journal_profiles/The_Lancet_Digital_Health.md +104 -0
  677. package/skills/write-paper/references/journal_profiles/World_Journal_of_Hepatology.md +106 -0
  678. package/skills/write-paper/references/journal_profiles/npj_Digital_Medicine.md +93 -0
  679. package/skills/write-paper/references/paper_types/ai_validation.md +270 -0
  680. package/skills/write-paper/references/paper_types/animal_study.md +194 -0
  681. package/skills/write-paper/references/paper_types/case_report.md +237 -0
  682. package/skills/write-paper/references/paper_types/cross_national.md +328 -0
  683. package/skills/write-paper/references/paper_types/letter.md +127 -0
  684. package/skills/write-paper/references/paper_types/meta_analysis.md +181 -0
  685. package/skills/write-paper/references/paper_types/nhis_cohort.md +297 -0
  686. package/skills/write-paper/references/paper_types/original_article.md +221 -0
  687. package/skills/write-paper/references/paper_types/technical_note.md +131 -0
  688. package/skills/write-paper/references/section_guides/discussion.md +155 -0
  689. package/skills/write-paper/references/section_guides/introduction.md +108 -0
  690. package/skills/write-paper/references/section_guides/methods.md +144 -0
  691. package/skills/write-paper/references/section_guides/results.md +113 -0
  692. package/skills/write-paper/references/section_guides/step7_1_classical_qc.md +67 -0
  693. package/skills/write-paper/references/section_guides/step7_4a_audit_recovery.md +74 -0
  694. package/skills/write-paper/references/section_guides/title_abstract.md +123 -0
  695. package/skills/write-paper/references/section_templates/methods_statistical.md +147 -0
  696. package/skills/write-paper/scripts/check_placeholders.py +182 -0
  697. package/skills/write-paper/skill.yml +48 -0
  698. package/skills/write-paper/tests/test_placeholders.sh +107 -0
  699. package/skills/write-protocol/SKILL.md +243 -0
  700. package/skills/write-protocol/references/ethics_checklist.md +150 -0
  701. package/skills/write-protocol/references/protocol_template.md +304 -0
  702. package/skills/write-protocol/skill.yml +34 -0
@@ -0,0 +1,325 @@
1
+ """
2
+ survival_analysis.py — Publication-ready Survival Analysis
3
+ ===========================================================
4
+ Kaplan-Meier curves, log-rank test, Cox proportional hazards model.
5
+
6
+ Input CSV columns:
7
+ time : float — Time to event or censoring (in days/months/years)
8
+ event : int — Event indicator (1 = event occurred, 0 = censored)
9
+ group : str — Group variable for KM comparison (optional)
10
+ [covariates]: float/int — Covariates for Cox model
11
+
12
+ Outputs:
13
+ - KM plot with at-risk table (PNG/PDF, 300 DPI)
14
+ - Cox model results table (CSV)
15
+ - Console: complete results summary
16
+
17
+ Usage:
18
+ python survival_analysis.py --input data.csv \
19
+ --time time_months --event event \
20
+ --group treatment_group \
21
+ --covariates age sex bmi comorbidity \
22
+ --time-unit "Months" \
23
+ --output survival_analysis
24
+
25
+ Dependencies:
26
+ pip install lifelines pandas numpy matplotlib scipy
27
+ """
28
+
29
+ import argparse
30
+ import sys
31
+ from datetime import datetime
32
+
33
+ import numpy as np
34
+ import pandas as pd
35
+ import matplotlib.pyplot as plt
36
+ import matplotlib.gridspec as gridspec
37
+
38
+ try:
39
+ from lifelines import KaplanMeierFitter, CoxPHFitter
40
+ from lifelines.statistics import logrank_test, multivariate_logrank_test
41
+ from lifelines.utils import restricted_mean_survival_time, median_survival_times
42
+ LIFELINES_AVAILABLE = True
43
+ except ImportError:
44
+ LIFELINES_AVAILABLE = False
45
+ print("ERROR: lifelines not installed. Install with: pip install lifelines")
46
+ sys.exit(1)
47
+
48
+ # ── Reproducibility ───────────────────────────────────────────────────────────
49
+ SCRIPT_VERSION = "1.0.0"
50
+ SEED = 42
51
+ np.random.seed(SEED)
52
+
53
+
54
+ def _fmt_time(x):
55
+ """Format a survival time; 'NR' (not reached) for inf/NaN."""
56
+ if x is None or not np.isfinite(x):
57
+ return "NR"
58
+ return f"{x:.1f}"
59
+
60
+
61
+ def median_with_ci(kmf, unit):
62
+ """Median survival with its 95% CI from a fitted KaplanMeierFitter.
63
+
64
+ A median point estimate reported without its CI is incomplete (analyze-stats
65
+ Survival reporting rule). Returns 'NR' when the median is not reached.
66
+ """
67
+ med = kmf.median_survival_time_
68
+ try:
69
+ ci = median_survival_times(kmf.confidence_interval_)
70
+ lo, hi = ci.iloc[0, 0], ci.iloc[0, 1]
71
+ except Exception:
72
+ lo = hi = float("nan")
73
+ return f"{_fmt_time(med)} (95% CI {_fmt_time(lo)}–{_fmt_time(hi)}) {unit}"
74
+ print(f"survival_analysis.py v{SCRIPT_VERSION} | {datetime.now().strftime('%Y-%m-%d')}")
75
+
76
+ # ── Style ─────────────────────────────────────────────────────────────────────
77
+ plt.rcParams.update({
78
+ "font.family": "Arial",
79
+ "font.size": 9,
80
+ "axes.labelsize": 9,
81
+ "xtick.labelsize": 8,
82
+ "ytick.labelsize": 8,
83
+ })
84
+
85
+ WONG_COLORS = ["#0072B2", "#D55E00", "#009E73", "#E69F00", "#CC79A7", "#56B4E9"]
86
+ LINE_STYLES = ["-", "--", "-.", ":", (0, (3, 1, 1, 1))]
87
+
88
+
89
+ def load_data(filepath, time_col, event_col):
90
+ df = pd.read_csv(filepath)
91
+ for col in [time_col, event_col]:
92
+ if col not in df.columns:
93
+ raise ValueError(f"Column '{col}' not found in {filepath}")
94
+ df = df.dropna(subset=[time_col, event_col])
95
+ return df
96
+
97
+
98
+ def km_analysis(df, time_col, event_col, group_col=None,
99
+ time_unit="Months", output_path="survival"):
100
+ """Kaplan-Meier analysis with at-risk table."""
101
+ fig = plt.figure(figsize=(7.0, 5.0))
102
+
103
+ if group_col and group_col in df.columns:
104
+ groups = sorted(df[group_col].dropna().unique())
105
+ n_groups = len(groups)
106
+ gs = gridspec.GridSpec(2, 1, height_ratios=[3.5, 1.5], hspace=0.05)
107
+ else:
108
+ groups = None
109
+ n_groups = 1
110
+ gs = gridspec.GridSpec(2, 1, height_ratios=[3.5, 1.5], hspace=0.05)
111
+
112
+ ax_km = fig.add_subplot(gs[0])
113
+ ax_risk = fig.add_subplot(gs[1])
114
+
115
+ fitters = {}
116
+
117
+ if groups:
118
+ for i, g in enumerate(groups):
119
+ mask = df[group_col] == g
120
+ d = df[mask]
121
+ kmf = KaplanMeierFitter()
122
+ kmf.fit(d[time_col], d[event_col], label=str(g))
123
+ fitters[g] = kmf
124
+
125
+ kmf.plot_survival_function(
126
+ ax=ax_km,
127
+ color=WONG_COLORS[i % len(WONG_COLORS)],
128
+ linestyle=LINE_STYLES[i % len(LINE_STYLES)],
129
+ linewidth=1.5,
130
+ ci_show=True,
131
+ ci_alpha=0.15,
132
+ )
133
+
134
+ # Median survival with 95% CI
135
+ print(f" {g}: Median survival = {median_with_ci(kmf, time_unit)}")
136
+
137
+ # Log-rank test
138
+ if n_groups == 2:
139
+ g1, g2 = groups
140
+ lr = logrank_test(
141
+ df.loc[df[group_col] == g1, time_col],
142
+ df.loc[df[group_col] == g2, time_col],
143
+ df.loc[df[group_col] == g1, event_col],
144
+ df.loc[df[group_col] == g2, event_col],
145
+ )
146
+ p_str = f"P {'< .001' if lr.p_value < 0.001 else f'= {lr.p_value:.3f}'}"
147
+ ax_km.text(0.98, 0.5, f"Log-rank {p_str}",
148
+ transform=ax_km.transAxes, fontsize=8,
149
+ va="center", ha="right")
150
+ print(f"\n Log-rank test: χ² = {lr.test_statistic:.3f}, P = {lr.p_value:.4f}")
151
+ else:
152
+ mlr = multivariate_logrank_test(
153
+ df[time_col], df[group_col], df[event_col]
154
+ )
155
+ p_str = f"P {'< .001' if mlr.p_value < 0.001 else f'= {mlr.p_value:.3f}'}"
156
+ ax_km.text(0.98, 0.5, f"Log-rank {p_str}",
157
+ transform=ax_km.transAxes, fontsize=8,
158
+ va="center", ha="right")
159
+ else:
160
+ # Single-group KM
161
+ kmf = KaplanMeierFitter()
162
+ kmf.fit(df[time_col], df[event_col], label="All patients")
163
+ fitters["All"] = kmf
164
+ kmf.plot_survival_function(ax=ax_km, color=WONG_COLORS[0],
165
+ linewidth=1.5, ci_show=True, ci_alpha=0.2)
166
+ print(f" Median survival: {median_with_ci(kmf, time_unit)}")
167
+
168
+ # KM axis formatting
169
+ ax_km.set_ylim(-0.02, 1.05)
170
+ ax_km.set_xlim(left=0)
171
+ ax_km.set_ylabel("Survival probability", fontsize=9)
172
+ ax_km.set_xlabel("")
173
+ ax_km.spines[["top", "right"]].set_visible(False)
174
+ ax_km.legend(fontsize=8, frameon=False)
175
+ ax_km.grid(axis="y", color="#EEEEEE", linewidth=0.5)
176
+
177
+ # At-risk table
178
+ ax_risk.set_axis_off()
179
+ time_points = np.linspace(0, df[time_col].max() * 0.95, 6)
180
+ row_offset = 1.0
181
+
182
+ for i, (label, kmf) in enumerate(fitters.items()):
183
+ at_risk = [kmf.event_table["at_risk"].iloc[
184
+ max(0, (kmf.event_table.index <= t).sum() - 1)
185
+ ] for t in time_points]
186
+ ax_risk.text(-0.01, row_offset - i * 0.35, str(label),
187
+ transform=ax_risk.transAxes, fontsize=7.5,
188
+ va="top", ha="right",
189
+ color=WONG_COLORS[i % len(WONG_COLORS)])
190
+ for j, (t, n) in enumerate(zip(time_points, at_risk)):
191
+ ax_risk.text(j / (len(time_points) - 1), row_offset - i * 0.35,
192
+ str(int(n)), transform=ax_risk.transAxes,
193
+ fontsize=7.5, va="top", ha="center")
194
+
195
+ ax_km.set_xticks(time_points)
196
+ ax_km.set_xlabel(time_unit, fontsize=9)
197
+
198
+ plt.suptitle("Kaplan-Meier Survival Curves", fontsize=10, y=1.01, fontweight="bold")
199
+ plt.tight_layout()
200
+
201
+ for ext in ["pdf", "png"]:
202
+ outfile = f"{output_path}_km.{ext}"
203
+ dpi = 300 if ext == "png" else None
204
+ plt.savefig(outfile, dpi=dpi, bbox_inches="tight",
205
+ facecolor="white", edgecolor="none")
206
+ print(f"Saved: {outfile}")
207
+ plt.close()
208
+
209
+
210
+ def cox_analysis(df, time_col, event_col, covariates, output_path="survival",
211
+ cluster_col=None):
212
+ """Cox proportional hazards model.
213
+
214
+ cluster_col: id column for nested observation units (e.g. multiple lesions /
215
+ eyes / repeated episodes per subject). When set, lifelines computes a robust
216
+ (cluster-sandwich) variance so the HR CIs reflect within-subject correlation
217
+ rather than treating correlated rows as independent.
218
+ """
219
+ keep = [time_col, event_col] + covariates + ([cluster_col] if cluster_col else [])
220
+ model_df = df[keep].dropna()
221
+ print(f"\n── Cox PH Model (N = {len(model_df)}) ───────────────────────")
222
+
223
+ # Events-per-variable (EPV) gate — mirror of the logistic EPV rule. A Wald CI
224
+ # from a sparse-event model is not stable; warn and rely on the penalizer.
225
+ n_events = int(model_df[event_col].sum())
226
+ epv = n_events / max(len(covariates), 1)
227
+ print(f"EPV = {epv:.1f} ({n_events} events / {len(covariates)} covariates; "
228
+ f"minimum recommended: 10)")
229
+ if epv < 10:
230
+ print("⚠ WARNING: EPV < 10 — Cox estimates may be unstable. The penalized "
231
+ "fit (penalizer=0.1) shrinks coefficients; consider Firth/penalized "
232
+ "Cox or profile-likelihood CIs and interpret Wald CIs with caution.")
233
+
234
+ cph = CoxPHFitter(penalizer=0.1)
235
+ fit_kw = {"duration_col": time_col, "event_col": event_col}
236
+ if cluster_col:
237
+ fit_kw["cluster_col"] = cluster_col # robust (cluster-sandwich) SE
238
+ print(f"Robust cluster-sandwich SE on '{cluster_col}' (nested units).")
239
+ cph.fit(model_df, **fit_kw)
240
+ cph.print_summary()
241
+
242
+ # Check PH assumption
243
+ print("\n── Proportional Hazards Assumption (Schoenfeld residuals) ───")
244
+ try:
245
+ cph.check_assumptions(model_df, p_value_threshold=0.05, show_plots=False)
246
+ except Exception as e:
247
+ print(f" PH assumption check: {e}")
248
+
249
+ # Save results table
250
+ summary = cph.summary.copy()
251
+ summary.columns = [c.replace(" ", "_") for c in summary.columns]
252
+ outfile = f"{output_path}_cox_results.csv"
253
+ summary.to_csv(outfile)
254
+ print(f"\nSaved: {outfile}")
255
+
256
+ # Concordance index
257
+ print(f"\nConcordance index (C-statistic): {cph.concordance_index_:.3f}")
258
+
259
+ return cph
260
+
261
+
262
+ def rmst_analysis(df, time_col, event_col, group_col, t_star, output_path="survival"):
263
+ """Restricted Mean Survival Time analysis."""
264
+ if group_col not in df.columns:
265
+ return
266
+
267
+ groups = df[group_col].dropna().unique()
268
+ print(f"\n── Restricted Mean Survival Time (t* = {t_star}) ────────────")
269
+ for g in groups:
270
+ d = df[df[group_col] == g]
271
+ kmf = KaplanMeierFitter()
272
+ kmf.fit(d[time_col], d[event_col])
273
+ rmst = restricted_mean_survival_time(kmf, t=t_star)
274
+ print(f" {g}: RMST = {rmst:.2f}")
275
+
276
+
277
+ def main():
278
+ parser = argparse.ArgumentParser(description="Survival analysis")
279
+ parser.add_argument("--input", required=True)
280
+ parser.add_argument("--time", required=True, help="Time column name")
281
+ parser.add_argument("--event", required=True, help="Event column name (1=event, 0=censored)")
282
+ parser.add_argument("--group", default=None)
283
+ parser.add_argument("--covariates", nargs="+", default=None)
284
+ parser.add_argument("--cluster", default=None,
285
+ help="ID column for nested units → robust cluster SE in Cox")
286
+ parser.add_argument("--time-unit", default="Months")
287
+ parser.add_argument("--rmst-t", type=float, default=None,
288
+ help="t* for RMST (in same units as time)")
289
+ parser.add_argument("--output", default="survival_analysis")
290
+
291
+ args = parser.parse_args()
292
+
293
+ df = load_data(args.input, args.time, args.event)
294
+ print(f"\nN = {len(df)} | Events: {df[args.event].sum()} "
295
+ f"({df[args.event].mean()*100:.1f}%)")
296
+
297
+ print("\n── Kaplan-Meier Analysis ────────────────────")
298
+ km_analysis(df, args.time, args.event, args.group,
299
+ args.time_unit, args.output)
300
+
301
+ if args.covariates:
302
+ cox_analysis(df, args.time, args.event, args.covariates, args.output,
303
+ cluster_col=args.cluster)
304
+
305
+ if args.rmst_t and args.group:
306
+ rmst_analysis(df, args.time, args.event, args.group,
307
+ args.rmst_t, args.output)
308
+
309
+ print(f"\n── Session Info ─────────────────────────────")
310
+ print(f"Python: {sys.version.split()[0]}")
311
+ for pkg in ["lifelines", "pandas", "numpy", "scipy"]:
312
+ try:
313
+ import importlib
314
+ m = importlib.import_module(pkg)
315
+ print(f" {pkg}: {m.__version__}")
316
+ except Exception:
317
+ pass
318
+
319
+
320
+ if __name__ == "__main__":
321
+ if len(sys.argv) == 1:
322
+ print("Usage: python survival_analysis.py --input data.csv "
323
+ "--time time_months --event event --group treatment")
324
+ else:
325
+ main()
@@ -0,0 +1,287 @@
1
+ """
2
+ Template: Table 1 — Baseline Demographics
3
+ Generates a publication-ready demographics table from tabular data.
4
+
5
+ Usage:
6
+ Modify the CONFIGURATION section below, then run:
7
+ python table1_demographics.py
8
+
9
+ Input: CSV or Excel file with one row per subject
10
+ Output: table1_demographics.csv, table1_demographics.md (console), summary text
11
+ """
12
+
13
+ # === REPRODUCIBILITY HEADER ===
14
+ import sys
15
+ import datetime
16
+ import numpy as np
17
+ import pandas as pd
18
+ from scipy import stats
19
+
20
+ np.random.seed(42)
21
+ print(f"Date: {datetime.date.today()}")
22
+ print(f"Python: {sys.version}")
23
+ print(f"numpy: {np.__version__}, pandas: {pd.__version__}, scipy: {stats.scipy.__version__}")
24
+ print()
25
+
26
+ # === CONFIGURATION (modify for your study) ===
27
+ INPUT_FILE = "data.csv" # Path to input data
28
+ OUTPUT_DIR = "." # Output directory
29
+ GROUP_COL = None # Column name for group comparison (None = no comparison)
30
+ CONTINUOUS_VARS = [] # List of continuous variable column names
31
+ CATEGORICAL_VARS = [] # List of categorical variable column names
32
+ VAR_LABELS = {} # Optional display labels: {"col_name": "Display Name (unit)"}
33
+ DECIMAL_PLACES = 1 # Decimal places for continuous variables
34
+ # ==============================================
35
+
36
+
37
+ def load_data(filepath: str) -> pd.DataFrame:
38
+ """Load CSV or Excel file."""
39
+ if filepath.endswith((".xlsx", ".xls")):
40
+ return pd.read_excel(filepath)
41
+ return pd.read_csv(filepath)
42
+
43
+
44
+ def test_normality(series: pd.Series, alpha: float = 0.05) -> tuple:
45
+ """Test normality using Shapiro-Wilk (n<50) or Kolmogorov-Smirnov (n>=50)."""
46
+ clean = series.dropna()
47
+ if len(clean) < 3:
48
+ return False, np.nan
49
+ if len(clean) < 50:
50
+ stat, p = stats.shapiro(clean)
51
+ else:
52
+ stat, p = stats.kstest(clean, "norm", args=(clean.mean(), clean.std()))
53
+ return p >= alpha, p
54
+
55
+
56
+ def format_continuous(series: pd.Series, is_normal: bool, dp: int = 1) -> str:
57
+ """Format continuous variable as mean +/- SD or median (IQR)."""
58
+ clean = series.dropna()
59
+ if is_normal:
60
+ return f"{clean.mean():.{dp}f} +/- {clean.std():.{dp}f}"
61
+ else:
62
+ q1, median, q3 = clean.quantile([0.25, 0.5, 0.75])
63
+ return f"{median:.{dp}f} ({q1:.{dp}f}-{q3:.{dp}f})"
64
+
65
+
66
+ def format_categorical(series: pd.Series) -> dict:
67
+ """Format categorical variable as n (%)."""
68
+ counts = series.value_counts(dropna=False)
69
+ total = len(series)
70
+ result = {}
71
+ for cat, n in counts.items():
72
+ pct = 100.0 * n / total if total > 0 else 0.0
73
+ label = str(cat) if pd.notna(cat) else "Missing"
74
+ result[label] = f"{n} ({pct:.1f}%)"
75
+ return result
76
+
77
+
78
+ def compare_continuous(groups: list, is_normal: bool) -> tuple:
79
+ """Compare continuous variable between groups."""
80
+ clean_groups = [g.dropna() for g in groups]
81
+ if len(clean_groups) == 2:
82
+ if is_normal:
83
+ stat, p = stats.ttest_ind(*clean_groups)
84
+ return "t-test", p
85
+ else:
86
+ stat, p = stats.mannwhitneyu(*clean_groups, alternative="two-sided")
87
+ return "Mann-Whitney U", p
88
+ else:
89
+ if is_normal:
90
+ stat, p = stats.f_oneway(*clean_groups)
91
+ return "ANOVA", p
92
+ else:
93
+ stat, p = stats.kruskal(*clean_groups)
94
+ return "Kruskal-Wallis", p
95
+
96
+
97
+ def compare_categorical(contingency: pd.DataFrame) -> tuple:
98
+ """Compare categorical variable between groups using chi-square or Fisher's exact."""
99
+ table = contingency.values
100
+ # Use Fisher's exact test for 2x2 tables with any expected count < 5
101
+ if table.shape == (2, 2):
102
+ expected = stats.chi2_contingency(table, correction=False)[3]
103
+ if (expected < 5).any():
104
+ odds_ratio, p = stats.fisher_exact(table)
105
+ return "Fisher's exact", p
106
+ # Otherwise chi-square (with Yates' correction for 2x2)
107
+ chi2, p, dof, expected = stats.chi2_contingency(table)
108
+ if (expected < 5).any():
109
+ print(f" Warning: expected counts < 5 in some cells; consider collapsing categories.")
110
+ return "Chi-square", p
111
+
112
+
113
+ def format_p(p: float) -> str:
114
+ """Format p-value per reporting rules."""
115
+ if pd.isna(p):
116
+ return ""
117
+ if p < 0.001:
118
+ return "<0.001"
119
+ return f"{p:.3f}"
120
+
121
+
122
+ def build_table1(df: pd.DataFrame) -> pd.DataFrame:
123
+ """Build the full Table 1 dataframe."""
124
+ rows = []
125
+ test_footnotes = set()
126
+
127
+ if GROUP_COL and GROUP_COL in df.columns:
128
+ groups = df[GROUP_COL].dropna().unique()
129
+ groups = sorted(groups, key=str)
130
+ group_dfs = {str(g): df[df[GROUP_COL] == g] for g in groups}
131
+ else:
132
+ groups = []
133
+ group_dfs = {}
134
+
135
+ n_row = {"Variable": "n"}
136
+ if group_dfs:
137
+ for g_name, g_df in group_dfs.items():
138
+ n_row[g_name] = str(len(g_df))
139
+ n_row["Overall"] = str(len(df))
140
+ if group_dfs:
141
+ n_row["p-value"] = ""
142
+ n_row["Test"] = ""
143
+ rows.append(n_row)
144
+
145
+ # --- Continuous variables ---
146
+ for var in CONTINUOUS_VARS:
147
+ if var not in df.columns:
148
+ print(f"Warning: '{var}' not found in data, skipping.")
149
+ continue
150
+ label = VAR_LABELS.get(var, var)
151
+ is_normal, norm_p = test_normality(df[var])
152
+ stat_type = "mean +/- SD" if is_normal else "median (IQR)"
153
+
154
+ row = {"Variable": f"{label}, {stat_type}"}
155
+ row["Overall"] = format_continuous(df[var], is_normal, DECIMAL_PLACES)
156
+
157
+ if group_dfs:
158
+ for g_name, g_df in group_dfs.items():
159
+ row[g_name] = format_continuous(g_df[var], is_normal, DECIMAL_PLACES)
160
+ grp_series = [g_df[var] for g_df in group_dfs.values()]
161
+ test_name, p_val = compare_continuous(grp_series, is_normal)
162
+ row["p-value"] = format_p(p_val)
163
+ row["Test"] = test_name
164
+ test_footnotes.add(test_name)
165
+
166
+ rows.append(row)
167
+
168
+ # --- Categorical variables ---
169
+ for var in CATEGORICAL_VARS:
170
+ if var not in df.columns:
171
+ print(f"Warning: '{var}' not found in data, skipping.")
172
+ continue
173
+ label = VAR_LABELS.get(var, var)
174
+
175
+ # Header row for this variable
176
+ header_row = {"Variable": f"{label}, n (%)"}
177
+
178
+ if group_dfs:
179
+ contingency = pd.crosstab(df[var], df[GROUP_COL])
180
+ test_name, p_val = compare_categorical(contingency)
181
+ header_row["p-value"] = format_p(p_val)
182
+ header_row["Test"] = test_name
183
+ test_footnotes.add(test_name)
184
+ for g_name in group_dfs:
185
+ header_row[g_name] = ""
186
+ header_row["Overall"] = ""
187
+ rows.append(header_row)
188
+
189
+ # Category rows
190
+ all_cats = format_categorical(df[var])
191
+ for cat_label, cat_val in all_cats.items():
192
+ cat_row = {"Variable": f" {cat_label}"}
193
+ cat_row["Overall"] = cat_val
194
+ if group_dfs:
195
+ for g_name, g_df in group_dfs.items():
196
+ cat_counts = format_categorical(g_df[var])
197
+ cat_row[g_name] = cat_counts.get(cat_label, "0 (0.0%)")
198
+ cat_row["p-value"] = ""
199
+ cat_row["Test"] = ""
200
+ rows.append(cat_row)
201
+
202
+ # Build dataframe
203
+ table_df = pd.DataFrame(rows)
204
+
205
+ # Reorder columns
206
+ col_order = ["Variable"]
207
+ if group_dfs:
208
+ col_order += [str(g) for g in sorted(groups, key=str)]
209
+ col_order += ["Overall"]
210
+ if group_dfs:
211
+ col_order += ["p-value", "Test"]
212
+ table_df = table_df[col_order]
213
+
214
+ print("\n--- Test Methods Used ---")
215
+ for t in sorted(test_footnotes):
216
+ print(f" - {t}")
217
+ print()
218
+
219
+ return table_df
220
+
221
+
222
+ def save_outputs(table_df: pd.DataFrame) -> None:
223
+ """Save table as CSV and print markdown version."""
224
+ import os
225
+ csv_path = os.path.join(OUTPUT_DIR, "table1_demographics.csv")
226
+
227
+ # Save CSV (without Test column for manuscript)
228
+ export_df = table_df.drop(columns=["Test"], errors="ignore")
229
+ export_df.to_csv(csv_path, index=False)
230
+ print(f"Saved: {csv_path}")
231
+
232
+ # Print markdown table
233
+ print("\n--- Table 1. Baseline Characteristics ---\n")
234
+ print(export_df.to_markdown(index=False))
235
+
236
+
237
+ def print_results_text(df: pd.DataFrame, table_df: pd.DataFrame) -> None:
238
+ """Print copy-paste-ready text for Results section."""
239
+ print("\n--- Results Text (copy-paste ready) ---\n")
240
+ n_total = len(df)
241
+
242
+ if GROUP_COL and GROUP_COL in df.columns:
243
+ groups = df[GROUP_COL].dropna().unique()
244
+ group_counts = df[GROUP_COL].value_counts()
245
+ parts = [f"{g} (n = {group_counts[g]})" for g in sorted(groups, key=str)]
246
+ print(f"A total of {n_total} subjects were included and divided into "
247
+ f"{len(groups)} groups: {', '.join(parts)}. "
248
+ f"Baseline characteristics are summarized in Table 1.")
249
+ else:
250
+ print(f"A total of {n_total} subjects were included. "
251
+ f"Baseline characteristics are summarized in Table 1.")
252
+
253
+ # Report missing data
254
+ missing = df[CONTINUOUS_VARS + CATEGORICAL_VARS].isnull().sum()
255
+ missing = missing[missing > 0]
256
+ if len(missing) > 0:
257
+ print(f"\nMissing data: ", end="")
258
+ parts = [f"{VAR_LABELS.get(col, col)}: {n} ({100*n/len(df):.1f}%)"
259
+ for col, n in missing.items()]
260
+ print("; ".join(parts) + ".")
261
+
262
+
263
+ # === MAIN ===
264
+ if __name__ == "__main__":
265
+ print("=" * 60)
266
+ print("Table 1: Baseline Demographics")
267
+ print("=" * 60)
268
+
269
+ df = load_data(INPUT_FILE)
270
+ print(f"\nLoaded: {INPUT_FILE} ({df.shape[0]} rows, {df.shape[1]} columns)")
271
+
272
+ # Auto-detect if CONTINUOUS_VARS and CATEGORICAL_VARS are empty
273
+ if not CONTINUOUS_VARS and not CATEGORICAL_VARS:
274
+ print("\nNo variables specified. Auto-detecting from data types...")
275
+ for col in df.columns:
276
+ if col == GROUP_COL:
277
+ continue
278
+ if pd.api.types.is_numeric_dtype(df[col]) and df[col].nunique() > 10:
279
+ CONTINUOUS_VARS.append(col)
280
+ print(f" Continuous: {col}")
281
+ elif df[col].nunique() <= 20:
282
+ CATEGORICAL_VARS.append(col)
283
+ print(f" Categorical: {col}")
284
+
285
+ table_df = build_table1(df)
286
+ save_outputs(table_df)
287
+ print_results_text(df, table_df)