Radial convergence diagram (aka chord diagram) for sensitivity analysis results and other inter-relationships between data

TLDR; Python script for radial convergence plots that can be found here.

You might have encountered this type of graph before, they’re usually used to present relationships between different entities/parameters/factors and they typically look like this:

From https://datavizcatalogue.com/methods/non_ribbon_chord_diagram.html

In the context of our work, I have seen them used to present sensitivity analysis results, where we are interested in both the individual significance of a model parameter, but also the extent of its interaction with others. For example, in Butler et al. (2014) they were used to present First, Second, and Total order parameter sensitivities as produced by a Sobol’ Sensitivity Analysis.

From Butler et al. (2014)

I set out to write a Python script to replicate them. Calvin Whealton has written a similar script in R, and the same functionality also exists within Rhodium. I just wanted something with a bit more flexibility, so I wrote this script that produces two types of these graphs, one with straight lines and one with curved (which are prettier IMO). The script takes dictionary items as inputs, either directly from SALib and Rhodium (if you are using it to display Sobol results), or by importing them (to display anything else). You’ll need one package to get this to run: NetworkX. It facilitates the organization of the nodes in a circle and it’s generally a very stable and useful package to have.

Graph with straight lines
Graph with curved lines

I made these graphs to display results the results of a Sobol analysis I performed on the model parameters of a system I am studying (a, b, c, d, h, K, m, sigmax, and sigmay). The node size indicates the first order index (S1) per parameter, the node border thickness indicates the total order index (ST) per parameter, and the thickness of the line between two nodes indicates the secord order index (S2). The colors, thicknesses, and sizes can be easily changed to fit your needs. The script for these can be found here, and I will briefly discuss what it does below.

After loading the necessary packages (networkx, numpy, itertools, and matplotlib) and data, there is some setting parameters that can be adapted for the figure generation. First, we can define a significance value for the indices (here set to 0.01). To keep all values just set it to 0. Then we have some stylistic variables that basically define the thicknesses and sizes for the lines and nodes. They can be changed to get the look of the graph to your liking.

# Set min index value, for the effects to be considered significant
index_significance_value = 0.01
node_size_min = 15 # Max and min node size
node_size_max = 30
border_size_min = 1 # Max and min node border thickness
border_size_max = 8
edge_width_min = 1 # Max and min edge thickness
edge_width_max = 10
edge_distance_min = 0.1 # Max and min distance of the edge from the center of the circle
edge_distance_max = 0.6 # Only applicable to the curved edges

The rest of the code should just do the work for you. It basically does the following:

  • Define basic variables and functions that help draw circles and curves, get angles and distances between points
  • Set up graph with all parameters as nodes and draw all second order (S2) indices as lines (edges in the network) connecting the nodes. For every S2 index, we need a Source parameter, a Target parameter, and the Weight of the line, given by the S2 index itself. If you’re using this script for other data, different information can fit into the line thickness, or they could all be the same.
  • Draw nodes and lines in a circular shape and adjust node sizes, borders, and line thicknesses to show the relative importance/weight. Also, annotate text labels on each node and adjust their location accordingly. This produces the graph with the straight lines.
  • For the graph with the curved lines, define function that will generate the x and y coordinates for them, and then plot using matplotlib.

I would like to mention this script by Enrico Ubaldi, based on which I developed mine.

Embedding figure text into a Latex document

Often times we have to create plots and schematic drawings for our publications. These figures are then included in the final document either as bitmaps (png, jpeg, bmp) or as vectorized images (ps, eps, pdf). Some inconveniences that arise due to this process and are noticed in the final document are:

  • Loss of image quality due to resizing the figure (bitmaps only)
  • Different font type and size from the rest of the text
  • Limited resizing possibility due to text readability
  • No straight-forward method to add equations to the figure

If the document is being created in LaTeX, it is possible to overcome all these inconveniences by exporting your figure into either svg or postscript formats and converting it into pdf+Latex format with Inkscape. This format allows the LaTeX engine to understand and treat figure text as any other text in the document and the lines and curves as a vectorized image.

EXPORTING FIGURE

The process for creating of a PDF+LaTeX figure is described below:

1 – Create your figure and save it in either svg or postscript format. Inkscape, Matlab, GNUPlot, and Python are examples of software that can export at least one of these formats. If your figure has any equations, remember to type them in LaTeX format in the figure.

