Jozsef Meszaros · Follow
Published in · 5 min read · May 7, 2020
--
Greetings! Unless you are familiar with the “fun” operations in MATLAB, you may want to begin by perusing my earlier posts, starting from Day 1.
Often, in academia, as you get closer to publishing or presenting your research, you will need to enhance your figures so that they are clear and crisp. Doing this programatically at the beginning will save you *so* *many* *headaches*.
Here’s what I did in grad school: I made figures that looked okay enough for lab meetings or showing to my advisor, but when it came to making them the right size, shape, color for accessibility, adding or emphasizing certain features for the reader, and so on — I went into Illustrator or Inkscape and started fiddling. These tools have their place (mainly laying out figures), but going through each figure and making adjustments is a huge time sink. And God forbid you have to remake the figures with new or additional data (you will).
The reason we do this is because sometimes our color schemes don’t match with a collaborator’s, or because MATLAB doesn’t give us a straightforward way to set the colors of certain objects.
The worst offender, by far, is the boxplot function. There is no straightforward way to:
(That said, if you are interested in packages that take care of a lot of this for you, I highly recommend Gramm by @NeuroPierre)
But for our purposes here, we will use these unfortunate limitations as an opportunity to learn:
- How to use findobj to search for and select objects in our graphing axes using ‘Type’ and ‘Tag’
- How to control those objects using arrayfun
- How to overlay a scatterplot with ‘Jitter’ based on the information in our dataset
Let’s dive in.
As usual, create a fake dataset:
rng(5)data = [ normrnd(1,.25,100,1); normrnd(2,.1,100,1); ];
animal_id = [ randi(5,100,1); 5+randi(5,100,1) ];mytable = table( data, animal_id, ...
'VariableNames',{'Data','Animal_id'});
We can imagine it consists of 100 data points distributed across one group of test subjects (identified as 1 through 5), and another 100 data points distributed across a second group with a higher mean (identified as 6 through 10). [For neuro people, maybe two groups of mice (1–5) and (6–10), and the data is the average firing rate of neurons from each mouse.]
Next, we’ll generate our boxplot as usual.
figure('color','w');
ax = axes('NextPlot','add','FontSize',16,'TickDir','out');boxplot( mytable.Data, mytable.Animal_id, 'Parent', ax );
You’ve created boxes, but where are they? We can get anything from the figure or its axes by simply using the findobj function. Try it in your command window.
findobj(ax)
You’ll see something like:
All well and good, and seems ripe for arrayfun. But how can we specify the objects we want to modify?
Turns out you can pass a ‘Type’ parameter and only pull out things of the ‘Type’ that is ‘Line’. Great way to make all the lines uniform. Let’s do it here.
all_lines = findobj(ax,'Type','Line');arrayfun( @(x) set(x,'LineStyle','-','Color','k','LineWidth',1), all_lines )
Just to review: You are iterating over the all_lines array, and for each element in that array, you are setting the property. No for loop, no i’s to index, no dummy variables. Just a simple arrayfun!
Already the plot is looking better.
But what about the boxes?
There’s a parameter for that, too. It’s ‘Tag’. Remember this for later when you want to modify other graphic objects that have Tags! *Hint: They all have tags.*
myboxes = findobj(ax,'Tag','Box')arrayfun( @(box) patch( box.XData, box.YData, 'm', 'FaceAlpha', 0.5), myboxes(1:5) )
We’ve basically placed a magenta patch over boxes 1 through 5 (but you could have chosen any subset of 1 through 10, our animal_id).
[Quirk: The last five boxes plotted are actually 1:5 in the myboxes array!]
You can do all kinds of things with patch, and I’d recommend you check out the documentation for it if you haven’t already.
The other cool thing: Instantly delete
You don’t like the way those outliers are plotted in boxplot? (I don’t.)
Just delete them. Easy.
outliers = findobj( 'Tag', 'Outliers' )
delete( outliers )
This will eliminate all the outliers — of course you can use arrayfun here, also, if you wanted to selectively single out certain outliers and annotate them or emphasize them.
Let’s add the data points, and match the color scheme.
We’ll make the second group of test subjects (6–10) magenta to match our boxes. To do this, we’ll do a little boolean indexing of our mytable variable. Try the following:
mytable.Animal_id(mytable.Animal_id>5)
This will produce a “mini” table consisting only of those subjects with Group > 5. Let’s just plot the contents of this table as a scatter on top of our boxplots as so:
scatter( mytable.Animal_id(mytable.Animal_id>5), mytable.Data(mytable.Animal_id>5) , 64, 'Jitter', 'on', 'JitterAmount', 0.1, 'MarkerEdgeColor','k', 'MarkerFaceColor', 'm', 'MarkerFaceAlpha', 0.5 )
[Note: We set the size of the dots to 64 (the third argument for scatter).]
By using the undocumented ‘Jitter’ and ‘JitterAmount’ properties, you can give the data points in the scatter a nice jittered look. Also look at how we are indexing the table in order to place the scatter points over the second group.
We can do the same for the first group of boxes.
scatter( mytable.Animal_id(mytable.Animal_id<=5), mytable.Data(mytable.Animal_id<=5) , 64, 'Jitter', 'on', 'JitterAmount', 0.1, 'MarkerEdgeColor','k', 'MarkerFaceColor', 'w', 'MarkerFaceAlpha', 0.5 )
The entire code for generating the figure is below.
It’s very paltry and hopefully easy to understand! But more importantly, it should be educational and not just practical.
Stay tuned for more tips to make your MATLAB code succinct and flexible!