OpenClaw-Medical-Skills bio-data-visualization-ggplot2-fundamentals

<!--

install
source · Clone the upstream repo
git clone https://github.com/FreedomIntelligence/OpenClaw-Medical-Skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/FreedomIntelligence/OpenClaw-Medical-Skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/bio-data-visualization-ggplot2-fundamentals" ~/.claude/skills/freedomintelligence-openclaw-medical-skills-bio-data-visualization-ggplot2-funda && rm -rf "$T"
OpenClaw · Install into ~/.openclaw/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/FreedomIntelligence/OpenClaw-Medical-Skills "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/bio-data-visualization-ggplot2-fundamentals" ~/.openclaw/skills/freedomintelligence-openclaw-medical-skills-bio-data-visualization-ggplot2-funda && rm -rf "$T"
manifest: skills/bio-data-visualization-ggplot2-fundamentals/SKILL.md
source content
<!-- # COPYRIGHT NOTICE # This file is part of the "Universal Biomedical Skills" project. # Copyright (c) 2026 MD BABU MIA, PhD <md.babu.mia@mssm.edu> # All Rights Reserved. # # This code is proprietary and confidential. # Unauthorized copying of this file, via any medium is strictly prohibited. # # Provenance: Authenticated by MD BABU MIA -->

name: bio-data-visualization-ggplot2-fundamentals description: Create publication-quality scientific figures with ggplot2 including scatter plots, boxplots, heatmaps, and multi-panel layouts. Use when creating static figures for papers, presentations, or reports in R. tool_type: r primary_tool: ggplot2 measurable_outcome: Execute skill workflow successfully with valid output within 15 minutes. allowed-tools:

  • read_file
  • run_shell_command

ggplot2 Fundamentals

Basic Structure

library(ggplot2)

# Grammar of graphics: data + aesthetics + geometry
ggplot(data, aes(x = var1, y = var2)) +
    geom_point()

Common Geoms

# Scatter plot
ggplot(df, aes(x, y)) + geom_point()

# Line plot
ggplot(df, aes(x, y)) + geom_line()

# Bar plot
ggplot(df, aes(x, y)) + geom_col()  # y values
ggplot(df, aes(x)) + geom_bar()     # counts

# Boxplot
ggplot(df, aes(group, value)) + geom_boxplot()

# Violin plot
ggplot(df, aes(group, value)) + geom_violin()

# Histogram
ggplot(df, aes(x)) + geom_histogram(bins = 30)

# Density
ggplot(df, aes(x, fill = group)) + geom_density(alpha = 0.5)

# Heatmap
ggplot(df, aes(x, y, fill = value)) + geom_tile()

Aesthetic Mappings

# Color by group
ggplot(df, aes(x, y, color = group)) + geom_point()

# Size by value
ggplot(df, aes(x, y, size = value)) + geom_point()

# Shape by category
ggplot(df, aes(x, y, shape = category)) + geom_point()

# Fill for bars/boxes
ggplot(df, aes(x, y, fill = group)) + geom_boxplot()

# Alpha for transparency
ggplot(df, aes(x, y, alpha = value)) + geom_point()

Publication Theme

theme_publication <- function(base_size = 12) {
    theme_bw(base_size = base_size) +
    theme(
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_rect(color = 'black', linewidth = 0.5),
        axis.text = element_text(color = 'black'),
        axis.ticks = element_line(color = 'black'),
        legend.key = element_blank(),
        strip.background = element_blank(),
        strip.text = element_text(face = 'bold')
    )
}

# Usage
ggplot(df, aes(x, y)) +
    geom_point() +
    theme_publication()

Color Palettes

library(RColorBrewer)
library(viridis)

# Qualitative (categorical)
scale_color_brewer(palette = 'Set1')
scale_fill_brewer(palette = 'Set2')

# Sequential (continuous)
scale_fill_viridis_c()
scale_color_gradient(low = 'white', high = 'red')

# Diverging
scale_fill_gradient2(low = 'blue', mid = 'white', high = 'red', midpoint = 0)
scale_fill_distiller(palette = 'RdBu')

# Manual colors
scale_color_manual(values = c('Control' = '#1f77b4', 'Treatment' = '#d62728'))

Volcano Plot

