## Data is Beautiful

A practical book on data visualisation that shows you how to create static and interactive visualisations that are engaging and beautiful.

# Chord Pro Features For Chord Diagrams

## Preamble¶

In [1]:
from chord import Chord

## Introduction¶

Note

This document is best viewed online where the interactivity of the demonstrations can be experienced.

In a chord diagram (or radial network), entities are arranged radially as segments with their relationships visualised by arcs that connect them. The size of the segments illustrates the numerical proportions, whilst the size of the arc illustrates the significance of the relationships1. Chord diagrams are useful when trying to convey relationships between different entities, and they can be beautiful and eye-catching.

### Get Chord Pro¶

To switch to the PRO version of the chord package, you need to assign a valid username (the email you entered at purchase) and license key. This can be purchased here.

In [ ]:
Chord.user = "your username"
Chord.key = "your license key"

We'll use the following data for the co-occurrence matrix and names parameters until we cover divided diagrams.

In [2]:
matrix = [
[0, 5, 6, 4, 7, 4],
[5, 0, 5, 4, 6, 5],
[6, 5, 0, 4, 5, 5],
[4, 4, 4, 0, 5, 5],
[7, 6, 5, 5, 0, 4],
[4, 5, 5, 5, 4, 0],
]

names = ["Action", "Adventure", "Comedy", "Drama", "Fantasy", "Thriller"]

## Defaults¶

Without passing in any arguments for the customisation parameters, the output will use the default value.

In [3]:
Chord(matrix, names).show()
Chord Diagram

## Outputs Methods¶

Chord Pro supports the following outputs.

### HTML to Jupyer Lab Cell (Interactive)¶

Outputs the interactive diagram to a Jupyter Lab cell.

In [4]:
Chord(matrix, names, title="Jupyter Lab Cell").show()
Chord Diagram

### HTML to file (Interactive)¶

Saves an interactive HTML file locally.

In [5]:
Chord(matrix, names).to_html('out.html')

### PNG to Jupyer Lab Cell (Image)¶

Outputs a PNG to a Jupyter Lab Cell.

In [6]:
Chord(matrix, names).show_png()

### PNG to file (image)¶

Saves a PNG file locally.

In [7]:
Chord(matrix, names).to_png('out.png')

### PDF to file¶

Saves a PDF file locally.

In [8]:
Chord(matrix, names).to_pdf('out.pdf')

### Disable SSL Verification¶

verify_ssl=True Some users behind school/corporate networks may experience issues contacting the Chord API end-points. One workaround is to use verify_ssl=False. You will receive an InsecureRequestWarning with a link to further information.

