This is third and final of a series of posts on plotting in MATLAB. This series is focusing on suggestions and considerations to get your plot looking “just right” for your paper or presentation. In the first post, I talked about how to improve the look of curves. In the second post, I talked about fixing up the text, including axis labels and legends. Here, I will talk about using a plot wrapper to automate most of your work. I will also talk about exporting your figure to whatever format you need.
Recap
Where were we? At the end of the previous post, our last version of the plotting function was the following:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
numPlotPoints = 50; | |
x = 1e-2:1e-2:100; | |
% Smooth curves | |
y1 = exp(-x); | |
y2 = 1-exp(-x); | |
% Noisy curves | |
n = length(x); | |
z1 = y1.*(1+0.005*randn(1,n)); | |
z2 = y2.*(1+0.005*randn(1,n)); | |
plotInd = unique(floor(logspace(0, log10(n), numPlotPoints))); | |
hFig = figure; | |
hAxes = axes('Parent',hFig,… | |
'FontSize',12,'XGrid','on', 'YGrid','on', 'Box', 'on',… | |
'TickLabelInterpreter', 'latex'); | |
set(hFig, 'Color', 'w') | |
hold('on'); | |
plot(hAxes, NaN,NaN,'LineStyle', '-', 'Color', [0 0 0],… | |
'LineWidth', 1); | |
plot(hAxes, NaN,NaN,'LineStyle', 'none', 'Color', [0 0 0],… | |
'LineWidth', 1, 'Marker', 'o'); | |
plot(hAxes, x(plotInd),y1(plotInd),'LineStyle', '-', 'Color', [0 0 0],… | |
'LineWidth', 1); | |
plot(hAxes, x(plotInd),y2(plotInd),'LineStyle', '-', 'Color', [0 0 1],… | |
'LineWidth', 1); | |
plot(hAxes, x(plotInd),z1(plotInd),'LineStyle', 'none', 'Color', [0 0.6 0],… | |
'LineWidth', 1, 'Marker', 'o'); | |
plot(hAxes, x(plotInd),z2(plotInd),'LineStyle', 'none', 'Color', [1 0 0],… | |
'LineWidth', 1, 'Marker', 'o'); | |
xlabel('Time [s]', 'interpreter', 'Latex'); | |
ylabel('Exponential Observation', 'interpreter', 'Latex'); | |
legend(hAxes, 'Analytical', 'Simulation') | |
set(hAxes,'XScale','log'); |
Which produces the following figure:
We did a bit more tweaking with the figure to add some annotations, but they’re a bit harder to automate so I won’t discuss them here.
Wrapping it Up
Now, we want to make the plot wrapper. This will be a custom function that will apply our common figure changes and that we can call for any plot we want. I previously wrote about wrapper functions here.
We want as much flexibility as we can so that the wrapper will be useful. The input arguments will be:
- Handle to the existing axes
- Data to plot
- Changes to apply to the wrapper’s default settings
Below is a sample plot wrapper. It has 3 subfunctions to set the default properties for the figure, axes, and curve. 2 other subfunctions are used to change structure and object settings. These last 2 subfunctions use MATLAB’s ability to reference structure fields like they are an array.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function [hFig, hAxes, hCurve] = my_plot_function(hAxes, … | |
xData, yData, myFigProp, myAxesProp, myCurveProp, xStr, yStr) | |
% A plotting wrapper function. Designed to plot one curve per call. | |
% | |
% INPUTS | |
% hAxes – handle to existing axes (set to 0 to create new figure and axes) | |
% xData – x data to plot (set to [] to not plot) | |
% yData – y data to plot (set to [] to not plot) | |
% myFigProp – structure of figure properties to change from defaults. See | |
% subfunction buildFigureStruct for defaults. Ignored if hAxes == 0. Set | |
% to [] to not change any defaults | |
% myAxesProp – structure of axes properties to change from defaults. See | |
% subfunction buildAxesStruct for defaults. Ignored if hAxes == 0. Set | |
% to [] to not change any defaults | |
% myCurveProp – structure of curve properties to change from defaults. See | |
% subfunction buildCurveStruct for defaults. Ignored if xData == [] or | |
% yData == 0. Set to [] to not change any defaults | |
% | |
% OUTPUTS (All optional) | |
% hFig – handle to figure | |
% hAxes – handle to axes. Store to plot more curves later | |
% hCurve – handle to curve | |
% | |
% Created by Adam Noel, 2016-09-16 | |
% Adapted from function accordPlotMaker.m, part of AcCoRD's MATLAB utilities | |
% https://github.com/adamjgnoel/AcCoRD | |
% | |
% Options to expand | |
% – control for type of plot (e.g., plot3, bar, surf) | |
% Create figure and apply properties if it does not exist | |
if hAxes == 0 | |
figProp = buildFigureStruct(myFigProp); | |
axesProp = buildAxesStruct(myAxesProp); | |
% Create Figure | |
hFig = figure; | |
hFig = applyObjChanges(hFig, figProp); | |
% Create Axes | |
hAxes = axes('Parent',hFig); | |
hAxes = applyObjChanges(hAxes, axesProp); | |
hold(hAxes, 'on'); | |
xlabel(xStr, 'interpreter', 'Latex'); | |
ylabel(yStr, 'interpreter', 'Latex'); | |
else | |
hFig = get(hAxes, 'Parent'); | |
end | |
if ~isempty(xData) && ~isempty(yData) | |
% Load curve properties | |
curveProp = buildCurveStruct(myCurveProp); | |
hCurve = plot(hAxes, xData, yData); | |
hCurve = applyObjChanges(hCurve, curveProp); | |
end | |
end | |
% Set default figure properties and apply changes | |
function figProp = buildFigureStruct(myFigProp) | |
figProp.Color = 'w'; | |
figProp = applyStructChanges(figProp, myFigProp); | |
end | |
% Set default axes properties and apply changes | |
function axesProp = buildAxesStruct(myAxesProp) | |
axesProp = struct(… | |
'Box', 'on', … % If on, draw complete box outline along axis limits | |
'FontSize', 12, … | |
'XGrid', 'on', … | |
'YGrid', 'on', … | |
'TickLabelInterpreter', 'latex'); | |
axesProp = applyStructChanges(axesProp, myAxesProp); | |
end | |
% Set default curve properties and apply changes | |
function curveProp = buildCurveStruct(myCurveProp) | |
curveProp = struct(… | |
'LineStyle', '-', … % Line style. Options: '-', '–', ':', '-.', 'none' | |
'LineWidth', 1, … % Line width | |
'Color', 'black', … % Line color | |
'Marker', 'o', … % Marker shape. Options: 'o', '+', '*', '.', 'x', 's', 'd', '^', 'v', '>', '<', 'p', 'h', 'none' | |
'MarkerSize', 6, … % Marker size | |
'MarkerEdgeColor', 'auto', … % Marker edge color. Options: 'auto', 'none', 'RGB triplet', 'color string' | |
'MarkerFaceColor', 'none', … % Marker edge color. Options: 'auto', 'none', 'RGB triplet', 'color string' | |
'DisplayName', ''); % Display string (if legend turned on) | |
curveProp = applyStructChanges(curveProp, myCurveProp); | |
end | |
% Change specified elements of structure | |
function curStruct = applyStructChanges(curStruct, changeStruct) | |
if ~isempty(changeStruct) | |
propFields = fieldnames(changeStruct); | |
numProp = numel(propFields); | |
for j = 1:numProp | |
curStruct.(propFields{j}) = changeStruct.(propFields{j}); | |
end | |
end | |
end | |
% Apply changes to object with handle | |
function h = applyObjChanges(h, changeStruct) | |
if ~isempty(changeStruct) | |
propFields = fieldnames(changeStruct); | |
numProp = numel(propFields); | |
for i = 1:numProp | |
set(h, propFields{i}, changeStruct.(propFields{i})); | |
end | |
end | |
end |
A few comments on this plot wrapper:
- It can be called with empty data to just build the figure and axes without plotting anything
- You don’t need to include any of the figure, axes, or label arguments if you already have the axes handle from a previous call (or elsewhere)
- You can pass your own custom structures for the figure, axes, and curve properties. As long as the structures have fields with the proper naming convention, then you can change (almost) any property this way. Disclaimer: I haven’t seen this work well when properties are also structures.
Now let’s try a simple script to build the figure we have above:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
clear; | |
numPlotPoints = 50; | |
x = 1e-2:1e-2:100; | |
% Smooth curves | |
y1 = exp(-x); | |
y2 = 1-exp(-x); | |
% Noisy curves | |
n = length(x); | |
z1 = y1.*(1+0.005*randn(1,n)); | |
z2 = y2.*(1+0.005*randn(1,n)); | |
plotInd = unique(floor(logspace(0, log10(n), numPlotPoints))); | |
% My axes properties | |
axesProp.XScale = 'log'; | |
hAxes = 0; | |
% Create 'Ghost curves' for legend | |
curveProp.Marker = 'none'; | |
[~, hAxes, ~] = my_plot_function(hAxes, NaN, NaN,[],axesProp,curveProp,… | |
'Time [s]', 'Exponential Observation'); | |
curveProp.Marker = 'o'; | |
curveProp.LineStyle = 'none'; | |
[~, hAxes, ~] = my_plot_function(hAxes, NaN, NaN,[],axesProp,curveProp,… | |
'Time [s]', 'Exponential Observation'); | |
hLegend = legend(hAxes, 'Analytical', 'Simulation'); | |
set(hLegend, 'Interpreter', 'latex'); | |
% Add smooth curves | |
curveProp.Marker = 'none'; | |
curveProp.LineStyle = '-'; | |
[~, hAxes, ~] = my_plot_function(hAxes, x(plotInd),y1(plotInd),[],[],curveProp,… | |
[], []); | |
curveProp.Color = [0 0 1]; | |
[~, hAxes, ~] = my_plot_function(hAxes, x(plotInd),y2(plotInd),[],[],curveProp, [], []); | |
% Add noisy curves | |
curveProp.LineStyle = 'none'; | |
curveProp.Marker = 'o'; | |
curveProp.Color = [0 0.6 0]; | |
[~, hAxes, ~] = my_plot_function(hAxes, x(plotInd),z1(plotInd),[],[],curveProp, [], []); | |
curveProp.Color = [1 0 0]; | |
[~, hAxes, ~] = my_plot_function(hAxes, x(plotInd),z2(plotInd),[],[],curveProp, [], []); |
This script produces the following:

The script using the wrapper is no shorter than the full plotting script above. But, it’s easier to copy and modify. If you make a large number of figures, then having a good wrapper should reduce your workload.
Exporting
Now to finish off by describing how to export your figures. I’m not going to re-invent the wheel here. I highly recommend using export_fig (found here on the MathWorks file exchange). It does a great job at reproducing what you see on your screen. It also works well with various file formats. I’ve used it to make pdf, eps, and jpeg images (including the ones in these posts).
Is it the End?
This short series shows an end-to-end workflow of plotting in MATLAB. There will be more posts on specific “tricks”.