Data Analysis with Rust Notebooks

A practical book on Data Analysis with Rust Notebooks that teaches you the concepts and how they’re implemented in practice.

Get the book

Getting Started with Chord PRO and Rust

Preamble

In [2]:
:dep chord = {Version = "0.1.6"}
use chord::{Chord, Plot};

Note

This introduction to ChordPRO was quickly put together to enable users to get started. You can see the most up-to-date API documentation at https://api.shahin.dev/docs.

Introduction

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

Click here to get lifetime access to the full-featured chord visualization API, producing beautiful interactive visualizations, e.g. those featured on the front page of Reddit.

chord pro

  • Produce beautiful interactive Chord diagrams.
  • Customize colours and font-sizes.
  • Access Divided mode, enabling two sides to your diagram.
  • Symmetric and Asymmetric modes,
  • Add images and text on hover,
  • Access finer-customisations including HTML injection.
  • Allows commercial use without open source requirement.
  • Currently supports Python, JavaScript, and Rust, with many more to come (accepting requests).

chord pro

The Chord Crate

I wasn't able to find any Rust crates for plotting chord diagrams, so I ported my own from Python to Rust.

You can get the package either from crates.io or from the GitHub repository. With your processed data, you should be able to plot something beautiful with just a single line, Chord{ matrix : matrix, names : names, .. Chord::default() }.show()

License

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

Chord {
    user: String::from("enter username here"),
    key: String::from("enter license key here"),
    matrix: matrix.clone(),
    names: names.clone(),
    wrap_labels: true,
    ..Chord::default()
}
.show();

Chord Diagrams with the Rich Hover Box

The Dataset

The focus for this section will be the demonstration of the chord package. To keep it simple, we will use synthetic data that illustrates the co-occurrences between movie genres within the same movie.

In [30]:
let matrix: Vec<Vec<f64>> = vec![
    vec![0., 5., 6., 4., 7., 4.],
    vec![5., 0., 5., 4., 6., 5.],
    vec![6., 5., 0., 4., 5., 5.],
    vec![4., 4., 4., 0., 5., 5.],
    vec![7., 6., 5., 5., 0., 4.],
    vec![4., 5., 5., 5., 4., 0.],
];

let names: Vec<String> = vec![
    "Action",
    "Adventure",
    "Comedy",
    "Drama",
    "Fantasy",
    "Thriller",
]
.into_iter()
.map(String::from)
.collect();

In 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.

In [31]:
let details : Vec<Vec<Vec<String>>> = vec![
    vec![vec![], vec!["Movie 1".to_string(),"Movie 2".to_string()], vec!["Movie 3".to_string(),"Movie 4".to_string(),"Movie 5".to_string()], vec!["Movie 6".to_string(),"Movie 7".to_string()], vec!["Movie 8".to_string(),"Movie 9".to_string(),"Movie 10".to_string(),"Movie 11".to_string()], vec!["Movie 12".to_string()]],
    vec![vec!["Movie 13".to_string(),"Movie 14".to_string()], vec![], vec!["Movie 15".to_string(),"Movie 16".to_string()], vec!["Movie 17".to_string()], vec!["Movie 18".to_string(),"Movie 19".to_string(),"Movie 20".to_string()], vec!["Movie 21".to_string(),"Movie 22".to_string()]],
    vec![vec!["Movie 23".to_string(),"Movie 24".to_string(),"Movie 25".to_string()], vec!["Movie 26".to_string(),"Movie 27".to_string()], vec![], vec!["Movie 28".to_string()], vec!["Movie 29".to_string(),"Movie 30".to_string()], vec!["Movie 31".to_string(),"Movie 32".to_string()]],
    vec![vec!["Movie 33".to_string()], vec!["Movie 34".to_string()], vec!["Movie 35".to_string()], vec![], vec!["Movie 36".to_string(),"Movie 37".to_string()], vec!["Movie 38".to_string(),"Movie 39".to_string()]],
    vec![vec!["Movie 40".to_string(),"Movie 41".to_string(),"Movie 42".to_string(),"Movie 43".to_string()], vec!["Movie 44".to_string(),"Movie 45".to_string(),"Movie 46".to_string()], vec!["Movie 47".to_string(),"Movie 48".to_string()], vec!["Movie 49".to_string(),"Movie 50".to_string()], vec![], vec!["Movie 51".to_string()]],
    vec![vec!["Movie 52".to_string()], vec!["Movie 53".to_string(),"Movie 54".to_string()], vec!["Movie 55".to_string(),"Movie 56".to_string()], vec!["Movie 57".to_string(),"Movie 58".to_string()], vec!["Movie 59".to_string()], vec![]]
];
In [32]:
let details_thumbs : Vec<Vec<Vec<String>>> = vec![
    vec![vec![], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string()]],
    vec![vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec![], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()]],
    vec![vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec![], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()]],
    vec![vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec![], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()]],
    vec![vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec![], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string()]],
    vec![vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string(),"https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec!["https://shahinrostami.com/images/stami-labs/lablet.png".to_string()], vec![]],
];

Let's see what the Chord() produces when we invoke the show() method.

In [33]:
Chord {
    user: String::from("enter username here"),
    key: String::from("enter license key here"),
    matrix: matrix.clone(),
    names: names.clone(),
    details: details,
    details_thumbs: details_thumbs,
    ..Chord::default()
}
.show();
Out[33]:
Chord Diagram

Chord Diagrams with Two Sides

In [34]:
let matrix: Vec<Vec<f64>> = vec![
    vec![0.0, 0.0, 0.0, 1.0, 4.0, 1.0],
    vec![0.0, 0.0, 0.0, 1.0, 3.0, 2.0],
    vec![0.0, 0.0, 0.0, 1.0, 2.0, 2.0],
    vec![1.0, 1.0, 1.0, 0.0, 0.0, 0.0],
    vec![4.0, 3.0, 2.0, 0.0, 0.0, 0.0],
    vec![1.0, 2.0, 2.0, 0.0, 0.0, 0.0],
];

let names: Vec<String> = vec!["A", "B", "C", "1", "2", "3"]
.into_iter()
.map(String::from)
.collect();

let colors: Vec<String> = vec!["#7400B8", "#5E60CE", "#5684D6", "#56CFE1", "#64DFDF", "#80FFDB"]
.into_iter()
.map(String::from)
.collect();

Chord {
    user: String::from("enter username here"),
    key: String::from("enter license key here"),
    matrix: matrix.clone(),
    names: names.clone(),
    colors: colors,
    divide: true,
    divide_idx: 3,
    ..Chord::default()
}.show();

Conclusion

In this section, we've introduced major PRO features of the chord package. We used the crate and some synthetic data to demonstrate several chord diagram visualisations with different configurations. The chord Python crate is available for free from crates.io or from the GitHub repository.


  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 on Data Analysis with Rust Notebooks.