2 – Open your figure with Inkscape, edit it as you see necessary (figure may need to be ungrouped), and save it.

3.0 – If you are comfortable with using a terminal and the figure does not need editing, open a terminal pointing to the folder where the figure is and type the following the command (no $). If this works, you can skip steps 3 and 4 and go straight to step 5.

$ inkscape fig1.svg --export-pdf fig1.pdf --export-latex

3 – Click on File -> Save As…, select “Portable Document Format (*.pdf)” as the file format, and click on Save.

ss1

4 – On the Portable Document Format window that will open, check the option “PDF+LaTeX: Omit text in PDF, and create LaTeX file” and click on OK.

ss2

Inkscape will then export two files, both with the same name but one with pdf and the other with pdf_tex extension. The pdf file contains all the drawing, while the pdf_tex contains all the text of the figure and calls the pdf file.

5 – On your latex document, include package graphicx with the command \usepackage{graphicx}.

6 – To include the figure in your document, use \input{your_figure.pdf_tex}. Do not use the conventional \includegraphics command otherwise you will end up with an error or with a figure with no text. If you want to scale the figure, type \def\svgwidth{240bp} (240 is the size of your figure in pixels) in the line before the \input command. Do not use the conventional [scale=0.5] command, which would cause an error. Some instructions are available at the first lines of the pdf_tex file, which can be opened with a regular text editor such as notepad.

Below is a comparison of how the same figure would look like in the document if exported in PDF+LaTeX and png formats. It can be seen that the figure created following the procedure above looks smoother and its text style matches that of the paragraphs above and below, which is more pleasant to the eyes. Also, the text can be marked and searched with any pdf viewer. However, the user should be aware that, since text font size is not affected by the scaling of the figure, some text may end up bigger than boxes that are supposed to contain it, as well as too close or to far from lines and curves. The former can be clearly seen in the figure below. This, however, can be easily fixed with software such as Inkscape and/or with the editing tips described in the following section.

ss3

TIPS FOR TEXT MANIPULATION AFTER FIGURE IS EXPORTED

If you noticed a typo of a poorly positioned text in the figure after the figure has been exported and inserted in your document, there is a easier way of fixing it other than exporting the figure again. If you open the pdf_tex file (your_figure.pdf_tex) with a text editor such as notepad, you can change any text and its position by changing the parameters of the \put commands inside the \begin{picture}\end{picture} LaTeX environment.

For example, it would be better if the value 1 in the y and x axes of the figures above would show as 1.0, so that its precision is consistent with that of the other values. The same applies to 2 vs. 2.0 in the x axis. This can be fixed by opening file fig1.pdf_tex and replacing lines:

\put(0.106,0.76466667){\makebox(0,0)[rb]{\smash{1}}}%
\put(0.53916667,0.0585){\makebox(0,0)[b]{\smash{1}}}%
\put(0.95833333,0.0585){\makebox(0,0)[b]{\smash{2}}}%

by:

\put(0.106,0.76466667){\makebox(0,0)[rb]{\smash{1.0}}}%
\put(0.53916667,0.0585){\makebox(0,0)[b]{\smash{1.0}}}%
\put(0.95833333,0.0585){\makebox(0,0)[b]{\smash{2.0}}}%

Also, one may think that the labels of both axes are too close to the axes. This can be fixed by replacing lines:

\put(0.02933333,0.434){\rotatebox{90}{\makebox(0,0)[b]{\smash{$x\cdot e^{-x+1}$}}}}%
\put(0.539,0.0135){\makebox(0,0)[b]{\smash{x}}}%

by:

\put(0.0,0.434){\rotatebox{90}{\makebox(0,0)[b]{\smash{$x\cdot e^{-x+1}$}}}}%
\put(0.0,0.0135){\makebox(0,0)[b]{\smash{x}}}%

With the modifications described above and resizing the legend box with Inkscape, the figure now would look like this:

ss4

Don’t forget to explore all the editing features of inkscape. If you export a figure form GNUPlot or Matlab and ungroup it with Inkscape into small pieces, Inkscape would give you freedom to rearrange and fine tune your plot.

Scientific figures in Illustrator

