Artificial Intelligence revolutionizes various fields such as networking, multi-dimensional data exploration, genomics, and sensor data analysis, increasing the demand for advanced data visualization tools. R, known for its robust visualization capabilities, particularly in circular plots, has played a significant role in this regard. However, Python’s visualization libraries like matplotlib and seaborn, though powerful, lack specific features for circular data visualization. Recognizing this gap, developers created pycirclize, drawing inspiration from R’s circlize
and RCircos
, offering Python users a specialized tool for intricate circular visualizations.
This library enhances Python’s data analysis toolkit, allowing users to understand complex relationships and patterns better, and present their findings with clarity and impact. The motivation behind pycirclize
likely stems from the growing trend of transitioning from R to Python seen in other libraries.
Python users now have access to circular visualization, an area historically dominated by R, thanks to pycirclize
. This new library enhances the Python visualization landscape, enabling the creation of intricate plots that were previously challenging. pycirclize
offers a fresh and insightful approach to visualizing and analyzing data, whether for understanding multi-dimensional datasets, dissecting network traffic nuances, or unraveling genomic sequences.
Circular visualization proves beneficial for Large Language Model (LLM) vector databases, simplifying the representation of high-dimensional vector spaces into a more understandable two-dimensional format. It aids in displaying relationships and groupings within the vector data, facilitating visual exploration of relationships between various vectors, such as words, sentences, or documents.
Leveraging Gen AI for analyzing and interpreting complex datasets, including those visualized circularly, holds promise. AI can identify patterns or clusters within circular visualizations of vector databases or genomic data, enriching understanding and insights drawn from such visuals.
This advancement not only expands Python enthusiasts’ analytical capabilities but also promotes a more inclusive and adaptable visualization environment, bridging the gap between Python and R’s established strengths in data visualization.
pycirclize, like circlize in R, can display various data types in circular plots. Here are common data formats:
Before utilizing data sources, ensuring proper data cleaning and structuring is crucial. This may involve normalization, handling missing values, or aggregating data points to make visualizations informative and meaningful.
#for pip installation
pip install pycirclize
#Conda Installation
conda install -c conda-forge pycirclize
#import csv
Similarly like R package, pyCirclize uses a circular layout design with Sectors and Tracks. Each sector can have a different set of data, and each sector can have an unlimited number of tracks for data visualization.
Each sector in the `Pycirclize` package represents a division on the circle’s circumference, while “sectors” in the data refer to various categories or groupings. Within each sector where the data is shown, there are concentric rings called “tracks” that enable the presentation of numerous layers of information.
The Understanding of Sector and track and later we will use data frame and see how sectors and tracks can be used.
from pycirclize import Circos
# Initialize circos sectors
sectors = {"cat A": 15, "Cat B": 15, "Cat C": 12, "Cat D": 20, "Cat E": 10}
circos = Circos(sectors, space=6) #space =6, the space between each sector
for sector in circos.sectors:
# Plot sector axis & name text
sector.axis(fc="pink", ls="dashdot", lw=2, ec="green", alpha=0.5, )
sector.text(f"Sector: {sector.name}={sector.size}", size=12) #size of the text on figure
fig = circos.plotfig()
#import csv
Tracks are concentric rings within the circle, each displaying a different aspect or measurement of the data. Sectors provide a categorical breakdown, while tracks offer layers of data detail, allowing a multifaceted view of the dataset in a single cohesive circular plot.
You can freely place tracks within the sector radius range (0 – 100).
from pycirclize import Circos
# Initialize circos sectors
sectors = {"cat A": 15, "Cat B": 15, "Cat C": 12, "Cat D": 20, "Cat E": 10}
circos = Circos(sectors, space=5)
for sector in circos.sectors:
# Plot sector axis & name text
sector.axis(fc="none", ls="dashed", lw=2, ec="Blue", alpha=0.3)
sector.text(f"{sector.name}={sector.size}", size=10)
# Set Track01 (Radius: 80 - 100)
track1 = sector.add_track((80, 100))
track1.axis(fc="red", alpha=0.2)
track1.text(track1.name)
# as you can see the track radius is kept from 80 to 100 and then
# next track is kept at 75 so that there is a gap of 5 between the tracks
# we can reduce or increase it, as done in the next tracks
# Set Track02 (Radius: 50 - 75)
track2 = sector.add_track((50, 75))
track2.axis(fc="cyan", alpha=0.2)
track2.text(track2.name)
# Set Track03 (Radius: 20 - 45)
track3 = sector.add_track((20, 48))
track3.axis(fc="lime", alpha=0.2)
track3.text(track3.name)
#Set Track04 (Radius 5 -15)
track4 = sector.add_track((5, 15))
track4.axis(fc="yellow", alpha=0.2)
track4.text(track4.name)
fig = circos.plotfig()
#import csv
As You can see, the basic parameters are similar to that of matplotlib and seaborn, for example : linestyle, fc, Alpha and, etc. However you must intialise the object Circos for setting of tracks and sectors.
from pycirclize import Circos
import numpy as np
np.random.seed(0)
sectors = {"A": 10, "B": 15, "C": 12, "D": 20, "E": 15}
circos = Circos(sectors, space=5) #initilaise
for sector in circos.sectors:
# Plot sector name
sector.text(f"Sector {sector.name}", r=106, size=12)
# r = 106 place #the text, if we change the value the texts move
# Create x positions & randomized y values for data plotting
x = np.arange(sector.start, sector.end) + 0.5
#sector.start
#is 0 and ends at the value of sector defined ,for a it is 10, B is 15
y = np.random.randint(0, 100, len(x))
# Plot line
line_track = sector.add_track((75, 100), r_pad_ratio=0.1)
line_track.axis(fc= 'yellow')
line_track.xticks_by_interval(1)
line_track.line(x, y)
# Plot points
points_track = sector.add_track((45, 70), r_pad_ratio=0.1)
points_track.axis(fc)
points_track.scatter(x, y)
# Plot bar
bar_track = sector.add_track((15, 40), r_pad_ratio=0.1)
bar_track.axis()
bar_track.bar(x, y)
fig = circos.plotfig()
#import csv
from pycirclize import Circos
import math
sectors = {"A": 10, "B": 20, "C": 15}
circos = Circos(sectors, end=270, space=10) #end angle
circos.axis(fc="lightgrey", ec="red") #ec is edge color
circos.line(r=80, deg_lim=(0, 270), color="red") #line circular
circos.line(r=60, deg_lim=(90, 360), color="blue", lw=3, ls="dotted")
circos.text("center") #represent text on the chart
circos.text("right-middle", r=50, deg=90) # r is radius with degree
circos.text("bottom", r=100, deg=180)
circos.text("left", r=100, deg=270)
circos.text("left-top", r=100 * math.sqrt(2), deg=315)
circos.rect(r_lim=(30, 50), deg_lim=(90, 360), fc="lime",
ec="grey", lw=2, hatch="//") # rectangular Fill
circos.rect(r_lim=(30, 100), deg_lim=(0, 90), fc="orange", alpha=0.2)
fig = circos.plotfig()
#import csv
Link charts are essential for showing linkages or connections between various data points or entities in circular visualizations, particularly those created with the R packages Circos and Circlize. These are especially helpful in fields such as genomics, networking, and any other area where links between different segments need to be emphasised. In genomics, they can be used to illustrate interactions between genes or genomic areas. Link charts provide an excellent way to express the nature, strength, and frequency of relationships by visually connecting points on a circular plot. This makes the complicated relational data they represent easy to understand.
Let’s say we have a networking data which looks like this.
import pandas as pd
net_df = pd.DataFrame({
"Connection_from": ["A", "A", "A", "B", "B", "C", "C"],
"val_1": [0, 1, 9, 5, 18, 1, 11.5],
"val_2": [0, 2, 10, 7, 16, 3, 14],
"connection_to": ["A", "A", "B", "C", "B", "B", "A"],
"val_3": [7, 7, 4, 6, 11, 2, 4],
"val_4": [8, 6, 3, 6, 13, 0, 3]
})
net_df
The output dataframe looks like
There are two ways to put up a connection, first lets understand statically and plot the linkage between the connection from and connection to.
from pycirclize import Circos
sectors = {"A": 10, "B": 20, "C": 15}
name2color = {"A": "red", "B": "blue", "C": "green"}
circos = Circos(sectors, space=5)
for sector in circos.sectors:
track = sector.add_track((95, 100))
track.axis(fc=name2color[sector.name])
track.text(sector.name, color="black", size=12)
track.xticks_by_interval(1)
# Plot links
circos.link(("A", 0,0), ("A", 7,8))
circos.link(("A", 1, 2), ("A", 7, 6))
circos.link(("A", 9, 10), ("B", 4, 3))
circos.link(("B", 5, 7), ("C", 6, 6))
circos.link(("B", 18, 16), ("B", 11, 13))
circos.link(("C", 1, 3), ("B", 2, 0))
circos.link(("C", 11.5, 14), ("A", 4, 3))
circos.text("Network")
fig = circos.plotfig()
result = [((row['Connection_from'], row['val_1'], row['val_2']),
(row['connection_to'], row['val_3'], row['val_4'])) for index,
row in net_df.iterrows()]
#print(result)
sectors = {"A": 10, "B": 20, "C": 15}
name2color = {"A": "red", "B": "blue", "C": "green"}
circos = Circos(sectors, space=5)
for sector in circos.sectors:
track = sector.add_track((95, 100))
track.axis(fc=name2color[sector.name])
track.text(sector.name, color="black", size=12)
track.xticks_by_interval(1)
for link in result:
circos.link(link[0], link[1])
circos.text("Network")
fig = circos.plotfig()
The output for the both ways is same:
This is an exemplar plot which can be used to cluster values or show multidimensional data where rect feature (class) has been used from circos.
from pycirclize import Circos
from pycirclize.utils import ColorCycler
ColorCycler.set_cmap("viridis")
sectors = {"A": 10, "B": 20, "C": 15, "D":10}
circos = Circos(sectors, space=5)
for sector in circos.sectors:
track1 = sector.add_track((90, 100))
track1.axis()
# Plot rect & text (style1)
for i in range(int(track1.size)):
start, end = i, i + 1
track1.rect(start, end, fc=ColorCycler())
track1.text(str(end), (end + start) / 2)
# Plot rect & text (style2)
track2 = sector.add_track((65, 85))
for i in range(int(track2.size)):
start, end = i, i + 1
track2.rect(start, end, fc=ColorCycler(), ec="white", lw=1)
track2.text(str(end), (end + start) / 2, color="white", orientation="vertical")
# Plot rect & text (style3)
track3 = sector.add_track((25, 60))
for i in range(int(track3.size)):
start, end = i, i + 1
track3.rect(start, end, fc=ColorCycler(), ec="white", lw=1)
track3.text(str(end), (end + start) / 2, color="white", orientation="vertical")
circos.text("Gene-324")
fig = circos.plotfig()
In genomics, circos plots are strong visualisation tools that let scientists present intricate genomic data in a circle format. These maps are especially helpful for showing connections and contrasts between different genomes or between different areas of the same genome. They allow for a thorough and condensed depiction of big datasets by illuminating a variety of genomic properties, including gene expressions, structural changes, and mutations. In contrast to conventional linear genome maps, this kind of visualisation makes it easier to spot patterns and correlations.
Here is an example :
from pycirclize.utils import fetch_genbank_by_accid
from pycirclize.parser import Genbank
# Download `NC_002483` E.coli plasmid genbank
gbk_fetch_data = fetch_genbank_by_accid("NC_002483")
gbk = Genbank(gbk_fetch_data)
print("Genome Length:",gbk.full_genome_length ,
"\n___________________________________________________________\n")
print("genome sequence :",gbk.genome_seq,
"\n___________________________________________________________\n")
print("Records :\n")
for i in gbk.records :
print(i)
# Initialize Circos instance with genome size
circos = Circos(sectors={gbk.name: gbk.range_size})
circos.text(f"Escherichia coli K-12 plasmid F\n\n{gbk.name}", size=14)
circos.rect(r_lim=(90, 100), fc="lightgrey", ec="none", alpha=0.5)
sector = circos.sectors[0]
# Plot forward strand CDS
f_cds_track = sector.add_track((95, 100))
f_cds_feats = gbk.extract_features("CDS", target_strand=1)
f_cds_track.genomic_features(f_cds_feats, plotstyle="arrow", fc="salmon", lw=0.5)
# Plot reverse strand CDS
r_cds_track = sector.add_track((90, 95))
r_cds_feats = gbk.extract_features("CDS", target_strand=-1)
r_cds_track.genomic_features(r_cds_feats, plotstyle="arrow", fc="skyblue", lw=0.5)
# Plot 'gene' qualifier label if exists
labels, label_pos_list = [], []
for feat in gbk.extract_features("CDS"):
start = int(str(feat.location.start))
end = int(str(feat.location.end))
label_pos = (start + end) / 2
gene_name = feat.qualifiers.get("gene", [None])[0]
if gene_name is not None:
labels.append(gene_name)
label_pos_list.append(label_pos)
f_cds_track.xticks(label_pos_list, labels, label_size=6, label_orientation="vertical")
# Plot xticks (interval = 10 Kb)
r_cds_track.xticks_by_interval(
10000, outer=False, label_formatter=lambda v: f"{v/1000:.1f} Kb"
)
fig = circos.plotfig()
In conclusion, Pycirclize enhances Python’s visualization landscape, enabling insightful data exploration across various domains. Its flexibility and power make it a valuable tool for analysts and researchers alike. Embrace pycirclize
to unlock new dimensions in your data visualization journey.