joyPlot documentation

The joyPlot function plots your data in a ridgeline representation, just like in the cover of Joy Divisions' Unknown Pleasures (and in many other newspapers, journals, etc.). The function is very simple and only uses the MATLAB® built-in functions fill and plot. I am actually amazed that this wasn't programmed before, but there you go.







[hf,hl] = joyPlot(_)

[hs,hf,hl] = joyPlot(_)

[hs,hf,hl,hvl] = joyPlot(_)


joyPlot(data,x,offset) Plots the information in the m by n matrix data, where n is the number of datasets and m is the sampling. x is a vector containing the $x$-coordinates of data. offset is the relative vertical distance between datasets. By default, the first row is plotted at the top and the last one at the bottom.

joyPlot(data,x,offset,overlapMethod) If overlapMethod is set to 'variable', offset is the relative overlap in percent between datasets.

joyPlot(data,x,offset,overlapMethod,reverse) If reverse is set to 'true', the first row of data will be plotted at the bottom and the last at the bottom.

joyPlot(_,Name,Value) Specifies patch and line properties using one or more 'Name,Value' pairs. For a list see Properties below.

[hf,hl] = joyPlot(_) Returns the patch and line handles.

[hs,hf,hl] = joyPlot(_) If the stroke is requested, its handle can be returned as well.

[hs,hf,hl,hvl] = joyPlot(_) If additional vertical lines are plotted, their handles can be returned too.


Joy Division's Unknown Pleasures album cover by Peter Saville

You can find online a LOT of information about this, so here is a link if you want to read the back story. I found the dataset (or at least a similar one) online. More details here and here .

% Save the data from the web
filename = websave('pulsar.csv',['',...
% Import it into MATLAB(R)
data = readmatrix(filename);
x = linspace(0,93,size(data,2));
% Create the figure and show the magic
set(gca,'Visible','off', 'box','off','XTick',[],'YTick',[])

Add some customization

Don't get me wrong, I don't think that this piece of art needs any more color, detail or anything. But for the sake of showing off the algorithm let's add some options.

% Add face colors as a function of the mean value of each dataset
set(gca,'Visible','off', 'box','off','XTick',[],'YTick',[])
% Add a colorbar to show the propertiy value

One last example with this data set: change the line color and add a stroke. Why anyone would do something like this is beyond me, though.

set(gca,'Visible','off', 'box','off','XTick',[],'YTick',[])

Plot some distributions

Let's face it, we are not goint to plot interesting things like that pulsar. Let's go with some simple distributions. I will use this example to show how to reverse the data representation and use variable offset of the datasets.

% Create the datasets from normal distributions
% Number of datasets
n = 10;
% Sampling
N = 100;
% Min and max values in x
xmin = 0;
xmax = 18;
x = linspace(xmin,xmax,N);
% Allocate a matrix to store the datasets and medians,
data = zeros(N,n);
medians = zeros(1,n);
% Create the distributions and the data with changing shape and scale.
% Save the median for later use
distName = 'gamma';
a = linspace(2,7,n);
b = linspace(0.5,1.5,n);
for ii = 1:n
    dist = makedist(distName,'a',a(ii),'b',b(ii));
    data(:,ii) = pdf(dist,x);
    medians(ii) = dist.median;
% Set overlapMethod to 'variable' and reverse to 'true'.
% Some axes settings
set(gca,'Color',[0.93 0.93 0.93])

Change the color of the stroke as a function of the height

This is achieved with the stroke of the diagram and therefore the line has to be hidden. This is the case because the stroke is created with a patch. See more details in the documentation. The 'FaceColor' value has to be set to 'interp'.

% For more clarity, 'LineColor' was set to 'none'
% Some axes settings
set(gca,'Color',[0.93 0.93 0.93])
% Change the colormap, you know, for fun.

Other useful combinations

If the overall shape of a distribution is important but its maximum value isn't, normalizing the data is the way to go. We will use the same dataset as before, but we will normalize it.

% Normalize the data
dataN = normalize(data,1,'range');
% Plot with the position as color
% Some axes settings
set(gca,'Color',[0.93 0.93 0.93])
% Change the colormap, you know, for fun.

Other possibility is to change the y-axis labels

% Create a char array with alphabet
alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
% Formatting
ylbls = sprintfc('Data %c',alph(1:n));
% Apply

Modify plots after creation

We will also add modal indicators. For the gamma distribution the mode is computed like this: $M = (a-1)*b$

% Compute the modes
M = (a-1).*b;
% Insert them in the joyPlot and return the handles of all objects
% By defining the offset as a negative number with overlapMethod
% 'variable', the plots now are apart.
[hf,hl,hvl] = joyPlot(dataN,x,-0.2,'variable',true,'FaceColor',M,'VLines',M);
% Change the colormap
% Now change the vertical line style
% And the line color
% And the face alpha
% And you could keep going with all possible patch and line methods.

Use everything at the same time

Why not? In the following example we will be showing 3 different properties of the curves simultaneously: the median, the scale and the local density value.

% Note that I removed the handle to the line because I set LineColor to
% 'none'.
[hs,hf,hvl] = joyPlot(data,x,0.3,'variable',true,'FaceColor',b,...
cbar = colorbar;

Notice how the lines do not change colors with the height? That is because we are using the same colormap for both the face and the edge. In MATLAB® it's impossible to use two maps for an axis, so we have to go with a workaround. Find more information here.

% Split the colormap
% Get the CData of the strokes
sCData = cell2mat(get(hs,'CData')');
% Change the values of the stroke CData
sCDataN = reshape(normalize(sCData(:),'range'),size(sCData));
% Set the new CData in the handle
% Get the CData of the faces
fCData = cell2mat(get(hf,'CData'));
% Change the values of the faces CData. The 1e-4 value is there to assure
% that the two datasets do not overlap.
fCDataN = normalize(fCData,'range') + 1 + 1e-4;
% Set the new CData in the handle
% Set the axis of the colorbar
caxis([min(sCDataN(:)) max(fCDataN(:))])
% Change the labels
slabels = num2cell(linspace(min(sCData(:)),max(sCData(:)),6));
flabels = num2cell(linspace(min(fCData(:)),max(fCData(:)),6));
cbar.TickLabels = [slabels(1:end-1),'-',flabels(2:end)];

Name-Value Pair Arguments

Specify optional comma-separated pairs of Name,Value arguments. Name is the argument name and Value is the corresponding value. Name must appear inside quotes. You can specify several name and value pair arguments in any order as Name1,Value1,...,NameN,ValueN.

- 'FaceColor': works just like the color in the patch function. It additionally accepts the input 'position', which colors the faces according to the position in the y-axis.

- 'FaceAlpha': works just like 'FaceAlpha' in the function patch.

- 'LineColor': works just like the color of function plot.

- 'LineWidth': works just like 'LineWidth' in the function plot.

- 'StrokeColor': adds a stroke to each dataset with the specified color. Here, the color works just like in the funciton patch.

- 'StrokeWidth': adds a stroke to each dataset with the specified width. Again, this works like in the function patch.

- 'VLines': adds vertical lines in each dataset corresponding to the x-coordinates provided. This is useful to plot median, mean or mode values for example.

- 'VLinesColor': works just like the color of function plot.

- 'VLinesWidth': works just like 'LineWidth' in the function plot.

See also

plot, patch, fill


Programmed by Santiago M. Benito at the Chair of Materials Technology of the Ruhr-Universität Bochum.