Once you have a figure sequence almost ready to publish in a journal, it’s time to make your figures look good. This may sound like a vain exercise, but if you consider that the journal article will be around for a long time, it’s worth it. Publication-quality scientific figures are typically in vector format (SVG, PDF, or EPS files) rather than raster format (JPEG, PNG, TIFF, and others) which may become pixelated if resized. You can read this discussion of raster vs. vector formats if you’re interested, or just take my word for it that vector is what you want.

Programs capable of editing vector graphics include Adobe Illustrator (paid) and Inkscape (free). This post will be about Illustrator, but keep in mind that Inkscape offers much of the same functionality. You can not edit vector images with photo editing programs like Photoshop or GIMP, nor can you make publishable vector images with MS Office programs like Excel or Powerpoint. This post will take a figure created in Matlab and clean it up into something that will look nice in a publication using Illustrator.

If you run the following Matlab code …

x = 0:0.1:5;

y(1,:) = exp(-1*x);
y(2,:) = exp(-0.5*x);
y(3,:) = exp(-1.5*x);

h = plot(x,y);
legend(h, {'Thing 1', 'Thing 2', 'Thing 3'});
grid on;
xlabel('Time (hours)');
ylabel('Amount of thing');
title('My plot title');

… it will give you this figure:

default matlab figure style

Default figure style. Bleh.

You’ve seen this before: the text is too small, the grid lines are noisy, the colors are uninspiring, the plot lines are too thin … and so on. Some of those issues you can fix from inside Matlab, which is a good idea if you plan to regenerate your plot several times. (An example of doing this is available here in the Matlab Plot Gallery). But here we’re going to do all the work in Illustrator instead (which as you may have gathered is not a very “repeatable” process, so only do it once you agree with coauthors on the general layout of the figure). If you’re following along at home, save your Matlab figure in .eps format. Unfortunately Matlab does not have an option to save in SVG format as of this post, which is typically the option of choice in Python or R.

Go find the .eps figure you just created, and open it with Illustrator. If your file extensions aren’t associated with Illustrator, you may need to right-click and select Open With / Adobe Illustrator. When opening the file, you may see some warnings about missing fonts, just click OK and proceed. Note that we are not “inserting” the file into an existing Illustrator document—we are opening the file itself. You should be greeted by our lovely figure, inside of what may be an overwhelming interface the first time you see it. Let’s break down the toolbar on the left-hand side to start with, and we’ll cover other options as we go.

Illustrator left toolbar

These annotations were professionally done.

This is only the top of the toolbar, but you’ll be using these “tools” (cursor types) probably 95% of the time. The select cursor is the default, and when in doubt you should return to it. The text, line, and shape options are for adding new things to your drawing, which is not so different from, say, Powerpoint. Stay on “Select” for now. Let’s get cleaning.

Step 0: Ungroup the main parts of the figure

When Matlab exports EPS files, it tends to group different parts of the figure together. This can be somewhat unpredictable and makes editing difficult. You’ll notice if you left-click any part of the figure, it will select everything. So, one of the first things you’ll want to do when editing almost any figure is to “ungroup”, which you can do by right-clicking any part of the figure and selecting the ungroup option:

Illustrator ungrouping

How to ungroup the elements of the figure (everything is grouped by default).

Now you should be able to select individual parts of the figure. Matlab may have saved a big white rectangle in the background of your figure (you can see it selected around the border of the above image), which you should feel free to delete. Illustrator’s white “Artboard” will serve as our background, and you can edit the artboard size by pressing Shift+O.

Step 1: Replace all text

This may sound harsh, but hear me out. What we really want to do is just resize the text, or maybe change the font type, nothing major. But what usually happens here is that the EPS file splits text objects into separate boxes, especially when a decimal point is involved. Which means if you resize, you get the following:

Illustrator text resize

The text elements are split into two, so resizing won’t work. Need to start from scratch.

This is not an indictment of Matlab specifically—in fact, when Matplotlib (Python) exports SVGs, it usually saves text as vector paths, which aren’t fonts at all! Rather than trying to repair this strangeness, just replace all of the text yourself. Choose a clean sans-serif font, unless you want to use Computer Modern serif for equations. I like Gill Sans for figures (Gill Sans MT on Windows), but your mileage may vary. My rule of thumb for text sizing is: Title > Axis labels = Legend > Tick labels, something like this:

Illustrator fonts text sizes

Same figure with fonts and text sizes fixed.

