Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Create circular genome visualizations with Circos and pyCircos. Display multi-track data including ideograms, genes, variants, CNVs, and interaction arcs. Use when creating circular genome visualizations.
.claude/skills/bio-data-visualization-circos-plots/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 31% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 146% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 149% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 115% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 44% | 0% |
<!--
#
#
-->
Circular genome visualizations for displaying multiple data tracks around chromosome ideograms.
| Tool | Language | Best For | |------|----------|----------| | Circos | Perl/CLI | Publication-quality, complex layouts | | pyCircos | Python | Programmatic generation, integration | | circlize | R | Quick plots, Bioconductor integration |
bashconda install -c bioconda circos # Or download from http://circos.ca
Circos requires configuration files defining the plot structure.
# Chromosome definitions
karyotype = data/karyotype.human.hg38.txt
<ideogram>
<spacing>
default = 0.005r
</spacing>
radius = 0.90r
thickness = 20p
fill = yes
</ideogram>
<image>
dir = output
file = circos.png
png = yes
svg = yes
radius = 1500p
</image>
<<include etc/colors_fonts_patterns.conf>>
<<include etc/housekeeping.conf>><plots>
<plot>
type = scatter
file = data/scatter.txt
r0 = 0.75r
r1 = 0.85r
min = 0
max = 1
glyph = circle
glyph_size = 8p
color = red
</plot>
</plots><plot>
type = histogram
file = data/histogram.txt
r0 = 0.60r
r1 = 0.74r
min = 0
max = 100
fill_color = blue
</plot><plot>
type = heatmap
file = data/heatmap.txt
r0 = 0.50r
r1 = 0.59r
color = spectral-9-div
</plot><links>
<link>
file = data/links.txt
radius = 0.45r
bezier_radius = 0.1r
color = grey_a5
thickness = 2p
<rules>
<rule>
condition = var(intrachr)
color = red
</rule>
</rules>
</link>
</links># Scatter/histogram: chr start end value
hs1 1000000 1500000 0.75
hs1 2000000 2500000 0.45
# Links: chr1 start1 end1 chr2 start2 end2
hs1 1000000 1500000 hs5 5000000 5500000bashcircos -conf circos.conf
bashpip install pyCircos
pythonfrom pycircos import Gcircle import matplotlib.pyplot as plt # Initialize with genome size circle = Gcircle() # Add chromosome data (name, length) chromosomes = [ ('chr1', 248956422), ('chr2', 242193529), ('chr3', 198295559), ('chr4', 190214555), ('chr5', 181538259), ('chr6', 170805979), ('chr7', 159345973), ('chr8', 145138636), ('chr9', 138394717), ('chr10', 133797422), ('chr11', 135086622), ('chr12', 133275309) ] for name, length in chromosomes: circle.add_garc(Garc(arc_id=name, size=length, interspace=2, raxis_range=(900, 950), labelposition=80, label_visible=True)) circle.set_garcs() # Save fig = circle.figure fig.savefig('genome_circle.png', dpi=300)
pythonfrom pycircos import Gcircle, Garc import numpy as np circle = Gcircle() # Add chromosomes for name, length in chromosomes: arc = Garc(arc_id=name, size=length, interspace=3, raxis_range=(800, 850), labelposition=60) circle.add_garc(arc) circle.set_garcs() # Add scatter track for name, length in chromosomes: positions = np.random.randint(0, length, 50) values = np.random.random(50) circle.scatterplot(name, data=values, positions=positions, raxis_range=(700, 780), facecolor='red', markersize=5) # Add bar track for name, length in chromosomes: positions = np.linspace(0, length, 100) values = np.random.random(100) * 100 circle.barplot(name, data=values, positions=positions, raxis_range=(600, 680), facecolor='blue') # Add links circle.chord_plot(('chr1', 10000000, 20000000), ('chr5', 50000000, 60000000), raxis_range=(0, 550), facecolor='purple', alpha=0.5) fig = circle.figure fig.savefig('circos_with_data.png', dpi=300)
rinstall.packages('circlize')
rlibrary(circlize) # Initialize with genome circos.initializeWithIdeogram(species = 'hg38') # Add track with data bed <- data.frame( chr = paste0('chr', sample(1:22, 100, replace=TRUE)), start = sample(1:1e8, 100), end = sample(1:1e8, 100), value = runif(100) ) bed$end <- bed$start + 1e6 circos.genomicTrack(bed, panel.fun = function(region, value, ...) { circos.genomicPoints(region, value, pch=16, cex=0.5, col='red') }) # Add links link_data <- data.frame( chr1 = c('chr1', 'chr3'), start1 = c(1e7, 5e7), end1 = c(2e7, 6e7), chr2 = c('chr5', 'chr10'), start2 = c(3e7, 8e7), end2 = c(4e7, 9e7) ) for (i in 1:nrow(link_data)) { circos.link(link_data$chr1[i], c(link_data$start1[i], link_data$end1[i]), link_data$chr2[i], c(link_data$start2[i], link_data$end2[i]), col = 'grey') } circos.clear()
rlibrary(circlize) circos.initializeWithIdeogram(species = 'hg38', plotType = c('axis', 'labels')) # Gene density track circos.genomicDensity(gene_bed, col = 'blue', track.height = 0.1) # Variant density track circos.genomicDensity(variant_bed, col = 'red', track.height = 0.1) # Heatmap track circos.genomicHeatmap(expression_bed, col = colorRamp2(c(-2, 0, 2), c('blue', 'white', 'red'))) circos.clear()
python# pyCircos CNV plot cnv_data = [ ('chr1', 10000000, 20000000, 2.5), # Gain ('chr3', 50000000, 80000000, 0.5), # Loss ('chr7', 100000000, 120000000, 3.0), # Amplification ] for chrom, start, end, log2 in cnv_data: color = 'red' if log2 > 1.5 else 'blue' if log2 < 0.7 else 'grey' circle.barplot(chrom, data=[log2], positions=[(start+end)//2], width=end-start, raxis_range=(600, 700), facecolor=color)
python# Visualize gene fusions as arcs fusions = [ ('chr9', 133600000, 133700000, 'chr22', 23200000, 23300000), # BCR-ABL ('chr2', 42300000, 42500000, 'chr2', 29400000, 29600000), # EML4-ALK ] for chr1, s1, e1, chr2, s2, e2 in fusions: circle.chord_plot((chr1, s1, e1), (chr2, s2, e2), raxis_range=(0, 500), facecolor='purple', alpha=0.7)
rlibrary(circlize) circos.initializeWithIdeogram(chromosome.index = paste0('chr', 1:22)) # Add Hi-C links with color by contact frequency for (i in 1:nrow(hic_contacts)) { col = colorRamp2(c(0, 100), c('grey90', 'red'))(hic_contacts$count[i]) circos.link(hic_contacts$chr1[i], c(hic_contacts$start1[i], hic_contacts$end1[i]), hic_contacts$chr2[i], c(hic_contacts$start2[i], hic_contacts$end2[i]), col = col) } circos.clear()
pythonfrom pycircos import Gcircle, Garc import pandas as pd # Load data variants = pd.read_csv('variants.bed', sep='\t', names=['chr', 'start', 'end', 'type']) cnv = pd.read_csv('cnv.bed', sep='\t', names=['chr', 'start', 'end', 'log2']) # Initialize circle = Gcircle() chromosomes = [('chr' + str(i), size) for i, size in enumerate([ 248956422, 242193529, 198295559, 190214555, 181538259, 170805979, 159345973, 145138636, 138394717, 133797422, 135086622, 133275309, 114364328, 107043718, 101991189, 90338345, 83257441, 80373285, 58617616, 64444167, 46709983, 50818468 ], start=1)] for name, length in chromosomes: arc = Garc(arc_id=name, size=length, interspace=2, raxis_range=(850, 900)) circle.add_garc(arc) circle.set_garcs() # Variant density track for chrom, length in chromosomes: chrom_vars = variants[variants['chr'] == chrom] if len(chrom_vars) > 0: hist, bins = np.histogram(chrom_vars['start'], bins=50, range=(0, length)) circle.barplot(chrom, data=hist, positions=bins[:-1], raxis_range=(750, 840), facecolor='steelblue') # CNV track for chrom, length in chromosomes: chrom_cnv = cnv[cnv['chr'] == chrom] for _, row in chrom_cnv.iterrows(): color = 'red' if row['log2'] > 0.3 else 'blue' if row['log2'] < -0.3 else 'grey' circle.fillplot(chrom, data=[abs(row['log2'])], positions=[(row['start'] + row['end']) // 2], raxis_range=(650, 740), facecolor=color) fig = circle.figure fig.savefig('genome_summary.png', dpi=300, bbox_inches='tight')
<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 28,171 | 21,381 | -24% | 1 | 1 | 0% | 6,200 | 8,134 | +31% | 0 | 0 | — |
case-07 | pass→pass | 15,003 | 7,393 | -51% | 1 | 1 | 0% | 3,184 | 5,090 | +60% | 0 | 0 | — |
case-13 | pass→pass | 8,581 | 5,270 | -39% | 1 | 1 | 0% | 1,734 | 4,651 | +168% | 0 | 0 | — |
case-14 | pass→pass | 13,459 | 7,583 | -44% | 1 | 1 | 0% | 2,668 | 5,156 | +93% | 0 | 0 | — |
case-15 | fail→fail | 14,586 | 13,864 | -5% | 1 | 1 | 0% | 3,078 | 6,469 | +110% | 0 | 0 | — |
case-16 | pass→pass | 3,931 | 2,506 | -36% | 1 | 1 | 0% | 821 | 3,987 | +386% | 0 | 0 | — |
case-17 | pass→pass | 6,369 | 2,113 | -67% | 1 | 1 | 0% | 1,203 | 3,928 | +227% | 0 | 0 | — |
case-02 | pass→pass | 10,433 | 6,069 | -42% | 1 | 1 | 0% | 2,285 | 4,806 | +110% | 0 | 0 | — |
case-03 | pass→pass | 9,478 | 9,717 | +3% | 1 | 1 | 0% | 1,928 | 5,532 | +187% | 0 | 0 | — |
case-04 | fail→pass | 11,088 | 7,043 | -36% | 1 | 1 | 0% | 2,011 | 4,941 | +146% | 0 | 0 | — |
case-05 | fail→pass | 11,548 | 9,995 | -13% | 1 | 1 | 0% | 2,235 | 5,564 | +149% | 0 | 0 | — |
case-06 | pass→pass | 12,292 | 9,160 | -25% | 1 | 1 | 0% | 2,548 | 5,471 | +115% | 0 | 0 | — |
case-08 | fail→pass | 11,585 | 4,996 | -57% | 1 | 1 | 0% | 2,131 | 4,585 | +115% | 0 | 0 | — |
case-09 | fail→pass | 16,846 | 6,016 | -64% | 1 | 1 | 0% | 3,352 | 4,838 | +44% | 0 | 0 | — |
case-10 | pass→pass | 24,940 | 8,024 | -68% | 1 | 1 | 0% | 2,459 | 5,348 | +117% | 0 | 0 | — |
case-11 | fail→fail | 22,404 | 24,644 | +10% | 1 | 1 | 0% | 4,730 | 9,228 | +95% | 0 | 0 | — |
case-12 | pass→pass | 9,102 | 6,241 | -31% | 1 | 1 | 0% | 1,831 | 4,763 | +160% | 0 | 0 | — |
case-18 | fail→pass | 8,729 | 5,884 | -33% | 1 | 1 | 0% | 1,598 | 4,853 | +204% | 0 | 0 | — |
case-19 | pass→pass | 6,569 | 3,184 | -52% | 1 | 1 | 0% | 1,238 | 4,207 | +240% | 0 | 0 | — |
case-20 | pass→pass | 15,045 | 11,352 | -25% | 1 | 1 | 0% | 2,633 | 5,667 | +115% | 0 | 0 | — |
case-21 | pass→pass | 19,356 | 12,777 | -34% | 1 | 1 | 0% | 3,646 | 6,162 | +69% | 0 | 0 | — |
case-22 | pass→pass | 14,539 | 13,359 | -8% | 1 | 1 | 0% | 2,882 | 6,290 | +118% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +27 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/24/2026 | +27% |
Other measured skills in the registry, with their headline benchmark lift.