Make Your Python Data Visualisation Charts Well-"Rounded"

Author:Murphy  |  View: 20542  |  Time: 2025-03-22 22:30:20
Graph Generated by the Author

If your jobs include plotting data onto graphs to show insights, you may hear of the Circos chart for its fancy presentation. In fact, rather than good-looking, it is also great in terms of visualising complex relationships such as the connections between genes in genomic research. Of course, in the general Data Visualisation use cases, there are also some benefits such as more efficiently utilising the space, highlighting patterns with cycles, etc.

You may think drawing a Circos chart could be difficult, but I would say no. With an amazing visualisation called PyCirclize, you can do that extremely easily in Python.

In this article, I'm going to show you how to draw a very basic Circos diagram step by step. In the next article, I'll add some real-world use cases and more complex charts using this library.

Let's not waste too much time on how to install the library. It can be easily added to your Python environment using pip.

$ pip install pycirclize

1. Quick Start

Image by Sekau67 from Pixabay

Let's have a look at how it works before drawing our first Circos chart.

Of course, before everything, we need to import the Circos module from the library package.

from pycirclize import Circos

Usually, we want to have multiple sectors for the circle. We need to initialise a Circos object with the sector metadata. The sectors need to be defined in a dictionary before passing it to the Circos constructor.

# Initialize circos sectors
sectors = {"A": 1, "B": 2, "C": 3, "D": 4}
circos = Circos(sectors, space=5)

The space specifies how much padding we want to add between the sectors. If it is set to zero, this will become a "pie chart".

Next, loop in the sectors and render each sector with what we want to display in it.

for sector in circos.sectors:
    sector.axis(lw=2)
    sector.text(f"Sector: {sector.name}={sector.size}", size=15)

The sector.axis() tells the library to draw boundaries of each sector. The lw=2 means the "line width" is set to 2, which is thicker than default. Then, the sector.text() function shows the legend of each sector. The sector.name is the key of the sector dictionary that we defined previously, and the sector.size is the value of the dictionary that defines how large the sector is. The size we passed in will be normalised so we don't need to worry about that.

Finally, we need to plot it. The code below will do it.

fig = circos.plotfig()

Here is the effect and the full code snippet.

from pycirclize import Circos

# Initialize circos sectors
sectors = {"A": 1, "B": 2, "C": 3, "D": 4}
circos = Circos(sectors, space=5)

# Loop the sectors and generate the graph
for sector in circos.sectors:
    sector.axis(lw=2)
    sector.text(f"Sector: {sector.name}={sector.size}", size=15)

# Plot it
fig = circos.plotfig()

2. A Basic Use Case – Visualising the Traffic Volume

Image by Harut Movsisyan from Pixabay

Now, let's have a look at how to create a practical Circos chart using this library. I will simulate a real-world problem.

Suppose we have a traffic dataset for an intersection. We want to visualise how many vehicles have entered this intersection from each direction.

First of all, we need to import the Circos graph type from the PyCirclize library. Then, let's import Numpy as well to generate some dummy data.

from pycirclize import Circos
import numpy as np

Next, let's create the four directions and the x-axis representing 24 hours in a day.

# Sectors represent different directions of the intersection,
# with the x-axis representing 24 hours of the day
sectors = {"North": 24, "East": 24, "South": 24, "West": 24}
circos = Circos(sectors, space=5)

Then, in the loop of each sector for sector in circos.sectors, we need to simulate the x (24 hours) and y (number of vehicles).

### Please be advised that the code below needs to run in the sectors for-loop

# Simulate x (24 hours) and y (number of vehicles)
x = np.linspace(0, 24, 24)
y = np.random.randint(10, 1000, 24)  # Simulated hourly vehicle numbers

As the first step, let's add a bar chart as follows. The tuple (10, 50) means that we want the circle to start at the 10th pixel away from the centre, and stop at the 50th. In this ring-shaped area, the bar chart will be rendered.

# Plot bars for the number of vehicles passed the intersection
bar_track = sector.add_track((10, 50))
bar_track.bar(x, y)

Below is the effect, it is pretty cool.

Please be advised that the code needs to be put in a for-loop. Also, at the end it needs to call the plotfig() method of the circos object. If you are not sure, please scroll down to get the full code snippet which is gauranteed runable.

Next, let's add line charts to show the traffic volume trend. This time, the sector begins at the 60th pixel and ends up with the 100th. Recall that the bar chart ended at the 50th pixel, so there will be a 10px padding between these two ring shapes.

Besides, the xticks_by_interval(1) will make sure there are ticks for every hour.

# Plot a line chart showing traffic volume trends throughout the day
line_track = sector.add_track((60, 100))
line_track.xticks_by_interval(1)
line_track.line(x, y)

Here is the effect.

Great! Now, let's add the missing titles for the sectors. That are, the areas of the city that were already in the sectors dictionary.

# Plot sector name for identification
sector.text(sector.name, r=110, size=15)

The r=110 tells that the text should be rendered at the 110th pixel, which leaves another 10 pixels from the line chart. The size controls the font size.

If we would like the charts to be enclosed in the sector, we can call the .axis() function to do so.

# Add enclosed axis of the charts in the sectors
line_track.axis()
bar_track.axis()

Here is the full code snippet for your convenience. It will generate the above graph exactly.

from pycirclize import Circos
import numpy as np
np.random.seed(0)

# Sectors represent different areas in a city, with the x-axis representing 24 hours of the day
sectors = {"North": 24, "East": 24, "South": 24, "West": 24}
circos = Circos(sectors, space=5)

for sector in circos.sectors:
    # Simulate x (24 hours) and y (number of vehicles)
    x = np.linspace(0, 24, 24)
    y = np.random.randint(10, 1000, 24)  # Simulated hourly vehicle numbers

    # Plot bars for the number of vehicles passed the intersection
    bar_track = sector.add_track((10, 50))
    bar_track.bar(x, y)

    # Plot a line chart showing traffic volume trends throughout the day
    line_track = sector.add_track((60, 100))
    line_track.xticks_by_interval(1)
    line_track.line(x, y)

    # Plot sector name for identification
    sector.text(sector.name, r=110, size=15)

    # Add enclosed axis of the charts in the sectors
    line_track.axis()
    bar_track.axis()

fig = circos.plotfig()

Summary

Image by Foundry Co from Pixabay

In this article, I have demonstrated the PyCirclize library for its surface functionalities. Basically, I have introduced what is a Circos chart and why we want to use it sometimes. I have also simulated a real-world use case about visualising traffic volumes in different directions of an intersection to demonstrate how easy it is to generate such a graph in Python using the library.

We've seen how the library renders datasets into appealing insights by the diagram with a few lines of code, but that's only a fraction of its capability. Therefore, my next article next week will have a deep dive into this library again. There will be fancier charts, and of course, real-world examples will be simulated and demonstrated. Please check out the following articles!

Probably the Best Data Visualisation for Showing Many-to-Many Proportion In Python

Please consider subscribing to my updates and receiving emails so you won't miss something like this article in the future!

Unless otherwise noted all images are by the author

Tags: Data Science Data Visualization Machine Learning Python Technology

Comment