That’s already so much better, just by improving the text readability. It looks like we actually spent some time on it, instead of just copypasting the raw Matlab output. You can insert text using the text cursor (shown on the toolbar figure above), and edit its properties from the Window/Type/Character window, pictured below, which you’ll usually want to keep visible.

Illustrator character window

The Type/Character window is where you change font types, sizes, and tracking.

A quick digression: the other window you’ll usually want to keep open is the Align window, which looks like this:

Illustrator align window

The align window is a must for lining up multiple elements. Don’t try to do it by hand.

Those little button symbols are actually pretty intuitive. If you select two or more objects, then press one of these “alignment” buttons, it will either left-, center-, or right-align them horizontally (the left three buttons) or vertically (the right three buttons). This comes in handy when you’re trying to line up tick labels that you’ve edited manually, or combining multiple EPS files as subplots in a larger figure file and you want to make sure they’re aligned properly. Even if you don’t learn how to do this right now, just remember that alignment shouldn’t be done manually.

Ok, digression over. When resizing text, pay particular attention to the aspect ratio (the width:height ratio of the object). Never ever resize these out of proportion. Either use the text size in the character window, shown above (recommended), or Shift+Drag when you resize, which will preserve the aspect ratio.

Don't change the aspect ratio

If you take one thing away from this post …

Step 2: Make grid lines solid and lighter

Right now, the grid lines are noisy and distracting—let’s clean them up. Fortunately the grid lines should all be grouped together, so we don’t need to do any fancy selection to get them all selected at the same time. Just left-click on any one of the grid lines and you should see them all highlighted. Then, on the right-hand toolbar, go to the “Stroke” options and deselect the “Dashed Line” checkbox:

Illustrator line weight

Changing line weight in Illustrator.

(I’m not doing the snapshots in parallel with the actual saved figure versions, so the font formatting isn’t shown in this snapshot). This should turn the grid lines into solid lines. But wait, they’re solid black! This is even more distracting than before! Have no fear, just go to the “Color” options on the right-hand toolbar and knock it down to maybe 30% gray or so:

Illustrator stroke color

Changing stroke color in Illustrator.

While we’re at it, let’s also bump up the thickness of the plot lines. To select the plot lines, you will need to Ctrl+click, since they are grouped (somehow, bizarrely) with the plot itself. You can Ctrl+Shift+click to select the other lines after that, so that you have all three selected at once. Then go back to the “Stroke” options on the right-hand toolbar (pictured in one of the above images) and increase the line weight to 2px. You should now have a figure that looks something like this:

Example plot after some improvements

We’re getting there … thicker lines, thinner grid, and nicer fonts. Only a few steps to go.

This is already a terrific improvement over the original version. I would be fine with publishing it at this point. But, there are a few other things we can do to make it even better.

Step 3: Care about Colors

As we saw in the very first image, Matlab’s default colors are red, green, and blue. This is fine, but you’ll find if you move beyond the defaults, people appreciate the extra effort. Illustrator makes the colors a little less grating when it imports the EPS file, because it converts them to CMYK format and does some magic behind the scenes that I don’t fully understand. But let’s imagine the case where the three lines represent something changing along a continuum (which they are—the exponential decay coefficient, to be exact). In this case, we might want their colors to also lie along a continuous spectrum.

I know of no better place to find discrete color palettes than Colorbrewer (http://colorbrewer2.org/). I am certainly not the first person to sing its praises, so you can go read about it elsewhere. Basically you choose whether your data are “Sequential”, “Diverging”, or “Qualitative”, give it the number of colors you want, and it generates a well-spaced set of colors for you to use. The case I just described would fall into the “Sequential” category, so let’s grab a set of 3 colors (for our three lines) from the single hue blues:

Colorbrewer palettes

Colorbrewer: if you’re not using it, you should be.

You can see in the bottom-right the RGB values for these three colors. You can change this to CMYK or HEX format if you prefer, but I’ll stick to RGBs in this example. Note if I were more responsible, I would have configured the colors of these lines in the Matlab script, so I could regenerate the figure as many times as I needed to. Oh well, we’re doing it in Illustrator now.

We want to change the color of each line, along with its legend entry, to correspond to the three colors that Colorbrewer gave us above. To do this quicker, we’ll use a neat selection trick. First Ctrl+click to select one of the lines. Then go to the menu option Select / Same / Stroke Color to add the line’s legend entry to your selection (see below). Now you can change the color of both of them at the same time!

Illustrator select same stroke color.

Illustrator has an option to select all other elements in the figure that have the same (appearance). In this case we want the same stroke color.

How do we set their color, you ask? Go back to the “Color” options on the right-hand toolbar. The color format might be set to something other than RGB, like CMYK. To change it to RGB, click the small options box in the upper-right corner and select “RGB”:

Illustrator RGB color format

Change the color format to RGB.

Then enter the RGB values from Colorbrewer. Repeat for the other two plot lines, and you’ll end up with something like this:

Illustrator color palette

Same figure as before, but with a “sequential” color palette. Useful if the lines represent some variable changing along a continuum.

Step 4: “Flat” Legend and Outer Box

At this point, I only have a few remaining grievances about this figure. First, the legend is too small. Second, there is a ton of whitespace in the upper right of the figure that is being wasted. Third, the solid black borders around the legend box, and around the plot itself, are distracting attention from the plot lines (which should be the focus, after all). Let’s see what we can do about this.

Select the legend and its components. Since we ungrouped everything at the beginning of this exercise, this will be annoying. Remember you can Shift+Click to select multiple elements at once. To make it easier to edit the legend, just move it outside the plot area for now. (Once you’re more experienced with Illustrator you can use layers to more easily edit “stuff” that’s sitting on top of other “stuff”).

To make the legend bigger (proportionally), it’s fine to select everything and Shift+Drag one of the corners of the bounding box. This will rescale the text proportionally as well. Make sure after you do this that the line thickness in the legend matches the thickness of the plot lines themselves (an important technicality), using the “Stroke” options in the right-hand toolbar.

Things get a bit confusing here because there may actually be two rectangles behind our legend—one defining the black border, and one defining the white background. If this seems to be the case in your figure (it is in mine), delete the black border completely, and then select the white background. Go to the “Color” options on the right-hand toolbar and change from white to a very light gray, maybe around 5% or so:

Illustrator change rectangle fill color

Changing the fill color of a rectangle.

See those two squares in the top-left of the Color options box? Those are the fill and stroke, respectively. You can toggle back and forth between the two by clicking them. The icon with the red line through it means there is “no fill” (or “no stroke”, respectively). The options for “none”, “black”, and “white” are always visible at the bottom because these are so common. Otherwise, you choose your own color. If you wanted something besides grayscale here, you could change the color format like we did before.

Take your enlarged legend and move it back inside the plot box. Here’s mine:

Illustrator flat legend

The “flat” legend at work. It solves our whitespace problem and is also nicer to look at.

Some may call it a fad, but I absolutely love these “flat” legends. Borders around legends are distracting, whereas a borderless light rectangle looks so clean. It can sit on top of the plot grid lines with no problem at all. And, by including the title inside the legend box, we’ve saved a bunch of whitespace at the top of the figure, too. I also rearranged the legend entries to go in the same vertical order as the plot lines—not required, but I think it makes sense here, especially if you pretend they’re called something besides “Thing 2”.

As a final step in our crusade against dark borders, let’s change the outer box to the same line style as the grid lines. For the record, I’m not completely sure I like the outcome of this, but it’s at least worth discussing. Select one of the black tick marks with Ctrl+Click (they are grouped with something else) and then use the Select / Same / Stroke Color to select all of the remaining black lines in the plot. See if you can remember how to change their line width to 0.333px (matching the grid lines), and their color to grayscale 30%. You should end up with something like this:

Example plot after fixing everything

The final result! Send it off to Nature and take a well-deserved break.

The border of the plot doesn’t announce itself anymore, but I consider this a good thing. The focus of the plot should be on the values being plotted, not on the box and grid lines. As I said before, this may be overkill, but now this seems like a polished, easily interpretable figure that I would be happy to see in a journal.

By the way, if you save your figure as a PDF and want to include it in a LaTeX document, it’s easy:

begin{figure}begin{center}
includegraphics[width=1.0columnwidth]{my-figure-filename.pdf}
caption{My Caption.}
end{center}end{figure}

That’s all for this tutorial. Go back and look at the original plot at the top of this post, and then at the final product we just made—what a difference! Don’t despair if it takes you a while to do this, because eventually you’ll learn where all of the options are and you’ll get much faster. Vector graphics are definitely worth learning, partly for clear scientific communication, but also because they just plain look nice.