Plot Circos genome plots with the pycircos package¶

Description¶

This small notebook shows examples of how to use the python package pycircos to plot circular maps of the genome, enriched with different data layers.

  • 'Circos' plots are a type of visualization that represent full genomes as a circle
  • the circle is subdivided in sectors which can represent different chromosomes or contigs, if there are any
  • the underlying data is primarily genome sequence information from a .fasta file, and genome annotation from a .gff
  • Fasta and GFF files need to have the same chromosome identifiers (seq_id), as they are matched

Requirements¶

  • need to install the python-circos package from bioconda, or using pip
  • needs biopython for sequence import and transformations

To install a fresh conda environment and use this as the kernel:

conda create -p myenv -c conda-forge -c bioconda biopython matplotlib
conda activate myenv
pip install python-circos requests

To install from a python chunk in a jupyter notebook:

import sys
!{sys.executable} -m pip install python-circos biopython requests matplotlib

Input data¶

  • first step is to make input data available in .fasta and .gff format
  • this repo has example files in the data/ dir

Run the python function¶

  • the function pycircos.py is provided with this repo
  • it takes care of data input and plotting
  • requires three arguments as input:
    • path to Fasta file
    • path to GFF file
    • path to desired output file

This will plot the example map:

python source/circos_plot.py \
  data/spyogenes_genome.fna \
  data/spyogenes_genome.gff \
  output/circos.png
In [5]:
from IPython.display import Image
Image(filename='../output/circos.png')
Out[5]:
No description has been provided for this image

The function also takes a fourth optional argument, a path to a TSV (tab-separated data) file. With a single file, the user can pass additional input data which will be plotted as seaprate lanes.

The supplied data must adhere to a format where the first two columns are seqid and position, indicating the chromosome and realive position of the data point. Then follows an arbitrary number of columns with header scatterplot, lineplot, or barplot. The numerical data from these columns will be parsed and plotted as long as it's possible.

Example of input data table:

tsv
seq	pos	scatterplot	lineplot	barplot
NC_002737.2	1587	0.894	0.790	0.887
NC_002737.2	2878	0.844	0.455	0.431
...

This code chunk will plot and example with extra data lanes:

python source/circos_plot.py \
  data/spyogenes_genome.fna \
  data/spyogenes_genome.gff \
  output/circos.png \
  data/spyogenes_expression_data.tsv
In [6]:
from IPython.display import Image
Image(filename='../output/circos_extra.png')
Out[6]:
No description has been provided for this image

Session info¶

In [7]:
!pip freeze
asttokens @ file:///home/conda/feedstock_root/build_artifacts/asttokens_1763409923949/work
attrs==25.4.0
beautifulsoup4==4.14.2
biopython @ file:///home/conda/feedstock_root/build_artifacts/biopython_1761734587192/work
bleach==6.3.0
certifi==2025.11.12
charset-normalizer==3.4.4
comm @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_comm_1753453984/work
contourpy @ file:///home/conda/feedstock_root/build_artifacts/contourpy_1762525276828/work
cycler @ file:///home/conda/feedstock_root/build_artifacts/cycler_1733332471406/work
debugpy @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_debugpy_1758162035/work
decorator @ file:///home/conda/feedstock_root/build_artifacts/decorator_1740384970518/work
defusedxml==0.7.1
executing @ file:///home/conda/feedstock_root/build_artifacts/executing_1756729339227/work
fastjsonschema==2.21.2
fonttools @ file:///home/conda/feedstock_root/build_artifacts/fonttools_1759187069296/work
idna==3.11
importlib_metadata @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_importlib-metadata_1747934053/work
ipykernel @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_ipykernel_1761567932/work
ipython @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_ipython_1762350942/work
ipython_pygments_lexers @ file:///home/conda/feedstock_root/build_artifacts/ipython_pygments_lexers_1737123620466/work
jedi @ file:///home/conda/feedstock_root/build_artifacts/jedi_1733300866624/work
Jinja2==3.1.6
jsonschema==4.25.1
jsonschema-specifications==2025.9.1
jupyter_client @ file:///home/conda/feedstock_root/build_artifacts/jupyter_client_1733440914442/work
jupyter_core @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_jupyter_core_1760643864/work
jupyterlab_pygments==0.3.0
kiwisolver @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_kiwisolver_1762488742/work
MarkupSafe==3.0.3
matplotlib==3.10.8
matplotlib-inline @ file:///home/conda/feedstock_root/build_artifacts/matplotlib-inline_1761214490209/work
mistune==3.1.4
munkres==1.1.4
nbclient==0.10.2
nbconvert==7.16.6
nbformat==5.10.4
nest_asyncio @ file:///home/conda/feedstock_root/build_artifacts/nest-asyncio_1733325553580/work
numpy @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_numpy_1763350996/work/dist/numpy-2.3.5-cp314-cp314-linux_x86_64.whl#sha256=6845a1314beab27017748f592bf887b8930c60411d97d98596aca90b518888fb
packaging @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_packaging_1745345660/work
pandocfilters==1.5.1
parso @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_parso_1755974222/work
pexpect @ file:///home/conda/feedstock_root/build_artifacts/pexpect_1733301927746/work
pillow @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_pillow_1761655794/work
platformdirs @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_platformdirs_1759953252/work
prompt_toolkit @ file:///home/conda/feedstock_root/build_artifacts/prompt-toolkit_1756321756983/work
psutil @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_psutil_1762092897/work
ptyprocess @ file:///home/conda/feedstock_root/build_artifacts/ptyprocess_1733302279685/work/dist/ptyprocess-0.7.0-py2.py3-none-any.whl#sha256=92c32ff62b5fd8cf325bec5ab90d7be3d2a8ca8c8a3813ff487a8d2002630d1f
pure_eval @ file:///home/conda/feedstock_root/build_artifacts/pure_eval_1733569405015/work
Pygments @ file:///home/conda/feedstock_root/build_artifacts/pygments_1750615794071/work
pyparsing @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_pyparsing_1758436411/work
PySide6==6.9.3
python-circos==0.3.0
python-dateutil @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_python-dateutil_1751104122/work
pyzmq @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_pyzmq_1757387023/work
referencing==0.37.0
requests==2.32.5
rpds-py==0.29.0
shiboken6==6.9.3
six @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_six_1753199211/work
soupsieve==2.8
stack_data @ file:///home/conda/feedstock_root/build_artifacts/stack_data_1733569443808/work
tinycss2==1.4.0
tornado @ file:///home/conda/feedstock_root/build_artifacts/tornado_1762506734690/work
traitlets @ file:///home/conda/feedstock_root/build_artifacts/traitlets_1733367359838/work
typing_extensions @ file:///home/conda/feedstock_root/build_artifacts/bld/rattler-build_typing_extensions_1756220668/work
unicodedata2 @ file:///home/conda/feedstock_root/build_artifacts/unicodedata2_1763054853500/work
urllib3==2.5.0
wcwidth @ file:///home/conda/feedstock_root/build_artifacts/wcwidth_1758622279606/work
webencodings==0.5.1
zipp @ file:///home/conda/feedstock_root/build_artifacts/zipp_1749421620841/work
In [ ]: