mcpbeat Sign in

Bio Data Visualization Circos Plots Agent Skill

Build circular genome visualizations using circlize (R), pyCirclize (Python), or Circos (Perl CLI) with ideogram tracks, multi-data tracks (scatter, histogram, heatmap), chord/link arcs for interactions, and explicit circos.clear() between plots. Covers when circular is appropriate vs when Cartesian wins (Cleveland-McGill 1984), karyograms, and chromosome adjacency in chord diagrams. Use when adjacency on the circle conveys meaning — chromosome-level overview, structural variants, Hi-C interactions, cross-genome comparisons.

5k tokens
context cost
the whole folder, loaded on every use
4
files
ships runnable scripts
0
copies elsewhere
how many repositories repackaged it
132
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/BioTender-max/awesome-bio-agent-skills --skill bio-data-visualization-circos-plots

What comes with it

7 560 bytes besides the instruction
examples/circos_basic.R
examples/circos_basic.py
usage-guide.md

The instruction itself

22 sections, as written by the author

Version Compatibility

Reference examples tested with: circlize 0.4.16+ (R), pyCirclize 1.4+ (Python), Circos 0.69-9 (Perl CLI), ComplexHeatmap 2.18+ (uses circlize for color mapping).

Before using code patterns, verify installed versions match. If versions differ:

  • R: packageVersion('<pkg>') then ?function_name
  • Python: pip show <package> then help(module.function)

If code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.

Circular Genome Plots (Circos)

"Make a circos plot" -> Render genome chromosomes around a circle with stacked tracks (histogram, scatter, heatmap) and arcs/chords showing interactions. Krzywinski 2009 *Genome Res* 19:1639 introduced the genre for genome-scale comparative views. The single decision that matters: does the circular layout convey meaning that Cartesian cannot?

  • R: circlize::circos.initializeWithIdeogram + circos.genomicTrack* (Gu 2014)
  • Python: pyCirclize.Gcircle
  • CLI: Circos (Perl); config-driven; most flexible but steepest learning

The Single Most Important Modern Insight -- Circular Plots Often Hide What Cartesian Reveals

Cleveland-McGill 1984 *J Am Stat Assoc* 79:531 effectiveness rankings establish that position-on-common-scale (Cartesian) is the most accurate visual channel; circular position requires mental "unwrapping" and impairs precise value comparison. Heer-Bostock 2010 *CHI* replicated the ranking in modern crowd studies. Use circular only when adjacency on the circle conveys meaning that linear cannot.

Use circular ONLY when:

  • Chromosome adjacency matters (whole-genome SVs, Hi-C contacts where genome circularity is the geometry)
  • Pairwise interactions between many entities (chord diagrams; chromosome translocations)
  • Aesthetic / overview infographic for cover figure

Do NOT use circular for:

  • Comparing values across categories (Cartesian bar/dot wins)
  • Time series (linear axis wins)
  • Anything where precise value reading matters

The circos plot is a beautiful but dangerous default. The most-cited published critique is the genre being applied where it adds no information.

circlize (R) — Modern Default

Goal: Render a multi-track circos plot with ideograms, gene-density histogram, variant-density heatmap, and inter-chromosomal SV links.

Approach: Initialize with chromosome ideograms via circos.initializeWithIdeogram; add tracks with circos.genomicTrack + appropriate panel function; add links with circos.link; always call circos.clear() after the plot completes.

library(circlize)

# 1. Initialize with hg38 ideograms
pdf('circos.pdf', width = 8, height = 8)
circos.par(start.degree = 90,             # 12 o'clock start
           gap.degree = c(rep(1, 23), 5)) # bigger gap before chr1 for visual break
# hg38 specifically benefits from explicit chromosome.index to skip unmapped contigs
circos.initializeWithIdeogram(species = 'hg38',
                               chromosome.index = paste0('chr', c(1:22, 'X', 'Y')),
                               plotType = c('axis', 'labels', 'ideogram'))

# 2. Gene-density histogram (outermost data track)
circos.genomicDensity(gene_bed, col = '#0072B2', track.height = 0.08)

# 3. Variant-density heatmap
circos.genomicHeatmap(variant_bed,
                       col = colorRamp2(c(0, 100), c('white', '#D55E00')),
                       heatmap_height = 0.08, side = 'inside')

