scientific-figure-assembly
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseScientific Figure Assembly (R-based)
基于R的科学图表组装
Create publication-ready multi-panel figures using R packages (patchwork, cowplot) with professional panel labels (A, B, C, D) at 300 DPI resolution.
⚠️ IMPORTANT: This workflow uses R for figure assembly. For meta-analysis projects, all figures should be generated and assembled in R.
使用R包(patchwork、cowplot)创建带有专业面板标签(A、B、C、D)、分辨率达300 DPI的可直接用于出版的多面板图表。
⚠️ 重要提示:此工作流使用R进行图表组装。对于元分析项目,所有图表都应在R中生成并组装。
When to Use
适用场景
- Combining multiple plots into a single multi-panel figure for publication
- Adding panel labels (A, B, C) to existing figures
- Ensuring figures meet journal requirements (300 DPI minimum)
- Creating consistent figure layouts for manuscripts
- Preparing figures for Nature, Science, Cell, JAMA, Lancet submissions
- 将多个绘图组合成单个多面板图表用于发表
- 为现有图表添加面板标签(A、B、C)
- 确保图表满足期刊要求(最低300 DPI)
- 为手稿创建布局一致的图表
- 为《Nature》《Science》《Cell》《JAMA》《Lancet》等期刊投稿准备图表
Quick Start
快速开始
Tell me:
- Plot objects: R plot objects (ggplot, forest plots, etc.) OR paths to PNG/JPG files
- Layout: Vertical (stacked), horizontal (side-by-side), or grid (2x2, 2x3, etc.)
- Output name: What to call the final figure
- Labels: Which panel labels to use (default: A, B, C, D...)
I'll create an R script using patchwork or cowplot to assemble the figure with proper spacing and labels.
请告知我:
- 绘图对象:R绘图对象(ggplot、森林图等)或PNG/JPG文件路径
- 布局:垂直(堆叠)、水平(并排)或网格(2x2、2x3等)
- 输出名称:最终图表的命名
- 标签:要使用的面板标签(默认:A、B、C、D...)
我将使用patchwork或cowplot创建R脚本,以合适的间距和标签组装图表。
R Package Approach (Recommended)
推荐的R包方法
Method 1: patchwork (For ggplot2 objects)
方法1:patchwork(适用于ggplot2对象)
The simplest and most powerful method for combining ggplot2 objects:
r
library(ggplot2)
library(patchwork)这是组合ggplot2对象最简单且功能最强大的方法:
r
library(ggplot2)
library(patchwork)Create or load individual plots
Create or load individual plots
p1 <- ggplot(data1, aes(x, y)) + geom_point() + ggtitle("A. First Panel")
p2 <- ggplot(data2, aes(x, y)) + geom_line() + ggtitle("B. Second Panel")
p3 <- ggplot(data3, aes(x, y)) + geom_bar(stat="identity") + ggtitle("C. Third Panel")
p1 <- ggplot(data1, aes(x, y)) + geom_point() + ggtitle("A. First Panel")
p2 <- ggplot(data2, aes(x, y)) + geom_line() + ggtitle("B. Second Panel")
p3 <- ggplot(data3, aes(x, y)) + geom_bar(stat="identity") + ggtitle("C. Third Panel")
Combine vertically
Combine vertically
combined <- p1 / p2 / p3
combined <- p1 / p2 / p3
Or combine horizontally
Or combine horizontally
combined <- p1 | p2 | p3
combined <- p1 | p2 | p3
Or grid layout (2 columns)
Or grid layout (2 columns)
combined <- (p1 | p2) / p3
combined <- (p1 | p2) / p3
Export at 300 DPI
Export at 300 DPI
ggsave("figures/figure1_combined.png",
plot = combined,
width = 10, height = 12, dpi = 300)
undefinedggsave("figures/figure1_combined.png",
plot = combined,
width = 10, height = 12, dpi = 300)
undefinedMethod 2: cowplot (For any R plots)
方法2:cowplot(适用于所有R绘图)
More flexible, works with base R plots and ggplot2:
r
library(ggplot2)
library(cowplot)灵活性更高,可用于基础R绘图和ggplot2:
r
library(ggplot2)
library(cowplot)Create individual plots
Create individual plots
p1 <- ggplot(data1, aes(x, y)) + geom_point()
p2 <- ggplot(data2, aes(x, y)) + geom_line()
p3 <- ggplot(data3, aes(x, y)) + geom_bar(stat="identity")
p1 <- ggplot(data1, aes(x, y)) + geom_point()
p2 <- ggplot(data2, aes(x, y)) + geom_line()
p3 <- ggplot(data3, aes(x, y)) + geom_bar(stat="identity")
Combine with automatic panel labels
Combine with automatic panel labels
combined <- plot_grid(
p1, p2, p3,
labels = c("A", "B", "C"),
label_size = 18,
ncol = 1, # Vertical stack
rel_heights = c(1, 1, 1) # Equal heights
)
combined <- plot_grid(
p1, p2, p3,
labels = c("A", "B", "C"),
label_size = 18,
ncol = 1, # Vertical stack
rel_heights = c(1, 1, 1) # Equal heights
)
Export
Export
ggsave("figures/figure1_combined.png",
plot = combined,
width = 10, height = 12, dpi = 300)
undefinedggsave("figures/figure1_combined.png",
plot = combined,
width = 10, height = 12, dpi = 300)
undefinedLegacy Python Script Template (Not Recommended)
遗留Python脚本模板(不推荐)
⚠️ For meta-analysis projects, use R methods above instead.
If you absolutely need Python for existing PNG files:
python
#!/usr/bin/env python3
"""Legacy: Assemble multi-panel scientific figure from PNG files."""
from PIL import Image, ImageDraw, ImageFont
from pathlib import Path
def add_panel_label(img, label, position='top-left',
font_size=80, offset=(40, 40),
bg_color='white', text_color='black',
border=True):
"""
Add panel label (A, B, C) to image.
Args:
img: PIL Image object
label: Label text (e.g., 'A', 'B', 'C')
position: 'top-left', 'top-right', 'bottom-left', 'bottom-right'
font_size: Font size in pixels (80 works well for 3000px wide images)
offset: (x, y) offset from corner in pixels
bg_color: Background color for label box
text_color: Label text color
border: Whether to draw border around label box
"""
draw = ImageDraw.Draw(img)
# Try system fonts (macOS, then Linux)
try:
font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", font_size)
except:
try:
font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", font_size
)
except:
font = ImageFont.load_default()
print(f"Warning: Using default font for label {label}")
# Calculate label position
x, y = offset
if 'right' in position:
bbox = draw.textbbox((0, 0), label, font=font)
text_width = bbox[2] - bbox[0]
x = img.width - text_width - offset[0]
if 'bottom' in position:
bbox = draw.textbbox((0, 0), label, font=font)
text_height = bbox[3] - bbox[1]
y = img.height - text_height - offset[1]
# Draw background box
bbox = draw.textbbox((x, y), label, font=font)
padding = 10
draw.rectangle(
[bbox[0] - padding, bbox[1] - padding,
bbox[2] + padding, bbox[3] + padding],
fill=bg_color,
outline='black' if border else None,
width=2 if border else 0
)
# Draw text
draw.text((x, y), label, fill=text_color, font=font)
return img
def assemble_vertical(input_files, output_file, labels=None,
spacing=40, dpi=300):
"""
Stack images vertically with panel labels.
Args:
input_files: List of paths to input images
output_file: Path for output image
labels: List of labels (default: A, B, C, ...)
spacing: Vertical spacing between panels in pixels
dpi: Output resolution
"""
if labels is None:
labels = [chr(65 + i) for i in range(len(input_files))] # A, B, C, ...
# Load all images
images = [Image.open(f) for f in input_files]
# Add labels
labeled = [add_panel_label(img, label)
for img, label in zip(images, labels)]
# Calculate dimensions
max_width = max(img.width for img in labeled)
total_height = sum(img.height for img in labeled) + spacing * (len(labeled) - 1)
# Create combined image
combined = Image.new('RGB', (max_width, total_height), 'white')
# Paste images
y_offset = 0
for img in labeled:
combined.paste(img, (0, y_offset))
y_offset += img.height + spacing
# Save with specified DPI
combined.save(output_file, dpi=(dpi, dpi))
print(f"✅ Created {output_file}")
print(f" Dimensions: {combined.width}×{combined.height} px at {dpi} DPI")
return output_file
def assemble_horizontal(input_files, output_file, labels=None,
spacing=40, dpi=300):
"""Stack images horizontally with panel labels."""
if labels is None:
labels = [chr(65 + i) for i in range(len(input_files))]
images = [Image.open(f) for f in input_files]
labeled = [add_panel_label(img, label)
for img, label in zip(images, labels)]
max_height = max(img.height for img in labeled)
total_width = sum(img.width for img in labeled) + spacing * (len(labeled) - 1)
combined = Image.new('RGB', (total_width, max_height), 'white')
x_offset = 0
for img in labeled:
combined.paste(img, (x_offset, 0))
x_offset += img.width + spacing
combined.save(output_file, dpi=(dpi, dpi))
print(f"✅ Created {output_file}")
print(f" Dimensions: {combined.width}×{combined.height} px at {dpi} DPI")
return output_file
def assemble_grid(input_files, output_file, rows, cols,
labels=None, spacing=40, dpi=300):
"""
Arrange images in a grid with panel labels.
Args:
rows: Number of rows
cols: Number of columns
Other args same as assemble_vertical
"""
if labels is None:
labels = [chr(65 + i) for i in range(len(input_files))]
images = [Image.open(f) for f in input_files]
labeled = [add_panel_label(img, label)
for img, label in zip(images, labels)]
# Calculate cell dimensions (use max from each row/col)
cell_width = max(img.width for img in labeled)
cell_height = max(img.height for img in labeled)
# Total dimensions
total_width = cell_width * cols + spacing * (cols - 1)
total_height = cell_height * rows + spacing * (rows - 1)
combined = Image.new('RGB', (total_width, total_height), 'white')
# Place images
for idx, img in enumerate(labeled):
if idx >= rows * cols:
break
row = idx // cols
col = idx % cols
x = col * (cell_width + spacing)
y = row * (cell_height + spacing)
combined.paste(img, (x, y))
combined.save(output_file, dpi=(dpi, dpi))
print(f"✅ Created {output_file}")
print(f" Dimensions: {combined.width}×{combined.height} px at {dpi} DPI")
return output_file
if __name__ == '__main__':
import sys
# Example usage
if len(sys.argv) < 3:
print("Usage: python assemble_figures.py <output> <layout> <input1> <input2> ...")
print(" layout: vertical, horizontal, or grid:RxC (e.g., grid:2x2)")
sys.exit(1)
output = sys.argv[1]
layout = sys.argv[2]
inputs = sys.argv[3:]
if layout == 'vertical':
assemble_vertical(inputs, output)
elif layout == 'horizontal':
assemble_horizontal(inputs, output)
elif layout.startswith('grid:'):
rows, cols = map(int, layout.split(':')[1].split('x'))
assemble_grid(inputs, output, rows, cols)
else:
print(f"Unknown layout: {layout}")
sys.exit(1)⚠️ 对于元分析项目,请使用上述R方法。
如果因现有PNG文件确实需要使用Python:
python
#!/usr/bin/env python3
"""Legacy: Assemble multi-panel scientific figure from PNG files."""
from PIL import Image, ImageDraw, ImageFont
from pathlib import Path
def add_panel_label(img, label, position='top-left',
font_size=80, offset=(40, 40),
bg_color='white', text_color='black',
border=True):
"""
Add panel label (A, B, C) to image.
Args:
img: PIL Image object
label: Label text (e.g., 'A', 'B', 'C')
position: 'top-left', 'top-right', 'bottom-left', 'bottom-right'
font_size: Font size in pixels (80 works well for 3000px wide images)
offset: (x, y) offset from corner in pixels
bg_color: Background color for label box
text_color: Label text color
border: Whether to draw border around label box
"""
draw = ImageDraw.Draw(img)
# Try system fonts (macOS, then Linux)
try:
font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", font_size)
except:
try:
font = ImageFont.truetype(
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", font_size
)
except:
font = ImageFont.load_default()
print(f"Warning: Using default font for label {label}")
# Calculate label position
x, y = offset
if 'right' in position:
bbox = draw.textbbox((0, 0), label, font=font)
text_width = bbox[2] - bbox[0]
x = img.width - text_width - offset[0]
if 'bottom' in position:
bbox = draw.textbbox((0, 0), label, font=font)
text_height = bbox[3] - bbox[1]
y = img.height - text_height - offset[1]
# Draw background box
bbox = draw.textbbox((x, y), label, font=font)
padding = 10
draw.rectangle(
[bbox[0] - padding, bbox[1] - padding,
bbox[2] + padding, bbox[3] + padding],
fill=bg_color,
outline='black' if border else None,
width=2 if border else 0
)
# Draw text
draw.text((x, y), label, fill=text_color, font=font)
return img
def assemble_vertical(input_files, output_file, labels=None,
spacing=40, dpi=300):
"""
Stack images vertically with panel labels.
Args:
input_files: List of paths to input images
output_file: Path for output image
labels: List of labels (default: A, B, C, ...)
spacing: Vertical spacing between panels in pixels
dpi: Output resolution
"""
if labels is None:
labels = [chr(65 + i) for i in range(len(input_files))] # A, B, C, ...
# Load all images
images = [Image.open(f) for f in input_files]
# Add labels
labeled = [add_panel_label(img, label)
for img, label in zip(images, labels)]
# Calculate dimensions
max_width = max(img.width for img in labeled)
total_height = sum(img.height for img in labeled) + spacing * (len(labeled) - 1)
# Create combined image
combined = Image.new('RGB', (max_width, total_height), 'white')
# Paste images
y_offset = 0
for img in labeled:
combined.paste(img, (0, y_offset))
y_offset += img.height + spacing
# Save with specified DPI
combined.save(output_file, dpi=(dpi, dpi))
print(f"✅ Created {output_file}")
print(f" Dimensions: {combined.width}×{combined.height} px at {dpi} DPI")
return output_file
def assemble_horizontal(input_files, output_file, labels=None,
spacing=40, dpi=300):
"""Stack images horizontally with panel labels."""
if labels is None:
labels = [chr(65 + i) for i in range(len(input_files))]
images = [Image.open(f) for f in input_files]
labeled = [add_panel_label(img, label)
for img, label in zip(images, labels)]
max_height = max(img.height for img in labeled)
total_width = sum(img.width for img in labeled) + spacing * (len(labeled) - 1)
combined = Image.new('RGB', (total_width, max_height), 'white')
x_offset = 0
for img in labeled:
combined.paste(img, (x_offset, 0))
x_offset += img.width + spacing
combined.save(output_file, dpi=(dpi, dpi))
print(f"✅ Created {output_file}")
print(f" Dimensions: {combined.width}×{combined.height} px at {dpi} DPI")
return output_file
def assemble_grid(input_files, output_file, rows, cols,
labels=None, spacing=40, dpi=300):
"""
Arrange images in a grid with panel labels.
Args:
rows: Number of rows
cols: Number of columns
Other args same as assemble_vertical
"""
if labels is None:
labels = [chr(65 + i) for i in range(len(input_files))]
images = [Image.open(f) for f in input_files]
labeled = [add_panel_label(img, label)
for img, label in zip(images, labels)]
# Calculate cell dimensions (use max from each row/col)
cell_width = max(img.width for img in labeled)
cell_height = max(img.height for img in labeled)
# Total dimensions
total_width = cell_width * cols + spacing * (cols - 1)
total_height = cell_height * rows + spacing * (rows - 1)
combined = Image.new('RGB', (total_width, total_height), 'white')
# Place images
for idx, img in enumerate(labeled):
if idx >= rows * cols:
break
row = idx // cols
col = idx % cols
x = col * (cell_width + spacing)
y = row * (cell_height + spacing)
combined.paste(img, (x, y))
combined.save(output_file, dpi=(dpi, dpi))
print(f"✅ Created {output_file}")
print(f" Dimensions: {combined.width}×{combined.height} px at {dpi} DPI")
return output_file
if __name__ == '__main__':
import sys
# Example usage
if len(sys.argv) < 3:
print("Usage: python assemble_figures.py <output> <layout> <input1> <input2> ...")
print(" layout: vertical, horizontal, or grid:RxC (e.g., grid:2x2)")
sys.exit(1)
output = sys.argv[1]
layout = sys.argv[2]
inputs = sys.argv[3:]
if layout == 'vertical':
assemble_vertical(inputs, output)
elif layout == 'horizontal':
assemble_horizontal(inputs, output)
elif layout.startswith('grid:'):
rows, cols = map(int, layout.split(':')[1].split('x'))
assemble_grid(inputs, output, rows, cols)
else:
print(f"Unknown layout: {layout}")
sys.exit(1)Common Layouts
常见布局
Vertical (Most Common)
垂直布局(最常用)
Stack plots on top of each other - good for showing progression or related outcomes.
Example: Three forest plots (pCR, EFS, OS) stacked vertically
- Panel A: pCR forest plot
- Panel B: EFS forest plot
- Panel C: OS forest plot
将绘图上下堆叠 - 适合展示过程或相关结果。
示例:三个森林图(pCR、EFS、OS)垂直堆叠
- 面板A:pCR森林图
- 面板B:EFS森林图
- 面板C:OS森林图
Horizontal
水平布局
Place plots side-by-side - good for comparisons.
Example: Two funnel plots showing publication bias
- Panel A: pCR funnel plot
- Panel B: EFS funnel plot
将绘图并排摆放 - 适合对比展示。
示例:两个展示发表偏倚的漏斗图
- 面板A:pCR漏斗图
- 面板B:EFS漏斗图
Grid (2x2, 2x3, etc.)
网格布局(2x2、2x3等)
Arrange in rows and columns - good for systematic comparisons.
Example: 2x2 grid of subgroup analyses
- Panel A: Age subgroup
- Panel B: Sex subgroup
- Panel C: Stage subgroup
- Panel D: Histology subgroup
按行和列排列 - 适合系统性对比。
示例:2x2网格的亚组分析
- 面板A:年龄亚组
- 面板B:性别亚组
- 面板C:分期亚组
- 面板D:组织学亚组
R Workflow (Recommended)
推荐的R工作流
Complete Example: Meta-Analysis Forest Plots
完整示例:元分析森林图
r
#!/usr/bin/env Rscriptr
#!/usr/bin/env Rscriptassemble_forest_plots.R
assemble_forest_plots.R
Combine multiple forest plots into a single figure
Combine multiple forest plots into a single figure
library(meta)
library(metafor)
library(patchwork)
library(meta)
library(metafor)
library(patchwork)
Set working directory
Set working directory
setwd("/Users/htlin/meta-pipe/06_analysis")
setwd("/Users/htlin/meta-pipe/06_analysis")
Load extraction data
Load extraction data
data <- read.csv("../05_extraction/extraction.csv")
data <- read.csv("../05_extraction/extraction.csv")
--- Create individual forest plots ---
--- Create individual forest plots ---
Plot 1: Pathologic complete response
Plot 1: Pathologic complete response
res_pcr <- metabin(
event.e = events_pcr_ici,
n.e = total_ici,
event.c = events_pcr_control,
n.c = total_control,
data = data,
studlab = study_id,
sm = "RR",
method = "MH"
)
res_pcr <- metabin(
event.e = events_pcr_ici,
n.e = total_ici,
event.c = events_pcr_control,
n.c = total_control,
data = data,
studlab = study_id,
sm = "RR",
method = "MH"
)
Save as ggplot-compatible object
Save as ggplot-compatible object
p1 <- forest(res_pcr, layout = "RevMan5") +
ggtitle("A. Pathologic Complete Response")
p1 <- forest(res_pcr, layout = "RevMan5") +
ggtitle("A. Pathologic Complete Response")
Plot 2: Event-free survival
Plot 2: Event-free survival
res_efs <- metagen(
TE = log_hr_efs,
seTE = se_log_hr_efs,
data = data,
studlab = study_id,
sm = "HR"
)
p2 <- forest(res_efs) +
ggtitle("B. Event-Free Survival")
res_efs <- metagen(
TE = log_hr_efs,
seTE = se_log_hr_efs,
data = data,
studlab = study_id,
sm = "HR"
)
p2 <- forest(res_efs) +
ggtitle("B. Event-Free Survival")
Plot 3: Overall survival
Plot 3: Overall survival
res_os <- metagen(
TE = log_hr_os,
seTE = se_log_hr_os,
data = data,
studlab = study_id,
sm = "HR"
)
p3 <- forest(res_os) +
ggtitle("C. Overall Survival")
res_os <- metagen(
TE = log_hr_os,
seTE = se_log_hr_os,
data = data,
studlab = study_id,
sm = "HR"
)
p3 <- forest(res_os) +
ggtitle("C. Overall Survival")
--- Combine with patchwork ---
--- Combine with patchwork ---
combined <- p1 / p2 / p3 +
plot_annotation(
title = "Figure 1. Efficacy Outcomes with ICI vs Control",
theme = theme(plot.title = element_text(size = 16, face = "bold"))
)
combined <- p1 / p2 / p3 +
plot_annotation(
title = "Figure 1. Efficacy Outcomes with ICI vs Control",
theme = theme(plot.title = element_text(size = 16, face = "bold"))
)
Export at 300 DPI
Export at 300 DPI
ggsave("../07_manuscript/figures/figure1_efficacy.png",
plot = combined,
width = 10,
height = 14,
dpi = 300,
bg = "white")
cat("✅ Created figure1_efficacy.png\n")
cat(" Dimensions: 3000×4200 px at 300 DPI\n")
undefinedggsave("../07_manuscript/figures/figure1_efficacy.png",
plot = combined,
width = 10,
height = 14,
dpi = 300,
bg = "white")
cat("✅ Created figure1_efficacy.png\n")
cat(" Dimensions: 3000×4200 px at 300 DPI\n")
undefinedUsing cowplot for More Control
使用cowplot实现更多控制
r
library(cowplot)r
library(cowplot)Combine with explicit panel labels and alignment
Combine with explicit panel labels and alignment
combined <- plot_grid(
p1, p2, p3,
labels = c("A", "B", "C"),
label_size = 18,
label_fontface = "bold",
ncol = 1,
align = "v", # Vertical alignment
axis = "l", # Align left axis
rel_heights = c(1, 1, 1)
)
combined <- plot_grid(
p1, p2, p3,
labels = c("A", "B", "C"),
label_size = 18,
label_fontface = "bold",
ncol = 1,
align = "v", # Vertical alignment
axis = "l", # Align left axis
rel_heights = c(1, 1, 1)
)
Add overall title
Add overall title
title <- ggdraw() +
draw_label(
"Figure 1. Efficacy Outcomes with ICI vs Control",
fontface = "bold",
size = 16,
x = 0.5,
hjust = 0.5
)
title <- ggdraw() +
draw_label(
"Figure 1. Efficacy Outcomes with ICI vs Control",
fontface = "bold",
size = 16,
x = 0.5,
hjust = 0.5
)
Combine title and plots
Combine title and plots
final <- plot_grid(
title,
combined,
ncol = 1,
rel_heights = c(0.1, 1)
)
final <- plot_grid(
title,
combined,
ncol = 1,
rel_heights = c(0.1, 1)
)
Export
Export
ggsave("../07_manuscript/figures/figure1_efficacy.png",
plot = final,
width = 10, height = 14, dpi = 300, bg = "white")
undefinedggsave("../07_manuscript/figures/figure1_efficacy.png",
plot = final,
width = 10, height = 14, dpi = 300, bg = "white")
undefinedGrid Layout (2x2 or 2x3)
网格布局(2x2或2x3)
r
library(patchwork)r
library(patchwork)2x2 grid
2x2 grid
combined <- (p1 | p2) / (p3 | p4) +
plot_annotation(tag_levels = "A")
combined <- (p1 | p2) / (p3 | p4) +
plot_annotation(tag_levels = "A")
2x3 grid
2x3 grid
combined <- (p1 | p2 | p3) / (p4 | p5 | p6) +
plot_annotation(tag_levels = "A")
ggsave("figure_grid.png", width = 14, height = 10, dpi = 300)
undefinedcombined <- (p1 | p2 | p3) / (p4 | p5 | p6) +
plot_annotation(tag_levels = "A")
ggsave("figure_grid.png", width = 14, height = 10, dpi = 300)
undefinedPython Workflow (Legacy - For PNG Files Only)
Python工作流(遗留 - 仅适用于PNG文件)
⚠️ Only use if you have existing PNG files and cannot regenerate in R.
⚠️ 仅当你有现有PNG文件且无法在R中重新生成时使用。
Step 1: Verify Input Files
步骤1:验证输入文件
bash
undefinedbash
undefinedCheck that all files exist and are PNG/JPG
Check that all files exist and are PNG/JPG
ls -lh path/to/plots/*.png
undefinedls -lh path/to/plots/*.png
undefinedStep 2: Create Assembly Script
步骤2:创建组装脚本
Use the Python template provided in this skill.
使用本技能中提供的Python模板。
Step 3: Run Assembly
步骤3:运行组装
bash
undefinedbash
undefinedUsing uv (recommended for dependency management)
使用uv(推荐用于依赖管理)
uv run python assemble_figures.py Figure1_Efficacy.png vertical
forest_plot_pCR.png
forest_plot_EFS.png
forest_plot_OS.png
forest_plot_pCR.png
forest_plot_EFS.png
forest_plot_OS.png
uv run python assemble_figures.py Figure1_Efficacy.png vertical
forest_plot_pCR.png
forest_plot_EFS.png
forest_plot_OS.png
forest_plot_pCR.png
forest_plot_EFS.png
forest_plot_OS.png
Or with system Python (requires PIL/Pillow)
或使用系统Python(需要安装PIL/Pillow)
python assemble_figures.py Figure1.png grid:2x2
plot1.png plot2.png plot3.png plot4.png
plot1.png plot2.png plot3.png plot4.png
undefinedpython assemble_figures.py Figure1.png grid:2x2
plot1.png plot2.png plot3.png plot4.png
plot1.png plot2.png plot3.png plot4.png
undefinedStep 4: Verify Output
步骤4:验证输出
bash
undefinedbash
undefinedCheck dimensions and file size
检查尺寸和文件大小
ls -lh Figure1_Efficacy.png
ls -lh Figure1_Efficacy.png
Verify DPI (should show 300x300)
验证DPI(应显示300x300)
file Figure1_Efficacy.png
undefinedfile Figure1_Efficacy.png
undefinedCustomization Options
自定义选项
Font Size Adjustment
字体大小调整
For different image sizes:
- 3000px wide images: (default)
font_size=80 - 1500px wide images:
font_size=40 - 6000px wide images:
font_size=160
针对不同图像尺寸:
- 3000px宽图像:(默认)
font_size=80 - 1500px宽图像:
font_size=40 - 6000px宽图像:
font_size=160
Label Position
标签位置
- (default)
position='top-left' position='top-right'position='bottom-left'position='bottom-right'
- (默认)
position='top-left' position='top-right'position='bottom-left'position='bottom-right'
Spacing Between Panels
面板间距
- Default: pixels
spacing=40 - Tight spacing:
spacing=20 - Loose spacing:
spacing=80
- 默认:像素
spacing=40 - 紧凑间距:
spacing=20 - 宽松间距:
spacing=80
Label Style
标签样式
- White background with black border (default, best visibility)
- Transparent background:
bg_color=None, border=False - Custom colors:
bg_color='#f0f0f0', text_color='#333333'
- 白色背景带黑色边框(默认,可见性最佳)
- 透明背景:
bg_color=None, border=False - 自定义颜色:
bg_color='#f0f0f0', text_color='#333333'
Journal Requirements
期刊要求
Nature, Science, Cell
《Nature》《Science》《Cell》
- Resolution: 300-600 DPI
- Format: TIFF or high-quality PDF preferred, PNG acceptable
- Width: 89mm (single column) or 183mm (double column) at final size
- Font: Arial, Helvetica, or similar sans-serif
- Labels: Bold, 8-10pt at final size
- 分辨率:300-600 DPI
- 格式:优先使用TIFF或高质量PDF,PNG也可接受
- 宽度:最终尺寸下单栏89mm或双栏183mm
- 字体:Arial、Helvetica或类似无衬线字体
- 标签:加粗,最终尺寸下8-10pt
Lancet, JAMA, NEJM
《Lancet》《JAMA》《NEJM》
- Resolution: 300 DPI minimum
- Format: TIFF, EPS, or PNG
- Width: Fit within column width (typically 3-4 inches)
- Labels: Clear, high contrast
- Grayscale: Must be readable in B&W
- 分辨率:最低300 DPI
- 格式:TIFF、EPS或PNG
- 宽度:适配栏宽(通常3-4英寸)
- 标签:清晰、高对比度
- 灰度:在黑白模式下必须可读
Quality Checklist
质量检查清单
Before submitting:
- All figures at 300 DPI minimum
- Panel labels (A, B, C) visible and correctly ordered
- Labels don't obscure important data
- All panels aligned properly
- Spacing consistent between panels
- File size reasonable (<10 MB for PNG)
- Figures readable when printed at final journal size
- Color schemes work in grayscale (if required)
提交前请确认:
- 所有图表分辨率不低于300 DPI
- 面板标签(A、B、C)清晰可见且顺序正确
- 标签未遮挡重要数据
- 所有面板对齐正确
- 面板间间距一致
- 文件大小合理(PNG格式小于10 MB)
- 图表在期刊最终印刷尺寸下可读
- 配色方案在灰度模式下可用(如要求)
Common Issues & Solutions
常见问题与解决方案
Problem: Labels too small
Solution: Increase parameter (try doubling it)
font_sizeProblem: Labels obscure data
Solution: Change to different corner or adjust
positionoffsetProblem: DPI too low
Solution: Regenerate input plots at higher resolution first, then reassemble
Problem: Uneven spacing
Solution: Crop input images to remove excess white space before assembly
Problem: File too large
Solution: Use PNG compression or convert to JPEG (may lose quality)
问题:标签过小
解决方案:增大参数(尝试翻倍)
font_size问题:标签遮挡数据
解决方案:将改为其他角落或调整
positionoffset问题:DPI过低
解决方案:先以更高分辨率重新生成输入绘图,再进行组装
问题:间距不均
解决方案:组装前裁剪输入图像以去除多余空白
问题:文件过大
解决方案:使用PNG压缩或转换为JPEG(可能会损失质量)
Example Use Cases
示例用例
Meta-Analysis Figures (R)
元分析图表(R)
r
undefinedr
undefinedFigure 1: Efficacy outcomes (3 vertical panels)
Figure 1: Efficacy outcomes (3 vertical panels)
library(patchwork)
combined <- p_pcr / p_efs / p_os +
plot_annotation(
title = "Figure 1. Efficacy Outcomes",
tag_levels = "A"
)
ggsave("07_manuscript/figures/figure1_efficacy.png",
width = 10, height = 14, dpi = 300)
library(patchwork)
combined <- p_pcr / p_efs / p_os +
plot_annotation(
title = "Figure 1. Efficacy Outcomes",
tag_levels = "A"
)
ggsave("07_manuscript/figures/figure1_efficacy.png",
width = 10, height = 14, dpi = 300)
Figure 2: Safety + Bias (2 vertical panels)
Figure 2: Safety + Bias (2 vertical panels)
combined <- p_safety / p_funnel +
plot_annotation(tag_levels = "A")
ggsave("07_manuscript/figures/figure2_safety.png",
width = 10, height = 10, dpi = 300)
combined <- p_safety / p_funnel +
plot_annotation(tag_levels = "A")
ggsave("07_manuscript/figures/figure2_safety.png",
width = 10, height = 10, dpi = 300)
Figure 3: Subgroup analysis (2x2 grid)
Figure 3: Subgroup analysis (2x2 grid)
combined <- (p_age | p_sex) / (p_stage | p_histology) +
plot_annotation(
title = "Figure 3. Subgroup Analyses",
tag_levels = "A"
)
ggsave("07_manuscript/figures/figure3_subgroups.png",
width = 14, height = 12, dpi = 300)
undefinedcombined <- (p_age | p_sex) / (p_stage | p_histology) +
plot_annotation(
title = "Figure 3. Subgroup Analyses",
tag_levels = "A"
)
ggsave("07_manuscript/figures/figure3_subgroups.png",
width = 14, height = 12, dpi = 300)
undefinedLegacy Python Examples (Not Recommended)
遗留Python示例(不推荐)
bash
undefinedbash
undefinedFigure 1: Efficacy outcomes (3 vertical panels)
Figure 1: Efficacy outcomes (3 vertical panels)
uv run python assemble.py Figure1_Efficacy.png vertical
forest_plot_pCR.png
forest_plot_EFS.png
forest_plot_OS.png
forest_plot_pCR.png
forest_plot_EFS.png
forest_plot_OS.png
uv run python assemble.py Figure1_Efficacy.png vertical
forest_plot_pCR.png
forest_plot_EFS.png
forest_plot_OS.png
forest_plot_pCR.png
forest_plot_EFS.png
forest_plot_OS.png
Figure 2: Safety + Bias (2 vertical panels)
Figure 2: Safety + Bias (2 vertical panels)
uv run python assemble.py Figure2_Safety.png vertical
forest_plot_SAE.png
funnel_plot_pCR.png
forest_plot_SAE.png
funnel_plot_pCR.png
undefineduv run python assemble.py Figure2_Safety.png vertical
forest_plot_SAE.png
funnel_plot_pCR.png
forest_plot_SAE.png
funnel_plot_pCR.png
undefinedDependencies
依赖项
R Packages (Recommended)
推荐的R包
r
undefinedr
undefinedInstall from CRAN
Install from CRAN
install.packages(c("patchwork", "cowplot", "ggplot2"))
install.packages(c("patchwork", "cowplot", "ggplot2"))
For meta-analysis plots
For meta-analysis plots
install.packages(c("meta", "metafor"))
undefinedinstall.packages(c("meta", "metafor"))
undefinedPython (Legacy - Only for PNG Assembly)
Python(遗留 - 仅用于PNG组装)
bash
undefinedbash
undefinedInstall using uv (if needed for legacy workflows)
使用uv安装(如果遗留工作流需要)
uv add Pillow
uv add Pillow
Or using pip
或使用pip
pip install Pillow
undefinedpip install Pillow
undefinedOutput Example
输出示例
R Output
R输出
✅ Created figure1_efficacy.png
Dimensions: 3000×4200 px at 300 DPI
Size: 2.3 MBThe output file will have:
- Professional panel labels (A, B, C) automatically added by patchwork/cowplot
- Consistent spacing between panels
- 300 DPI resolution suitable for publication
- Aligned axes for easy comparison
- Publication-ready theme
✅ Created figure1_efficacy.png
Dimensions: 3000×4200 px at 300 DPI
Size: 2.3 MB输出文件将包含:
- 由patchwork/cowplot自动添加的专业面板标签(A、B、C)
- 面板间一致的间距
- 适合发表的300 DPI分辨率
- 对齐的坐标轴便于对比
- 可直接用于发表的主题样式
Python Output (Legacy)
Python输出(遗留)
✅ Created Figure1_Efficacy.png
Dimensions: 3000×6080 px at 300 DPIThe output file will have:
- Professional panel labels (A, B, C) in top-left corners
- Consistent spacing between panels
- 300 DPI resolution suitable for publication
- White background with black border around labels for maximum visibility
✅ Created Figure1_Efficacy.png
Dimensions: 3000×6080 px at 300 DPI输出文件将包含:
- 位于左上角的专业面板标签(A、B、C)
- 面板间一致的间距
- 适合发表的300 DPI分辨率
- 标签带有白色背景和黑色边框以保证最高可见性
Related Skills
相关技能
- - Complete meta-analysis manuscript preparation
/meta-manuscript-assembly - - Create individual publication-ready plots
/plot-publication - - Generate comprehensive figure legends
/figure-legends
- - 完整的元分析手稿准备
/meta-manuscript-assembly - - 创建单个可直接用于发表的绘图
/plot-publication - - 生成全面的图表图例
/figure-legends
Pro Tips
专业技巧
R Workflow Tips
R工作流技巧
- Work in R throughout: Generate plots AND assemble in R for best results
- Use patchwork for ggplot2: Simplest syntax (for vertical)
p1 / p2 - Use cowplot for mixed plots: Works with base R and ggplot2
- Set theme globally: Use for consistency
theme_set(theme_minimal()) - Export once at end: Create all plots, combine, then export (faster)
- Check alignment: Use and
align = "v"in cowplotaxis = "l" - Consistent sizes: Set in theme for readable text
base_size
- 全程使用R:在R中生成并组装绘图以获得最佳效果
- ggplot2绘图使用patchwork:语法最简单(表示垂直堆叠)
p1 / p2 - 混合绘图使用cowplot:适用于基础R绘图和ggplot2
- 全局设置主题:使用保证一致性
theme_set(theme_minimal()) - 最后统一导出:创建所有绘图后再组合导出(速度更快)
- 检查对齐:在cowplot中使用和
align = "v"axis = "l" - 统一尺寸:在主题中设置以保证文本可读性
base_size
General Tips
通用技巧
- Generate high-quality inputs first: Assembly won't improve low-quality source plots
- Label systematically: A-B-C top-to-bottom or left-to-right
- Check in print preview: Ensure labels readable at final print size
- Keep R scripts: Save R code for reproducibility
- Version control figures: Commit both R scripts and final PNG files
- Test on different screens: Check readability on laptop and printed page
- 先生成高质量输入:组装无法提升低质量源绘图的品质
- 系统地添加标签:按从上到下或从左到右的顺序使用A-B-C标签
- 打印预览检查:确保标签在最终印刷尺寸下可读
- 保留R脚本:保存R代码以保证可重复性
- 版本控制图表:同时提交R脚本和最终PNG文件
- 多屏幕测试:在笔记本电脑和打印页面上检查可读性
R Package Resources
R包资源
When you need help with R packages:
- CRAN: https://cran.r-project.org/ (patchwork, cowplot documentation)
- Tidyverse: https://www.tidyverse.org/ (ggplot2 reference)
- R-universe: https://r-universe.dev/search/ (search all R packages)
- patchwork guide: https://patchwork.data-imaginist.com/
- cowplot guide: https://wilkelab.org/cowplot/
当你需要R包帮助时:
- CRAN:https://cran.r-project.org/(patchwork、cowplot文档)
- Tidyverse:https://www.tidyverse.org/(ggplot2参考)
- R-universe:https://r-universe.dev/search/(搜索所有R包)
- patchwork指南:https://patchwork.data-imaginist.com/
- cowplot指南:https://wilkelab.org/cowplot/