volcano_plot <- function(res, fdr = 0.05, lfc = 1) {
    res <- res %>%
        mutate(
            significance = case_when(
                padj < fdr & log2FoldChange > lfc ~ 'Up',
                padj < fdr & log2FoldChange < -lfc ~ 'Down',
                TRUE ~ 'NS'
            )
        )

    ggplot(res, aes(log2FoldChange, -log10(pvalue), color = significance)) +
        geom_point(alpha = 0.6, size = 1) +
        scale_color_manual(values = c('Up' = '#d62728', 'Down' = '#1f77b4', 'NS' = 'grey60')) +
        geom_vline(xintercept = c(-lfc, lfc), linetype = 'dashed', color = 'grey40') +
        geom_hline(yintercept = -log10(fdr), linetype = 'dashed', color = 'grey40') +
        labs(x = 'Log2 Fold Change', y = '-Log10 P-value') +
        theme_publication()
}

MA Plot

ma_plot <- function(res, fdr = 0.05) {
    res <- res %>%
        mutate(significant = padj < fdr)

    ggplot(res, aes(log10(baseMean), log2FoldChange, color = significant)) +
        geom_point(alpha = 0.5, size = 1) +
        scale_color_manual(values = c('TRUE' = 'red', 'FALSE' = 'grey60')) +
        geom_hline(yintercept = 0, color = 'black') +
        labs(x = 'Log10 Mean Expression', y = 'Log2 Fold Change') +
        theme_publication()
}

Boxplot with Points

ggplot(df, aes(group, value, fill = group)) +
    geom_boxplot(outlier.shape = NA, alpha = 0.7) +
    geom_jitter(width = 0.2, alpha = 0.5, size = 1) +
    scale_fill_brewer(palette = 'Set2') +
    labs(x = NULL, y = 'Expression') +
    theme_publication() +
    theme(legend.position = 'none')

Faceting

# Wrap by one variable
ggplot(df, aes(x, y)) +
    geom_point() +
    facet_wrap(~ group, scales = 'free')

# Grid by two variables
ggplot(df, aes(x, y)) +
    geom_point() +
    facet_grid(rows = vars(condition), cols = vars(timepoint))

Labels and Text

library(ggrepel)

ggplot(res, aes(log2FoldChange, -log10(pvalue))) +
    geom_point() +
    geom_text_repel(
        data = subset(res, padj < 0.01),
        aes(label = gene),
        max.overlaps = 20,
        size = 3
    )

Multi-Panel Figures

library(patchwork)

p1 <- ggplot(df, aes(x, y)) + geom_point()
p2 <- ggplot(df, aes(group, value)) + geom_boxplot()
p3 <- ggplot(df, aes(x)) + geom_histogram()

# Combine horizontally
p1 + p2 + p3

# Combine with layout
(p1 | p2) / p3

# Add labels
(p1 + p2 + p3) + plot_annotation(tag_levels = 'A')

# Shared legend
(p1 + p2) + plot_layout(guides = 'collect')

Saving Figures

# For publication (300 DPI)
ggsave('figure.pdf', p, width = 7, height = 5, units = 'in')
ggsave('figure.png', p, width = 7, height = 5, units = 'in', dpi = 300)
ggsave('figure.tiff', p, width = 7, height = 5, units = 'in', dpi = 300, compression = 'lzw')

# For presentations
ggsave('figure.png', p, width = 10, height = 6, dpi = 150)

Axis Formatting

library(scales)

# Scientific notation
scale_y_continuous(labels = scientific)

# Comma separators
scale_x_continuous(labels = comma)

# Log scale
scale_y_log10(labels = trans_format('log10', math_format(10^.x)))

# Percent
scale_y_continuous(labels = percent)

# Limits
coord_cartesian(xlim = c(0, 10), ylim = c(0, 100))

# Breaks
scale_x_continuous(breaks = seq(0, 10, 2))

Legend Customization

# Position
theme(legend.position = 'bottom')
theme(legend.position = 'none')
theme(legend.position = c(0.8, 0.2))

# Title
labs(color = 'Condition', fill = 'Group')
guides(color = guide_legend(title = 'Condition'))

# Order
scale_color_discrete(limits = c('Control', 'Treatment'))

Heatmap with pheatmap

library(pheatmap)
library(RColorBrewer)

pheatmap(
    mat,
    scale = 'row',
    color = colorRampPalette(rev(brewer.pal(9, 'RdBu')))(100),
    cluster_rows = TRUE,
    cluster_cols = TRUE,
    show_rownames = TRUE,
    show_colnames = TRUE,
    annotation_col = annotation_df,
    fontsize = 8,
    filename = 'heatmap.pdf',
    width = 8,
    height = 10
)

Related Skills

  • differential-expression/de-visualization - DE-specific plots
  • pathway-analysis/enrichment-visualization - Enrichment plots
  • reporting/rmarkdown-reports - Figures in reports
<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->