# 4. CNV scatter
circos.genomicTrack(cnv_bed, ylim = c(-2, 2),
                     panel.fun = function(region, value, ...) {
                         circos.genomicPoints(region, value,
                                              col = ifelse(value > 0.3, '#D55E00',
                                                           ifelse(value < -0.3, '#0072B2', 'grey60')),
                                              pch = 16, cex = 0.4)
                     },
                     track.height = 0.1)

# 5. Inter-chromosomal SV links
for (i in seq_len(nrow(sv_df))) {
    circos.link(sv_df$chr1[i], c(sv_df$start1[i], sv_df$end1[i]),
                sv_df$chr2[i], c(sv_df$start2[i], sv_df$end2[i]),
                col = '#888888', lwd = 0.4)
}

# 6. CRITICAL -- clear global state
circos.clear()
dev.off()

The circos.clear() Trap

circos.par() settings (start.degree, gap.degree, canvas.xlim, canvas.ylim, clock.wise, circle.margin) are GLOBAL state. After a plot completes, those settings persist into the next plot.

Forgetting circos.clear() produces:

  • Next circos.par() calls silently fail to take effect (warning, easily missed in loops)
  • Re-initialization may error or render at wrong angles
  • Loop-rendered figures inherit state from the previous iteration

Always call circos.clear() after every plot. Make it the last line of the plotting block alongside dev.off().

pyCirclize (Python)

from pycirclize import Circos
import matplotlib.pyplot as plt

sectors = {'chr1': 248956422, 'chr2': 242193529, ...}
circos = Circos(sectors, space=2)                       # space = degree gap between sectors

for sector in circos.sectors:
    sector.text(sector.name, r=110, size=8)
    # outer ideogram
    sector.axis(r_lim=(95, 100), fc='lightgrey')
    # data track
    track = sector.add_track((75, 90))
    track.bar(positions, heights, width=bin_size, color='#0072B2')

# Inter-sector links (chord diagram)
circos.link(('chr1', 1e8, 1.1e8), ('chr5', 2e8, 2.1e8),
            color='#888888', alpha=0.5)

fig = circos.plotfig()
fig.savefig('circos_py.pdf', bbox_inches='tight')

pyCirclize is a younger package than circlize but actively developed (Shimoyama 2024+). API more Pythonic than circlize-via-rpy2.

Circos CLI (Perl) — Most Powerful, Steepest Curve

# config: circos.conf with karyotype, ideogram, plots, links sections
circos -conf circos.conf -outputfile output.png

Circos (Krzywinski 2009) is the original; supports unlimited tracks and arbitrary geometries via configuration. For publication-grade complex figures the Perl tool remains the most powerful. For Python/R workflows, circlize/pyCirclize are more accessible.

Decision Tree by Use Case

| Use case | Recommended | Why |

|----------|-------------|-----|

| Whole-genome CNV summary | circlize/pyCirclize | Standard genre |

| SV link diagram | Chord arcs in circos | Inter-chromosomal adjacency |

| Hi-C contact summary at chromosome level | circos heatmap track | Adjacency matters |

| Per-sample mutation overview | Circular karyogram | Aesthetic; comparable to OncoPrint |

| Cohort-wide gene expression comparison | NOT circular | Use heatmap (Cartesian wins) |

| Time-series of any kind | NOT circular | Use line plot |

| Pathway diagram | NOT circular | Use Cytoscape |

Ideogram + Karyogram Without Circos

For per-chromosome data display where circularity is not required, karyoploteR (Gel 2017 *Bioinformatics* 33:3088) renders linear ideograms with stacked data tracks — often the better choice for CNV per-chromosome views.

library(karyoploteR)
kp <- plotKaryotype(genome = 'hg38', chromosomes = c('chr1', 'chr7', 'chr17'))
kpAddBaseNumbers(kp)
kpLines(kp, data = cnv_gr, y = cnv_gr$log2)
kpAddCytobandLabels(kp)

See copy-number/cnv-visualization for karyoploteR in depth.

Per-Method Failure Modes

circos.clear() forgotten in a loop

Trigger: Plotting multiple circos figures in a for loop without circos.clear() between.

Mechanism: circos.par settings (gap.degree, start.degree, clock.wise) persist across plots.

Symptom: Plots 2..N inherit state from plot 1; gap sizes, rotation differ unexpectedly.

Fix: End every plot block with circos.clear(). Make it a hygiene rule.

Using circular when Cartesian would be better

Trigger: "Circos plot of gene expression across 20 conditions."

Mechanism: Circular impairs value comparison (Cleveland-McGill 1984; Heer-Bostock 2010).

Symptom: Reviewer or coauthor says "I can't tell which condition is highest."

Fix: Use clustered heatmap. Reserve circos for genome-adjacency or chord-diagram use cases.

Trigger: Plotting 10000+ chord links between chromosomes.

Mechanism: Overlap saturates the center; no individual link visible.

Symptom: Center of circos is uniformly dark.

Fix: Filter to top-confidence links; OR color-bin by interaction strength with alpha; OR aggregate to chromosome-level summary then link.

Sector ordering arbitrary

Trigger: Default sector order is input order.

Mechanism: circlize / pyCirclize do not auto-order chromosomes 1..22, X, Y.

Symptom: Chromosomes appear in genome-build-file order.

Fix: Explicit chromosome.index = c(paste0('chr', 1:22), 'chrX', 'chrY').

Wrong species ideogram

Trigger: species = 'hg19' when data is hg38-coordinate.

Mechanism: circlize fetches cytoband data per species; mismatch renders correct ideogram but wrong banding for the data.

Symptom: Cytoband boundaries don't match published references.

Fix: Match species to data coordinate system. For non-standard genomes, supply custom cytoband file. For species = 'hg38' specifically, always pass chromosome.index = paste0('chr', c(1:22, 'X', 'Y')) to skip unmapped contigs (jokergoo/circlize issue #46).

Ideogram covers data track

Trigger: Default ideogram track height too large; data track squeezed.

Mechanism: circos.initializeWithIdeogram uses ~5% of radius; left-over for data.

Symptom: Data values invisible because track is too narrow.

Fix: Reduce cytoband.height in initialization; OR use plotType = c('axis', 'labels') to omit ideogram entirely.

Chromosome label collisions for small chromosomes

Trigger: Default label position; small chromosomes (chr21, chr22, chrY) have overlapping labels.

Mechanism: Labels drawn at sector midpoints regardless of sector width.

Symptom: Labels overlap.

Fix: circos.par(gap.degree = c(rep(1, 22), 10, 10, 10)) for larger gaps before small chromosomes; OR reduce label font size.

Reconciliation

| Pattern | Cause | Action |

|---------|-------|--------|

| circlize and pyCirclize differ in default rotation | Different start-angle convention | Set start.degree=90 (R) / equivalent (Python) explicitly |

| Cytoband colors don't match UCSC | Different species cytoband source | Verify species; for custom genomes supply band file |

| Inter-sector links arc the "long way around" | Default arc direction | Some chord packages support direction = 'short' |

Quantitative Thresholds

| Threshold | Value | Source |

|-----------|-------|--------|

| Max sectors readable | ~30 | Visualization practical |

| Max links before blob | ~5000 | Practical; depends on alpha |

| Cytoband.height default | 0.05 of radius | circlize default |

| When circular adds value | Adjacency-meaningful only | Cleveland-McGill 1984 |

Common Errors

| Error / symptom | Cause | Solution |

|-----------------|-------|----------|

| Subsequent plots use wrong rotation | circos.clear() forgotten | Always end with circos.clear() |

| Chromosomes out of order | Default = input order | Explicit chromosome.index |

| Cytoband mismatch | Wrong species | Match species to data coords |

| Center of circos black | Too many links | Filter or aggregate |

| Reviewer asks "why circular?" | Cartesian would have been clearer | Migrate to heatmap unless adjacency matters |

| Small-chromosome label overlap | Default label position | Larger gap.degree before small sectors |

References

  • Cleveland WS, McGill R. 1984. Graphical perception: theory, experimentation, and application to the development of graphical methods. *J Am Stat Assoc* 79(387):531-554.
  • Gel B, Serra E. 2017. karyoploteR: an R/Bioconductor package to plot customizable genomes. *Bioinformatics* 33(19):3088-3090.
  • Gu Z, Gu L, Eils R, Schlesner M, Brors B. 2014. circlize implements and enhances circular visualization in R. *Bioinformatics* 30(19):2811-2812.
  • Heer J, Bostock M. 2010. Crowdsourcing graphical perception: using Mechanical Turk to assess visualization design. *Proc CHI* 203-212.
  • Krzywinski M, Schein J, Birol I, et al. 2009. Circos: an information aesthetic for comparative genomics. *Genome Res* 19(9):1639-1645.
  • Shimoyama Y. 2024. pyCirclize: Circular visualization in Python. *GitHub* https://github.com/moshi4/pyCirclize
  • copy-number/cnv-visualization - karyoploteR linear alternative for CNV
  • variant-calling/structural-variant-calling - SV data for circos links
  • hi-c-analysis/hic-visualization - Hi-C contact data circular display
  • data-visualization/genome-tracks - Linear track alternative
  • data-visualization/color-palettes - Sector and link palettes

Other skills for the same job

different authors, same section of the catalogue
D3 Viz
by chrisvoncsefalvay
×3

Creating interactive data visualisations using d3.js. This skill should be used when creating custom charts, graphs, network diagrams, geographic visualisations, or any complex SVG-based data visualisation that requires fine-grained control over visual elements, transitions, or interactions. Use this for bespoke visualisations beyond standard charting libraries, whether in React, Vue, Svelte, vanilla JavaScript, or any other environment.

20k tokens
Astropy
by christophacham
×3

Comprehensive Python library for astronomy and astrophysics. This skill should be used when working with astronomical data including celestial coordinates, physical units, FITS files, cosmological calculations, time systems, tables, world coordinate systems (WCS), and astronomical data analysis. Use when tasks involve coordinate transformations, unit conversions, FITS file manipulation, cosmological distance calculations, time scale conversions, or astronomical data processing.

16k tokens
Instrument Data To Allotrope
by anthropics
vendor ×2

Convert laboratory instrument output files (PDF, CSV, Excel, TXT) to Allotrope Simple Model (ASM) JSON format or flattened 2D CSV. Use this skill when scientists need to standardize instrument data for LIMS systems, data lakes, or downstream analysis. Supports auto-detection of instrument types. Outputs include full ASM JSON, flattened CSV for easy import, and exportable Python code for data engineers. Common triggers include converting instrument files, standardizing lab data, preparing data for upload to LIMS/ELN systems, or generating parser code for production pipelines.

33k tokens scripts
Qutip
by ComeOnOliver
×2

Quantum mechanics simulations and analysis using QuTiP (Quantum Toolbox in Python). Use when working with quantum systems including: (1) quantum states (kets, bras, density matrices), (2) quantum operators and gates, (3) time evolution and dynamics (Schrödinger, master equations, Monte Carlo), (4) open quantum systems with dissipation, (5) quantum measurements and entanglement, (6) visualization (Bloch sphere, Wigner functions), (7) steady states and correlation functions, or (8) advanced methods (Floquet theory, HEOM, stochastic solvers). Handles both closed and open quantum systems across various domains including quantum optics, quantum computing, and condensed matter physics.

27k tokens
Copilot Usage Metrics
by github
vendor ×1

Retrieve and display GitHub Copilot usage metrics for organizations and enterprises using the GitHub CLI and REST API.

1k tokens scripts
Mentoring Juniors
by github
vendor ×1

Socratic mentoring for junior developers and AI newcomers. Guides through questions, never answers. Triggers: "help me understand", "explain this code", "I''m stuck", "Im stuck", "I''m confused", "Im confused", "I don''t understand", "I dont understand", "can you teach me", "teach me", "mentor me", "guide me", "what does this error mean", "why doesn''t this work", "why does not this work", "I''m a beginner", "Im a beginner", "I''m learning", "Im learning", "I''m new to this", "Im new to this", "walk me through", "how does this work", "what''s wrong with my code", "what''s wrong", "can you break this down", "ELI5", "step by step", "where do I start", "what am I missing", "newbie here", "junior dev", "first time using", "how do I", "what is", "is this right", "not sure", "need help", "struggling", "show me", "help me debug", "best practice", "too complex", "overwhelmed", "lost", "debug this", "/socratic", "/hint", "/concept", "/pseudocode". Progressive clue systems, teaching techniques, and success metrics.

4k tokens
Astropy
by K-Dense-AI
×1

Core Python library for astronomy and astrophysics workflows that need Astropy APIs, including units/quantities, coordinates, FITS I/O, tables, time systems, WCS, and cosmology. Use when implementing or debugging astronomical data analysis code with Astropy.

18k tokens
Polars
by K-Dense-AI
×1

High-performance DataFrame library for Python ETL, analytics, and pandas migration. Use for expression-based data manipulation with lazy query optimization, parallel execution, streaming out-of-core processing, Arrow interoperability, and optional GPU execution.

20k tokens

How to use it

Copy the folder

Take biotender-max/bio-data-visualization-circos-plots from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.