function forest(celldata) % AUTHOR: Neil Carter, Psychology Department, Swansea University, UK % % LST UPDATED: 2012-10-04 12:02 % % DESCRIPTION: Generates a forest plot, typically used for showing % statistical effect size. % % Based on the script retrieved from: % % https://groups.google.com/forum/?fromgroups#!topic/comp.soft-sys.matlab/aBoDWhZ28qw % % CREATED: for row = 1:length(celldata(:,1)) % A single space is needed to prevent a shortened list. (Empty cells % would not be coppied by the = array assignation. if isempty(celldata{row,1}) celldata{row,1} = ' '; end if isempty(celldata{row,2}) celldata{row,2} = 0; end if isempty(celldata{row,4}) celldata{row,4} = 0; end if isempty(celldata{row,5}) celldata{row,5} = 0; end if isempty(celldata{row,6}) celldata{row,6} = 0; end end title = celldata(:,1); effect = cell2mat(celldata(:,2)); % Ignore column 3 (SE) sampsz = cell2mat(celldata(:,4)); lowlim = cell2mat(celldata(:,5)); uprlim = cell2mat(celldata(:,6)); % Ignore column 7 (overall effect size) pvalue = cell2mat(celldata(:,8)); summation = celldata(:,9); nlines = length(title); norm_samp = sampsz / 15; clf; set( gcf, 'Color', 'white' ); % --------------------------------------------------------------------- % Left-hand plot with study names. subplot(1,8,1); % Y axis starts at zero and goes up to one more than the number of % cases. % Set the size of the plot. We need one extra line at the top and the % bottom, to provide space for the axes. axis( [ 0, 1, 0, nlines+1 ] ); % Hide the axes. set(gca,'visible','off'); for n = nlines : -1 : 1 if strcmp( title{n}, ' ' ) ~= 0 if sampsz(n) > 0 text( 1.2, nlines+1 - n, 'Overall effect', ..., 'HorizontalAlignment', 'right', ... 'fontsize', 10, ... 'fontweight', 'bold' ); end else text( 1.2, nlines+1 - n, title{n}, ..., 'HorizontalAlignment', 'right', ... 'fontsize', 10, ... 'fontweight', 'bold' ); end; end % --------------------------------------------------------------------- % First right-hand plot, with effect sizes and P values. subplot(1,8,5); axis( [ 0, 1, 0, nlines+1 ] ); set( gca, 'visible', 'off' ); for ln = nlines : -1 : 1 strfmt = '%4.2f (p<%4.2f)'; if pvalue(ln) < 0.01 strfmt = '%4.2f (p<%5.3f)'; end if sampsz(ln) > 1 myText = sprintf( strfmt, effect(ln), pvalue(ln) ); else myText = ''; end text( -0.2, nlines+1 - ln, myText, ... 'HorizontalAlignment', 'left', ... 'fontsize', 10, ... 'fontweight', 'bold' ); end % --------------------------------------------------------------------- % Second right-hand plot, with summation information. subplot(1,8,[6 7 8]); prvgap = 0; % The following axis command does not change the physical width of the % graph; it affects only the range of x values that fit within the % predefined physical width. axis( [ 0, 1, 0, nlines+1 ] ); axis manual; hold on; set( gca, 'visible', 'off' ); for ln = 1 : nlines if sampsz(ln) < 1 strfmt = ':\n%4.2f (p<%4.2f)'; if pvalue(ln) < 0.01 strfmt = ':\n%4.2f (p<%5.3f)'; end txt1 = sprintf( strfmt, effect(ln), pvalue(ln) ); txt2 = sprintf( '%s%s', char(summation(ln)), txt1 ); txt3 = sprintf( 'Summated effect size for studies including %s', txt2 ); txt4 = textwrap( cellstr(txt3), 40 ); % Example. Assume previous gap at line 20, current gap at line % 12, so line should be: % 12 + ((20-12)/2) % = 12 + (8/2) % = 12 + 4 % = 16 % textln contains the line where the current gap lies. textln = ln - ((ln - prvgap)/2); plot( [0.05; 0.05], [ nlines-prvgap+.2 nlines-ln+1.7 ], 'k', 'LineWidth', 2.5 ); text( 0.1, nlines+1-textln, txt4, ... 'HorizontalAlignment', 'left', ... 'fontsize', 10, ... 'fontweight', 'bold' ); prvgap = ln; end; end; % --------------------------------------------------------------------- % Middle-plot of actual data. subplot(1,8,[2 3 4]); hold on; % X-axis size axis( [ -1, 1, 0, nlines+1 ] ); % Draw the max-min bars. % The first row contains negative error (minimum), the second row % contains the positive error (maximum). X = [ lowlim, uprlim ]'; Y = [1;1] * [nlines : -1 : 1]; % Draw the sample-size boxes for ln = nlines : -1 : 1 if strcmp(title(ln), ' ') == 0 plot( X(:,ln), Y(:,ln), 'k', 'LineWidth', 2.5 ); plot( effect(ln), nlines+1 - ln, 'ks', ... 'Marker', 's', ... 'markerSize',norm_samp(ln), ... 'MarkerEdgeColor','k', ... 'MarkerFaceColor','k' ); else % Plot diamonds for overall effect size if sampsz(ln) ~= 0 plot( effect(ln), nlines+1 - ln, 'ks', ... 'Marker', 'd', ... 'markerSize',norm_samp(ln)/2, ... 'MarkerEdgeColor','k', ... 'MarkerFaceColor','k' ); end end end set( gca, 'visible', 'on' ); set( gca, 'YTick', [] ); celllabel = {'Favors' 'placebo' }; text( -0.5, -0.8, celllabel, ... 'fontsize', 10, 'fontweight', 'bold', ... 'HorizontalAlignment', 'center' ); celllabel = {'Favors' 'multivitamins/minerals' }; text( 0.5, -0.8, celllabel, ... 'fontsize', 10, 'fontweight', 'bold', ... 'HorizontalAlignment', 'center', ... 'Interpreter', 'tex' ); grid on; set( gca, 'XTick', -1:0.5:1 ); set( gca, 'XTickMode', 'manual', 'fontweight', 'bold' ); set( gca, 'GridLineStyle', '-' ) axesPosition = get(gca,'Position'); %# Get the current axes position axes('Position',axesPosition,... %# Place a new axes on top... 'Color','none',... %# ... with no background color 'XAxisLocation','top',... %# ... located on the right 'XTick',[],... %# ... with no x tick marks 'YTick',[],... %# ... with no x tick marks 'Box','off'); %# ... and no surrounding box set(gcf, 'PaperType', 'A4'); set(gcf, 'PaperOrientation', 'landscape'); saveas( gcf, 'daves_forest_plot.pdf', 'pdf' ); end