General
poster-presentation - Claude MCP Skill
Create scientific conference posters as native, editable .pptx files using python-pptx. Handles A0/A1 layouts, section placement, figure insertion, and academic color schemes. Exports editable .pptx and PDF. Use when the user wants a directly editable PowerPoint poster; for HTML/CSS-based posters exported to PDF/PPTX use pptx-posters, and for standard LaTeX posters use latex-posters.
SEO Guide: Enhance your AI agent with the poster-presentation tool. This Model Context Protocol (MCP) server allows Claude Desktop and other LLMs to create scientific conference posters as native, editable .pptx files using python-pptx. handles a0/a... Download and configure this skill to unlock new capabilities for your AI workflow.
Documentation
SKILL.md# Scientific Conference Poster β PowerPoint (.pptx)
## Overview
This skill creates professional scientific conference posters as editable PowerPoint (.pptx) files using `python-pptx`. It supports standard conference poster sizes (A0, A1), landscape and portrait orientations, structured academic sections, figure insertion with captions, and publication-quality academic color schemes.
The generated `.pptx` is fully editable, allowing researchers to fine-tune layout, fonts, and colors using Microsoft PowerPoint, LibreOffice Impress, or any compatible application. PDF export is available via LibreOffice or PowerPoint.
---
## When to Use This Skill
Use this skill when:
- Creating a poster for an academic conference, symposium, or workshop
- Converting a research paper or manuscript into poster format
- Building a poster template for a research group or institution
- Presenting preliminary results, thesis work, or funded project outcomes
- Needing an editable (non-PDF) poster that collaborators can update
**Trigger phrases:**
- "Create a conference poster as a PowerPoint / .pptx"
- "Make me a scientific poster I can edit in PowerPoint"
- "Generate a poster for my paper / conference / symposium"
- "Build an A0 / A1 poster for [conference name]"
- "Create a research poster with sections for methods, results, conclusions"
---
## Prerequisites
Install required Python packages before running any poster generation code:
```bash
pip install python-pptx Pillow
```
For PDF export from the command line:
```bash
# macOS (via Homebrew)
brew install --cask libreoffice
# Ubuntu / Debian
sudo apt-get install libreoffice
# Windows β download from https://www.libreoffice.org/
```
---
## Standard Poster Dimensions
| Format | Orientation | Width (cm) | Height (cm) | Width (in) | Height (in) | Common use |
|----------|-------------|------------|-------------|------------|-------------|---------------------|
| A0 | Portrait | 84.1 | 118.9 | 33.11 | 46.81 | European conferences|
| A0 | Landscape | 118.9 | 84.1 | 46.81 | 33.11 | US / mixed format |
| A1 | Portrait | 59.4 | 84.1 | 23.39 | 33.11 | Smaller venues |
| A1 | Landscape | 84.1 | 59.4 | 33.11 | 23.39 | Departmental events |
| 36Γ48 in | Portrait | 91.44 | 121.92 | 36.0 | 48.0 | US conferences |
| 48Γ36 in | Landscape | 121.92 | 91.44 | 48.0 | 36.0 | US conferences |
**python-pptx uses EMUs (English Metric Units): 1 inch = 914400 EMU, 1 cm = 360000 EMU**
---
## Workflow Phases
### Phase 1: Gather Content
Collect all poster content from the user or source document:
1. **Title** β full paper/poster title
2. **Authors** β list with superscript affiliation numbers
3. **Affiliations** β institution names linked to authors
4. **Contact / corresponding author** email
5. **Abstract** β 150β250 words
6. **Introduction / Background** β key context and motivation (3β5 bullet points or short paragraphs)
7. **Methods** β concise description with optional workflow figure
8. **Results** β key findings, data visualizations, tables
9. **Conclusions** β 4β6 bullet points
10. **Acknowledgements** β funding sources, collaborators
11. **References** β 5β10 key references (abbreviated format)
12. **Figures** β file paths to images/plots to embed
13. **Logo(s)** β institutional/conference logo paths
14. **Color scheme** β preferred colors or institution palette (see schemes below)
### Phase 2: Plan Layout
Standard two- or three-column academic poster layout:
```
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β LOGO β TITLE / AUTHORS / AFFILIATIONS β LOGO β
βββββββββββββββββββ¬βββββββββββββββββ¬βββββββββββββββββββββββββ€
β Introduction β Methods β Results β
β β β β
β Background β Workflow β Figure 1 β
β β Figure β β
βββββββββββββββββββ΄βββββββββββββββββ€ Figure 2 β
β [Optional middle spanning row] β β
βββββββββββββββββββ¬βββββββββββββββββΌβββββββββββββββββββββββββ€
β Conclusions β Acknowledgementsβ References β
βββββββββββββββββββ΄βββββββββββββββββ΄βββββββββββββββββββββββββ
```
### Phase 3: Generate .pptx
Use the code templates below to build the poster programmatically.
### Phase 4: Export
- Save as `.pptx` (primary deliverable β fully editable)
- Export to PDF via LibreOffice or PowerPoint (see export section)
- Verify layout at 100% zoom before delivering
---
## Core Code: Poster Foundation
```python
"""
scientific_poster.py β Generate A0 landscape conference poster as .pptx
Requires: python-pptx, Pillow
"""
from pptx import Presentation
from pptx.util import Inches, Pt, Emu, Cm
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
from pptx.util import Inches, Pt
import os
# ββ Dimensions ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# A0 Landscape: 118.9 cm Γ 84.1 cm
POSTER_WIDTH_CM = 118.9
POSTER_HEIGHT_CM = 84.1
def cm(value):
"""Convert centimetres to EMUs."""
return Cm(value)
def create_poster(output_path: str = "poster.pptx") -> Presentation:
"""Create and return a blank poster Presentation at A0 landscape size."""
prs = Presentation()
prs.slide_width = cm(POSTER_WIDTH_CM)
prs.slide_height = cm(POSTER_HEIGHT_CM)
# Remove all default placeholder layouts β use blank slide
slide_layout = prs.slide_layouts[6] # index 6 = blank
slide = prs.slides.add_slide(slide_layout)
return prs, slide
```
---
## Academic Color Schemes
```python
# ββ Color Palettes ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
SCHEMES = {
"classic_blue": {
"header_bg": RGBColor(0x1A, 0x3A, 0x5C), # dark navy
"header_text": RGBColor(0xFF, 0xFF, 0xFF), # white
"section_bg": RGBColor(0xD6, 0xE4, 0xF0), # light blue
"section_header": RGBColor(0x1A, 0x3A, 0x5C),
"body_text": RGBColor(0x1A, 0x1A, 0x1A),
"accent": RGBColor(0xE8, 0x8A, 0x00), # amber
"background": RGBColor(0xF5, 0xF7, 0xFA),
},
"green_academic": {
"header_bg": RGBColor(0x1B, 0x4B, 0x36), # forest green
"header_text": RGBColor(0xFF, 0xFF, 0xFF),
"section_bg": RGBColor(0xD8, 0xED, 0xE3), # light green
"section_header": RGBColor(0x1B, 0x4B, 0x36),
"body_text": RGBColor(0x1A, 0x1A, 0x1A),
"accent": RGBColor(0xC0, 0x39, 0x2B), # red
"background": RGBColor(0xF4, 0xF9, 0xF6),
},
"crimson_grey": {
"header_bg": RGBColor(0x8B, 0x00, 0x00), # crimson
"header_text": RGBColor(0xFF, 0xFF, 0xFF),
"section_bg": RGBColor(0xF0, 0xE8, 0xE8), # blush
"section_header": RGBColor(0x8B, 0x00, 0x00),
"body_text": RGBColor(0x1A, 0x1A, 0x1A),
"accent": RGBColor(0x2C, 0x3E, 0x50), # slate
"background": RGBColor(0xFA, 0xF9, 0xF9),
},
"purple_modern": {
"header_bg": RGBColor(0x4A, 0x14, 0x8C), # deep purple
"header_text": RGBColor(0xFF, 0xFF, 0xFF),
"section_bg": RGBColor(0xED, 0xE7, 0xF6), # lavender
"section_header": RGBColor(0x4A, 0x14, 0x8C),
"body_text": RGBColor(0x1A, 0x1A, 0x1A),
"accent": RGBColor(0xF5, 0x7C, 0x00), # orange
"background": RGBColor(0xFA, 0xF8, 0xFF),
},
"monochrome": {
"header_bg": RGBColor(0x21, 0x21, 0x21),
"header_text": RGBColor(0xFF, 0xFF, 0xFF),
"section_bg": RGBColor(0xEE, 0xEE, 0xEE),
"section_header": RGBColor(0x21, 0x21, 0x21),
"body_text": RGBColor(0x1A, 0x1A, 0x1A),
"accent": RGBColor(0x75, 0x75, 0x75),
"background": RGBColor(0xFF, 0xFF, 0xFF),
},
}
DEFAULT_SCHEME = "classic_blue"
```
---
## Helper Functions
```python
# ββ Drawing helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
from pptx.oxml.ns import qn
from lxml import etree
def set_background_color(slide, color: RGBColor):
"""Fill the slide background with a solid color."""
background = slide.background
fill = background.fill
fill.solid()
fill.fore_color.rgb = color
def add_filled_rectangle(slide, left, top, width, height,
fill_color: RGBColor, line_color=None, line_width_pt=0):
"""Add a solid filled rectangle shape (used for section boxes and header)."""
shape = slide.shapes.add_shape(
1, # MSO_SHAPE_TYPE.RECTANGLE
left, top, width, height
)
shape.fill.solid()
shape.fill.fore_color.rgb = fill_color
if line_color:
shape.line.color.rgb = line_color
shape.line.width = Pt(line_width_pt)
else:
shape.line.fill.background() # no border
return shape
def add_textbox(slide, left, top, width, height, text: str,
font_size: int, font_color: RGBColor,
bold=False, italic=False, alignment=PP_ALIGN.LEFT,
word_wrap=True, font_name="Calibri"):
"""Add a text box with specified formatting."""
txBox = slide.shapes.add_textbox(left, top, width, height)
tf = txBox.text_frame
tf.word_wrap = word_wrap
p = tf.paragraphs[0]
p.alignment = alignment
run = p.add_run()
run.text = text
font = run.font
font.name = font_name
font.size = Pt(font_size)
font.color.rgb = font_color
font.bold = bold
font.italic = italic
return txBox
def add_multiline_textbox(slide, left, top, width, height, lines: list,
font_size: int, font_color: RGBColor,
bold_first=False, font_name="Calibri",
bullet=False, line_spacing_pt=None):
"""
Add a text box with multiple paragraphs (one per item in `lines`).
If bullet=True, prepends 'β’ ' to each line.
"""
txBox = slide.shapes.add_textbox(left, top, width, height)
tf = txBox.text_frame
tf.word_wrap = True
for i, line in enumerate(lines):
if i == 0:
p = tf.paragraphs[0]
else:
p = tf.add_paragraph()
p.alignment = PP_ALIGN.LEFT
run = p.add_run()
prefix = "β’ " if bullet else ""
run.text = prefix + line
font = run.font
font.name = font_name
font.size = Pt(font_size)
font.color.rgb = font_color
font.bold = (bold_first and i == 0)
if line_spacing_pt:
from pptx.util import Pt as pPt
from pptx.oxml.ns import qn
pPr = p._pPr
if pPr is None:
pPr = p._p.get_or_add_pPr()
lnSpc = etree.SubElement(pPr, qn("a:lnSpc"))
spcPts = etree.SubElement(lnSpc, qn("a:spcPts"))
spcPts.set("val", str(int(line_spacing_pt * 100)))
return txBox
def add_image(slide, image_path: str, left, top, width, height=None):
"""
Insert an image at the specified position.
If height is None, python-pptx preserves the aspect ratio.
"""
if not os.path.exists(image_path):
print(f"[WARNING] Image not found: {image_path} β skipping.")
return None
if height is None:
pic = slide.shapes.add_picture(image_path, left, top, width=width)
else:
pic = slide.shapes.add_picture(image_path, left, top, width, height)
return pic
def add_section_header(slide, left, top, width, height,
title: str, scheme: dict, font_size=24):
"""Draw a colored section header bar with white text."""
add_filled_rectangle(slide, left, top, width, height,
fill_color=scheme["section_header"])
add_textbox(slide, left + Cm(0.3), top, width - Cm(0.3), height,
text=title,
font_size=font_size,
font_color=scheme["header_text"],
bold=True,
alignment=PP_ALIGN.LEFT)
```
---
## Poster Header Section
```python
def build_header(slide, scheme: dict,
title: str,
authors: str,
affiliations: str,
logo_left_path: str = None,
logo_right_path: str = None,
poster_width_cm: float = POSTER_WIDTH_CM):
"""
Build the full-width header: logos on left/right, title/authors/affiliations centre.
Header height = ~15% of poster height.
"""
HEADER_HEIGHT = cm(12)
LOGO_WIDTH = cm(12)
PADDING = cm(1)
# Background bar
add_filled_rectangle(slide,
left=cm(0), top=cm(0),
width=cm(poster_width_cm), height=HEADER_HEIGHT,
fill_color=scheme["header_bg"])
# Left logo
if logo_left_path and os.path.exists(logo_left_path):
add_image(slide, logo_left_path,
left=PADDING, top=cm(1),
width=LOGO_WIDTH, height=cm(10))
# Right logo
if logo_right_path and os.path.exists(logo_right_path):
add_image(slide, logo_right_path,
left=cm(poster_width_cm) - LOGO_WIDTH - PADDING,
top=cm(1),
width=LOGO_WIDTH, height=cm(10))
# Title β centered
text_left = LOGO_WIDTH + PADDING * 2
text_width = cm(poster_width_cm) - (LOGO_WIDTH + PADDING) * 2
add_textbox(slide,
left=text_left, top=cm(1),
width=text_width, height=cm(5),
text=title,
font_size=52,
font_color=scheme["header_text"],
bold=True,
alignment=PP_ALIGN.CENTER)
add_textbox(slide,
left=text_left, top=cm(6),
width=text_width, height=cm(2.5),
text=authors,
font_size=28,
font_color=scheme["header_text"],
bold=False,
alignment=PP_ALIGN.CENTER)
add_textbox(slide,
left=text_left, top=cm(8.5),
width=text_width, height=cm(2),
text=affiliations,
font_size=22,
font_color=scheme["header_text"],
italic=True,
alignment=PP_ALIGN.CENTER)
```
---
## Section Building Blocks
```python
def build_text_section(slide, left, top, width, height,
section_title: str,
content_lines: list,
scheme: dict,
header_height_cm: float = 2.0,
font_size: int = 20,
bullet: bool = True):
"""
Draw a complete section box: colored header + white body with text lines.
"""
HDR = cm(header_height_cm)
# Section background
add_filled_rectangle(slide, left, top, width, height,
fill_color=scheme["section_bg"],
line_color=scheme["section_header"],
line_width_pt=1.5)
# Section header bar
add_section_header(slide, left, top, width, HDR,
title=section_title, scheme=scheme)
# Body text
add_multiline_textbox(slide,
left=left + cm(0.5),
top=top + HDR + cm(0.3),
width=width - cm(1),
height=height - HDR - cm(0.5),
lines=content_lines,
font_size=font_size,
font_color=scheme["body_text"],
bullet=bullet)
def build_figure_section(slide, left, top, width, height,
section_title: str,
image_path: str,
caption: str,
scheme: dict,
header_height_cm: float = 2.0,
caption_height_cm: float = 2.5):
"""
Draw a section box containing a figure + caption below it.
"""
HDR = cm(header_height_cm)
CAPTION = cm(caption_height_cm)
PAD = cm(0.4)
# Background
add_filled_rectangle(slide, left, top, width, height,
fill_color=scheme["section_bg"],
line_color=scheme["section_header"],
line_width_pt=1.5)
# Header
add_section_header(slide, left, top, width, HDR,
title=section_title, scheme=scheme)
# Image area
img_top = top + HDR + PAD
img_height = height - HDR - CAPTION - PAD * 2
if image_path:
add_image(slide, image_path,
left=left + PAD,
top=img_top,
width=width - PAD * 2,
height=img_height)
else:
# Placeholder grey box when no image provided
add_filled_rectangle(slide,
left=left + PAD, top=img_top,
width=width - PAD * 2, height=img_height,
fill_color=RGBColor(0xCC, 0xCC, 0xCC))
# Caption
add_textbox(slide,
left=left + PAD,
top=top + HDR + PAD + img_height,
width=width - PAD * 2,
height=CAPTION,
text=caption,
font_size=18,
font_color=scheme["body_text"],
italic=True,
alignment=PP_ALIGN.CENTER)
```
---
## Full Poster Assembly β Three-Column A0 Landscape
```python
def build_a0_landscape_poster(
title: str,
authors: str,
affiliations: str,
abstract_lines: list,
intro_lines: list,
methods_lines: list,
results_lines: list,
conclusions_lines: list,
acknowledgements: str,
references_lines: list,
figure1_path: str = None,
figure1_caption: str = "Figure 1.",
figure2_path: str = None,
figure2_caption: str = "Figure 2.",
methods_figure_path: str = None,
methods_figure_caption: str = "Workflow.",
logo_left: str = None,
logo_right: str = None,
color_scheme: str = "classic_blue",
output_path: str = "poster.pptx"
):
"""
Build a complete three-column A0 landscape scientific poster.
Layout (all measurements in cm from top-left origin):
Header: full width, 0β12 cm
Column 1 (left): 0β38 cm wide, 12β82 cm tall
Column 2 (middle): 40β78 cm wide, 12β82 cm tall
Column 3 (right): 80β118 cm wide, 12β82 cm tall
Footer: full width, 82β84.1 cm
"""
scheme = SCHEMES.get(color_scheme, SCHEMES[DEFAULT_SCHEME])
prs, slide = create_poster(output_path)
# Poster background
set_background_color(slide, scheme["background"])
# ββ HEADER ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
build_header(slide, scheme,
title=title, authors=authors, affiliations=affiliations,
logo_left_path=logo_left, logo_right_path=logo_right)
# ββ LAYOUT CONSTANTS ββββββββββββββββββββββββββββββββββββββββββββββββββββ
COL_TOP = cm(12.5)
COL_BOTTOM = cm(82)
COL_HEIGHT = COL_BOTTOM - COL_TOP
GAP = cm(1.5)
C1_LEFT = cm(1)
C1_WIDTH = cm(37)
C2_LEFT = C1_LEFT + C1_WIDTH + GAP
C2_WIDTH = cm(37)
C3_LEFT = C2_LEFT + C2_WIDTH + GAP
C3_WIDTH = cm(POSTER_WIDTH_CM) - C3_LEFT - cm(1)
# ββ COLUMN 1: Abstract + Introduction βββββββββββββββββββββββββββββββββββ
ABSTRACT_H = cm(22)
build_text_section(slide,
left=C1_LEFT, top=COL_TOP,
width=C1_WIDTH, height=ABSTRACT_H,
section_title="Abstract",
content_lines=abstract_lines,
scheme=scheme, bullet=False, font_size=19)
INTRO_H = COL_HEIGHT - ABSTRACT_H - GAP
build_text_section(slide,
left=C1_LEFT, top=COL_TOP + ABSTRACT_H + GAP,
width=C1_WIDTH, height=INTRO_H,
section_title="Introduction & Background",
content_lines=intro_lines,
scheme=scheme, bullet=True, font_size=20)
# ββ COLUMN 2: Methods + Methods Figure ββββββββββββββββββββββββββββββββββ
METHODS_TEXT_H = cm(28)
METHODS_FIG_H = COL_HEIGHT - METHODS_TEXT_H - GAP
build_text_section(slide,
left=C2_LEFT, top=COL_TOP,
width=C2_WIDTH, height=METHODS_TEXT_H,
section_title="Methods",
content_lines=methods_lines,
scheme=scheme, bullet=True, font_size=20)
build_figure_section(slide,
left=C2_LEFT,
top=COL_TOP + METHODS_TEXT_H + GAP,
width=C2_WIDTH, height=METHODS_FIG_H,
section_title="Workflow",
image_path=methods_figure_path,
caption=methods_figure_caption,
scheme=scheme)
# ββ COLUMN 3: Results (2 figures) + Conclusions βββββββββββββββββββββββββ
FIG1_H = cm(26)
FIG2_H = cm(22)
CONCLUSIONS_H = COL_HEIGHT - FIG1_H - FIG2_H - GAP * 2
build_figure_section(slide,
left=C3_LEFT, top=COL_TOP,
width=C3_WIDTH, height=FIG1_H,
section_title="Results",
image_path=figure1_path,
caption=figure1_caption,
scheme=scheme)
build_figure_section(slide,
left=C3_LEFT, top=COL_TOP + FIG1_H + GAP,
width=C3_WIDTH, height=FIG2_H,
section_title="",
image_path=figure2_path,
caption=figure2_caption,
scheme=scheme)
build_text_section(slide,
left=C3_LEFT,
top=COL_TOP + FIG1_H + FIG2_H + GAP * 2,
width=C3_WIDTH, height=CONCLUSIONS_H,
section_title="Conclusions",
content_lines=conclusions_lines,
scheme=scheme, bullet=True, font_size=20)
# ββ FOOTER: Acknowledgements + References βββββββββββββββββββββββββββββββ
FOOTER_TOP = cm(82.5)
FOOTER_H = cm(POSTER_HEIGHT_CM) - FOOTER_TOP
HALF_W = (cm(POSTER_WIDTH_CM) - cm(2)) / 2
build_text_section(slide,
left=cm(1), top=FOOTER_TOP,
width=HALF_W, height=FOOTER_H,
section_title="Acknowledgements",
content_lines=[acknowledgements],
scheme=scheme, bullet=False, font_size=16)
build_text_section(slide,
left=cm(1) + HALF_W + GAP, top=FOOTER_TOP,
width=HALF_W - GAP, height=FOOTER_H,
section_title="References",
content_lines=references_lines,
scheme=scheme, bullet=False, font_size=15)
# ββ SAVE ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
prs.save(output_path)
print(f"[OK] Poster saved: {output_path}")
return output_path
```
---
## Example Usage
```python
if __name__ == "__main__":
build_a0_landscape_poster(
title="Deep Learning for Early Detection of Alzheimer's Disease\nUsing Multimodal Neuroimaging",
authors="J. SmithΒΉ, A. PatelΒ², R. MΓΌllerΒΉ, L. ChenΒ³",
affiliations="ΒΉDept. of Neuroscience, University of Example | Β²Brain Imaging Centre, City Hospital | Β³ML Lab, Tech Institute",
abstract_lines=[
"Alzheimer's disease (AD) affects over 55 million people worldwide. "
"Early and accurate diagnosis remains a significant clinical challenge. "
"We present a multimodal deep learning framework integrating structural MRI, "
"FDG-PET, and cerebrospinal fluid biomarkers to improve early AD detection. "
"Our model achieves 94.2% accuracy on the ADNI dataset, outperforming "
"unimodal baselines by 8.3 percentage points. These results suggest "
"multimodal fusion substantially improves pre-clinical AD diagnosis."
],
intro_lines=[
"Alzheimer's disease is the leading cause of dementia, with costs exceeding $300B/year in the US alone.",
"Current diagnostic methods rely on late-stage symptom presentation, missing the critical early treatment window.",
"Neuroimaging biomarkers (MRI atrophy, PET hypometabolism) show promise but are typically analysed in isolation.",
"Deep learning enables automated feature extraction from high-dimensional neuroimaging data.",
"We hypothesise that multimodal fusion will significantly outperform single-modality approaches for early AD classification.",
],
methods_lines=[
"Dataset: 1,200 subjects from ADNI (400 CN, 400 MCI, 400 AD).",
"Modalities: T1-weighted MRI (3T), FDG-PET, CSF AΞ²42/tau ratios.",
"Preprocessing: FreeSurfer cortical parcellation, SPM12 PET normalisation.",
"Architecture: Three-stream CNN encoders with cross-modal attention fusion.",
"Training: 5-fold cross-validation, AdamW optimiser, cosine LR schedule.",
"Evaluation: Accuracy, AUC-ROC, sensitivity/specificity for CN vs. MCI vs. AD.",
],
results_lines=[
"94.2% overall accuracy (vs. 86.1% MRI-only baseline).",
"AUC-ROC: 0.97 for AD vs. CN; 0.89 for MCI vs. CN.",
"Cross-modal attention identified hippocampus, entorhinal cortex, and precuneus as most predictive.",
"Model generalises across APOE-Ξ΅4 carrier subgroups (p > 0.05 for subgroup differences).",
],
conclusions_lines=[
"Multimodal deep learning significantly improves early AD detection over single-modality approaches.",
"Cross-modal attention provides interpretable biomarker importance maps consistent with known AD pathology.",
"The framework is scanner-agnostic and generalises across genetic risk subgroups.",
"Future work: longitudinal modelling, external validation, prospective clinical study.",
],
acknowledgements="Funded by NIH R01-AG012345 and the Alzheimer's Association Research Grant #AARG-22-000123. "
"Data provided by the Alzheimer's Disease Neuroimaging Initiative (ADNI). "
"Computing resources from the National Center for Supercomputing Applications.",
references_lines=[
"[1] Jack et al. (2018). NIA-AA Research Framework. Alzheimer's & Dementia, 14, 535β562.",
"[2] Litjens et al. (2017). A survey on deep learning in medical image analysis. Med. Im. Analysis, 42, 60β88.",
"[3] Ngiam et al. (2011). Multimodal deep learning. ICML 2011.",
"[4] Zhang et al. (2022). Multimodal neuroimaging fusion for AD. NeuroImage, 249, 118907.",
"[5] Petersen et al. (2014). ADNI: 10 years. Arch Neurol, 71, 806β813.",
],
figure1_path="figures/roc_curves.png",
figure1_caption="Figure 1. ROC curves for AD vs. CN (AUC = 0.97), MCI vs. CN (AUC = 0.89), and AD vs. MCI (AUC = 0.91).",
figure2_path="figures/attention_map.png",
figure2_caption="Figure 2. Cross-modal attention heatmaps overlaid on MRI showing hippocampal and entorhinal activation.",
methods_figure_path="figures/architecture.png",
methods_figure_caption="Figure 3. Three-stream CNN architecture with cross-modal attention fusion module.",
logo_left="logos/university_logo.png",
logo_right="logos/funder_logo.png",
color_scheme="classic_blue",
output_path="poster_ad_multimodal.pptx"
)
```
---
## Portrait Poster (A0 / A1)
For portrait orientation, adjust dimensions and use a two-column layout:
```python
# A0 Portrait: 84.1 cm Γ 118.9 cm
def create_portrait_poster(output_path="poster_portrait.pptx"):
prs = Presentation()
prs.slide_width = Cm(84.1)
prs.slide_height = Cm(118.9)
slide_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(slide_layout)
return prs, slide
# A1 Landscape: 84.1 cm Γ 59.4 cm
def create_a1_landscape(output_path="poster_a1.pptx"):
prs = Presentation()
prs.slide_width = Cm(84.1)
prs.slide_height = Cm(59.4)
slide_layout = prs.slide_layouts[6]
slide = prs.slides.add_slide(slide_layout)
return prs, slide
```
---
## PDF Export
### Via LibreOffice (command line β cross-platform)
```bash
# Export .pptx to PDF using LibreOffice headless mode
libreoffice --headless --convert-to pdf poster_ad_multimodal.pptx --outdir ./
# Or specify output directory
libreoffice --headless --convert-to pdf:impress_pdf_Export poster.pptx --outdir output/
```
### Via Python subprocess
```python
import subprocess
import os
def export_to_pdf(pptx_path: str, output_dir: str = ".") -> str:
"""Convert .pptx to PDF using LibreOffice."""
os.makedirs(output_dir, exist_ok=True)
result = subprocess.run(
["libreoffice", "--headless", "--convert-to", "pdf",
pptx_path, "--outdir", output_dir],
capture_output=True, text=True
)
if result.returncode != 0:
raise RuntimeError(f"LibreOffice conversion failed:\n{result.stderr}")
pdf_name = os.path.splitext(os.path.basename(pptx_path))[0] + ".pdf"
pdf_path = os.path.join(output_dir, pdf_name)
print(f"[OK] PDF exported: {pdf_path}")
return pdf_path
```
---
## Verification Checklist
Before delivering the poster:
- [ ] Title, authors, affiliations render correctly in header
- [ ] All sections have content (no empty boxes)
- [ ] All referenced image files exist and load without warnings
- [ ] Text is not clipped or overflowing section boxes (check at 100% zoom)
- [ ] Font sizes are legible at the target print size (β₯18pt for body, β₯24pt for section headers)
- [ ] Color scheme is consistent throughout
- [ ] .pptx opens correctly in both PowerPoint and LibreOffice
- [ ] PDF export renders without distortion
---
## Common Issues and Fixes
| Problem | Likely cause | Fix |
|---------|-------------|-----|
| Text overflows section box | Font size too large / too many lines | Reduce font size or split into two sections |
| Image not inserted | File path wrong or file missing | Check `os.path.exists(path)` before calling `add_image` |
| Wrong poster size | `slide_width`/`slide_height` set in inches, not EMUs | Use `Cm()` or `Inches()` wrappers, not raw integers |
| Logo appears stretched | Width and height both specified with wrong aspect ratio | Set only `width=` and let python-pptx auto-compute height |
| PDF looks different from .pptx | Font not installed on LibreOffice machine | Embed fonts or use system fonts (Calibri β Liberation Sans) |
| Columns misaligned | Arithmetic error in column left/width calculations | Print all `left`, `top`, `width`, `height` values and verify sum |
---
## Integration with Scientific Schematics
For high-quality figures to embed in the poster, use the `scientific-schematics` skill before generating the poster:
```bash
# Generate workflow diagram for Methods section
python <path-to-scientific-schematics-skill>/scripts/generate_schematic.py \
"Three-stream CNN architecture: MRI encoder, PET encoder, CSF encoder feeding into cross-modal attention fusion with final classification layer" \
-o figures/architecture.png
# Generate results figure
python <path-to-scientific-schematics-skill>/scripts/generate_schematic.py \
"ROC curves for three-class neuroimaging classification showing AD vs CN AUC 0.97, MCI vs CN AUC 0.89" \
-o figures/roc_curves.png
```
Then pass the generated file paths as `figure1_path`, `figure2_path`, or `methods_figure_path` arguments to the poster builder.
---
## File Naming Conventions
```
posters/
βββ YYYYMMDD_<short_title>/
βββ poster.pptx # Primary deliverable
βββ poster.pdf # PDF export
βββ generate_poster.py # Generation script (reproducible)
βββ figures/ # Embedded images
βββ fig1_results.png
βββ fig2_attention.png
βββ fig3_architecture.png
```Signals
Information
- Repository
- K-Dense-AI/claude-scientific-writer
- Author
- K-Dense-AI
- Last Sync
- 7/22/2026
- Repo Updated
- 7/22/2026
- Created
- 6/15/2026
Reviews (0)
No reviews yet. Be the first to review this skill!
Related Skills
cursorrules
CrewAI Development Rules
firecrawl-build-search
Integrate Firecrawl `/search` into product code and agent workflows. Use when an app needs discovery before extraction, when the feature starts with a query instead of a URL, or when the system should search the web and optionally hydrate result content.
firecrawl-build-onboarding
Get Firecrawl credentials and SDK setup into a project. Use when an application needs `FIRECRAWL_API_KEY`, when an agent should add Firecrawl to `.env`, when the user wants to authenticate Firecrawl for app code, or when choosing the first SDK and docs for a new Firecrawl integration. This skill includes its own browser auth flow, so it does not depend on the website onboarding skill.
firecrawl-build
Integrate Firecrawl into application code whenever a product, agent, or workflow needs web data inside the app β web search, live search results, page scraping, structured extraction, or browser interaction. Use when building any feature that needs data from the web in code, even if the user does not mention Firecrawl explicitly and only describes wanting web data, website content, search, scraping, or interaction in an application. Trigger for Firecrawl requests, "fire girl" shorthand, and generic app-level web-data needs that should map to `/scrape`, `/search`, or `/interact`. Do not use this skill for one-off terminal-only web tasks during the current session; use `firecrawl/cli` for those.
Related Guides
Mastering the Oracle CLI: A Complete Guide to the Claude Skill for Database Professionals
Learn how to use the oracle Claude skill. Complete guide with installation instructions and examples.
Python Django Best Practices: A Comprehensive Guide to the Claude Skill
Learn how to use the python django best practices Claude skill. Complete guide with installation instructions and examples.
Mastering Python and TypeScript Development with the Claude Skill Guide
Learn how to use the python typescript guide Claude skill. Complete guide with installation instructions and examples.