In [9]:
Chord(matrix, names, verify_ssl=False, title="SSL Verification Disabled").show()
/Users/shahin/miniconda3/envs/analytics/lib/python3.9/site-packages/urllib3/connectionpool.py:1013: InsecureRequestWarning: Unverified HTTPS request is being made to host 'api.shahin.dev'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
warnings.warn(
Chord Diagram

## Chord Colours¶

colors="d3.schemeSet1"

The default setting for the chord colours is d3.schemeSet1.

This can be changed to any of the sequential, diverging, or categorical colour schemes in d3-scale-chromatic, such as d3.schemeAccent, d3.schemeBlues[n], or d3.schemePaired :

In [10]:
Chord(matrix, names, colors="d3.schemeAccent").show()
Chord Diagram

The colors parameter also accepts a Python list of HEX colour codes.

In [11]:
grayscale = ["#222222", "#333333", "#4c4c4c", "#666666", "#848484", "#9a9a9a"]
Chord(matrix, names, colors=grayscale).show()
Chord Diagram

## Opacity¶

opacity=0.8

This sets the opacity for the arcs when they are not selected (mouseover/touch).

In [12]:
Chord(matrix, names, opacity=0.2).show()
Chord Diagram

opacity=0.8

This sets the direction of the arc gradients.

In [13]:
Chord(matrix, names, reverse_gradients=True).show()
Chord Diagram

## Arc Numbers¶

arc_numbers=False

This sets the visibility of quantity labels on segments.

In [14]:
Chord(matrix, names, arc_numbers=True).show()
Chord Diagram

## Diagram Title¶

titles=""

This sets the text and visibility of the diagram title.

In [15]:
Chord(matrix, names, title="Movie Genre Co-occurrence").show()
Chord Diagram

padding=0.01

This sets the padding between segments as a fraction of the circle.

In [16]:
Chord(matrix, names, padding=0.5).show()
Chord Diagram

## Width¶

width=700

This sets the width (and height) of the chord diagram.

In [17]:
Chord(matrix, names, width=400).show()
Chord Diagram

## Rotation¶

rotate=0

This sets the rotation of the chord diagram.

In [18]:
Chord(matrix, names, rotate=-30).show()
Chord Diagram

inner_radius_scale=0.45, outer_radius_scale=1.1,

This sets the inner and outer radius scale of the chord diagram.

In [19]:
Chord(matrix, names, inner_radius_scale=0.3, outer_radius_scale=1.5).show()
Chord Diagram

## Label Color¶

label_color="#454545"

This sets the label colour.

In [20]:
Chord(matrix, names, label_color="#B362FF").show()
Chord Diagram

## Curved Labels¶

curved_labels=False

This turns curved labels on or off. It's not suitable for diagrams with many segments, but sometimes it can improve the look.

In [21]:
Chord(matrix, names, curved_labels=True).show()
Chord Diagram

## Label Wrapping¶

wrap_labels=True

This turns label wrapping on or off. It's on by default.

Let's temporarily change our names data to demonstrate this.

In [22]:
names = ["Exciting Action", "Fun Adventure", "Hilarious Comedy", "Drama", "Fantasy", "Chilling Thriller"]
In [23]:
Chord(matrix, names).show()
Chord Diagram

Now to demonstrate label wrapping set to disabled.

In [24]:
Chord(matrix, names, wrap_labels=False).show()
Chord Diagram

We'll restore our names data before we continue.

In [25]:
names = ["Action", "Adventure", "Comedy", "Drama", "Fantasy", "Thriller"]

## Margins¶

margin=100

This sets the chord diagram margin.

In [26]:
Chord(matrix, names, margin=200).show()
Chord Diagram

## Font-size¶

font_size="16px" font_size_large="20px"

This sets the font-size for two views, font-size-large (@media min-width: 600px), otherwise font-size. Setting a large font-size may require adjustment of the margin parameter to avoid text-clipping.

In [27]:
Chord(matrix, names, font_size="20px", font_size_large="30px").show()
Chord Diagram

popup_width=350

This sets the max-width of the popup.

In [28]:
Chord(matrix, names, popup_width=150).show()
Chord Diagram

conjunction="and" verb="occur together in" noun="instances"

These change parts of the popup text:

e.g. we could change it to:

In [29]:
Chord(matrix, names, conjunction="&", verb="appear together in", noun="cases",).show()
Chord Diagram

## Symmetric and Asymmetric Diagrams¶

symmetric=True

This turns the symmetric mode on or off. The primary support is for symmetric diagrams, but there is some support for asymmetric ones.

For example, this will update the popup text to reflect the asymmetry of relationships.

In [30]:
matrix = [
[0, 5, 3, 4, 7, 3],
[2, 0, 6, 5, 2, 7],
[6, 3, 0, 4, 5, 7],
[8, 3, 4, 0, 4, 7],
[2, 8, 6, 7, 0, 4],
[5, 3, 3, 4, 2, 0],
]

Chord(matrix, names, symmetric=False).show()
Chord Diagram

allow_download=False

This sets the visibility of the Download button. This uses client-side scripts to create and download an SVG from the current visualisation. This has been tested on Firefox and Safari.

In [31]:
Chord(matrix, names, allow_download=True).show()
Chord Diagram

details=[], details_thumbs=[],

In the basic version of chord, matrix and names are the only sets of data that can be used to create a chord diagram. In the Pro version, you can also use details and details_thumbs. These enable the rich hover boxes.

First, we'll reduce the co-occurrence frequency in our matrix to make the following examples easier to follow.

In [32]:
matrix = [
[0, 2, 3, 1, 4, 1],
[2, 0, 2, 1, 3, 2],
[3, 2, 0, 1, 2, 2],
[1, 1, 1, 0, 2, 2],
[4, 3, 2, 2, 0, 1],
[1, 2, 2, 2, 1, 0],
]

Let's create and populate an example details and details_thumbs variable.

In [33]:
details = [
[[], ["Movie 1","Movie 2"], ["Movie 3","Movie 4","Movie 5"], ["Movie 6","Movie 7"], ["Movie 8","Movie 9","Movie 10","Movie 11"], ["Movie 12"]],
[["Movie 13","Movie 14"], [], ["Movie 15","Movie 16"], ["Movie 17"], ["Movie 18","Movie 19","Movie 20"], ["Movie 21","Movie 22"]],
[["Movie 23","Movie 24","Movie 25"], ["Movie 26","Movie 27"], [], ["Movie 28"], ["Movie 29","Movie 30"], ["Movie 31","Movie 32"]],
[["Movie 33"], ["Movie 34"], ["Movie 35"], [], ["Movie 36","Movie 37"], ["Movie 38","Movie 39"]],
[["Movie 40","Movie 41","Movie 42","Movie 43"], ["Movie 44","Movie 45","Movie 46"], ["Movie 47","Movie 48"], ["Movie 49","Movie 50"], [], ["Movie 51"]],
[["Movie 52"], ["Movie 53","Movie 54"], ["Movie 55","Movie 56"], ["Movie 57","Movie 58"], ["Movie 59"], []],
]

The details parameter can accept HTML.

In [34]:
details_thumbs = [
[[], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png"]],
[["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], [], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"]],
[["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], [], ["https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"]],
[["https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png"], [], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"]],
[["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], [], ["https://datacrayon.com/images/lablet.png"]],
[["https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png","https://datacrayon.com/images/lablet.png"], ["https://datacrayon.com/images/lablet.png"], []],
]

It looks a bit messy, so let's achieve some clarity using the pandas.DataFrame HTML table output.

In [35]:
import pandas as pd
pd.DataFrame(details)
Out[35]:
0 1 2 3 4 5
0 [] [Movie 1, Movie 2] [Movie 3, Movie 4, Movie 5] [Movie 6, Movie 7] [Movie 8, Movie 9, Movie 10, Movie 11] [Movie 12]
1 [Movie 13, Movie 14] [] [Movie 15, Movie 16] [Movie 17] [Movie 18, Movie 19, Movie 20] [Movie 21, Movie 22]
2 [Movie 23, Movie 24, Movie 25] [Movie 26, Movie 27] [] [Movie 28] [Movie 29, Movie 30] [Movie 31, Movie 32]
3 [Movie 33] [Movie 34] [Movie 35] [] [Movie 36, Movie 37] [Movie 38, Movie 39]
4 [Movie 40, Movie 41, Movie 42, Movie 43] [Movie 44, Movie 45, Movie 46] [Movie 47, Movie 48] [Movie 49, Movie 50] [] [Movie 51]
5 [Movie 52] [Movie 53, Movie 54] [Movie 55, Movie 56] [Movie 57, Movie 58] [Movie 59] []
In [36]:
pd.DataFrame(details_thumbs)
Out[36]:
0 1 2 3 4 5
0 [] [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png]
1 [https://datacrayon.com/images/lablet.png, htt... [] [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png] [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt...
2 [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt... [] [https://datacrayon.com/images/lablet.png] [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt...
3 [https://datacrayon.com/images/lablet.png] [https://datacrayon.com/images/lablet.png] [https://datacrayon.com/images/lablet.png] [] [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt...
4 [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt... [] [https://datacrayon.com/images/lablet.png]
5 [https://datacrayon.com/images/lablet.png] [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png, htt... [https://datacrayon.com/images/lablet.png] []
In [37]:
Chord(matrix, names, details=details, details_thumbs=details_thumbs).show()
Chord Diagram

thumbs_width=85 thumbs_margin=5 thumbs_font_size=14

These allow changing the spacing and size of the details thumbnails.

In [38]:
Chord(matrix, names, details=details, details_thumbs=details_thumbs,
thumbs_width=40, thumbs_margin=10, thumbs_font_size=10).show()
Chord Diagram

## Divided (Bipartite) Chord Diagram¶

divide=False, divide_idx=0, divide_size=0.5,

• divide enables/disables the divided chord diagram mode.
• divide_idx sets the dividing point of the matrix.
• divide_size sets the size of the spacing that creates the divide.

First, we'll change the data in matrix and names such that they're suitable for our bipartite chord diagram. We'll add some new colours too.

In [39]:
matrix = [
[0, 0, 0, 1, 4, 1],
[0, 0, 0, 1, 3, 2],
[0, 0, 0, 1, 2, 2],
[1, 1, 1, 0, 0, 0],
[4, 3, 2, 0, 0, 0],
[1, 2, 2, 0, 0, 0],
]

names = ["A", "B", "C", "1", "2", "3"]
colors = ["#7400B8", "#5E60CE", "#5684D6", "#56CFE1", "#64DFDF", "#80FFDB"]
In [40]:
Chord(matrix, names, colors=colors, divide=True, divide_idx=3).show()
Chord Diagram

## Divided (Bipartite) Chord Diagram Labels¶

divide_left_label="", divide_right_label=""

These parameters allow you to label either side of the divided chord diagram.

In [41]:
Chord(matrix, names, colors=colors, divide=True, divide_idx=3,
divide_left_label="Left Side", divide_right_label="Right Side").show()
Chord Diagram

## Colored Diagonals¶

colored_diagonals=True

This sets the visibility of the occurrences (not co-occurrences), i.e. the representation of the diagonal of the matrix.

In [42]:
names=['one','two','three','four','five','six']

matrix = [
[19, 5, 6, 4, 7, 4],
[5, 4, 5, 4, 6, 5],
[6, 5, 0, 4, 5, 5],
[4, 4, 4, 0, 5, 5],
[7, 6, 5, 5, 0, 4],
[4, 5, 5, 5, 4, 0],
]

Chord(matrix, names, title="Diagonals coloured").show()
Chord(matrix, names, title="Diagonals not coloured", colored_diagonals=False).show()
Chord Diagram
Chord Diagram

## Equal-sized Sections¶

This makes use of the colored_diagonals feature above. The idea is to determine the max frequency in our plot, and set all the diagonals to that value. Let's assume that is 20 for this example.

In [43]:
names=['one','two','three','four','five','six']

matrix = [
[20, 0, 0, 0, 0, 0],
[0, 20, 0, 0, 0, 0],
[0, 0, 20, 0, 0, 0],
[0, 0, 0, 20, 0, 0],
[0, 0, 0, 0, 20, 0],
[0, 0, 0, 0, 0, 20],
]

Chord(matrix, names, title="Diagonals not coloured", colored_diagonals=False).show()
Chord Diagram

We can see above that this creates a chord diagram with equal-sized segments. All we need to do now is introduce our relationships, and subtract them from the corresponding diagonal value.

In [44]:
matrix = [
[11, 4, 5, 0, 0, 0],
[4, 14, 2, 0, 0, 0],
[5, 2, 13, 0, 0, 0],
[0, 0, 0, 20, 0, 0],
[0, 0, 0, 0, 20, 0],
[0, 0, 0, 0, 0, 20],
]

Chord(matrix, names, title="Diagonals not coloured", colored_diagonals=False).show()
Chord Diagram

In [45]:
matrix = [
[11, 4, 5, 0, 0, 0],
[4, 14, 2, 0, 0, 0],
[5, 2, 13, 0, 0, 0],
[0, 0, 0, 20, 0, 0],
[0, 0, 0, 0, 20, 0],
[0, 0, 0, 0, 0, 20],
]

Chord(matrix, names, title="Diagonals not coloured", colored_diagonals=False, padding=0.2).show()
Chord Diagram

## Mix and Match¶

In [46]:
matrix = [
[0, 5, 6, 4, 7, 4],
[5, 0, 5, 4, 6, 5],
[6, 5, 0, 4, 5, 5],
[4, 4, 4, 0, 5, 5],
[7, 6, 5, 5, 0, 4],
[4, 5, 5, 5, 4, 0],
]

names = ["Action", "Adventure", "Comedy", "Drama", "Fantasy", "Thriller"]
In [47]:
Chord(matrix, names, padding=0.5, reverse_gradients=True, colors="d3.schemeAccent",
curved_labels=True, label_color="#777777", font_size_large="30px",
inner_radius_scale=0.45, outer_radius_scale=1.4, arc_numbers=True).show()

1. Tintarev, N., Rostami, S., & Smyth, B. (2018, April). Knowing the unknown: visualising consumption blind-spots in recommender systems. In Proceedings of the 33rd Annual ACM Symposium on Applied Computing (pp. 1396-1399).

Support this work

You can access this notebook and more by getting the e-book, Data is Beautiful.

## Data is Beautiful

A practical book on data visualisation that shows you how to create static and interactive visualisations that are engaging and beautiful.