-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
941 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
% copyfields.m - copies fields from one scalar structure to another | ||
% | ||
% /--------------------------------------------------------------\ | ||
% | Date: 01/08/2023 | | ||
% | Author: Jonathan Cody | | ||
% | Affiliation: Pienaar Computational Systems Pharmacology Lab | | ||
% | Weldon School of Biomedical Engineering | | ||
% | Purdue University | | ||
% \--------------------------------------------------------------/ | ||
% | ||
% Copy field values from one scalar structure variable 'struc2' into | ||
% another structure variable 'struc1' and return struc1. If overWrite=0, | ||
% existing struc1 fields will not be changed, only new fields added. If a | ||
% struc2 field is itself a structure, 'copyfields' is called again for that | ||
% structure. | ||
% | ||
%% ======================================================================== | ||
% FUNCTION | ||
% ======================================================================== | ||
function struc1 = copyfields(struc1,struc2,overWrite) | ||
|
||
if nargin < 3 ; overWrite = 1 ; end % overwrite fields by default | ||
|
||
if isempty(struc2) ; return ; end % do nothing if struc2 is empty | ||
|
||
fields2 = fieldnames(struc2) ;% names of fields in struc2 | ||
|
||
for f = 1:length(fields2) | ||
if overWrite || ~isfield(struc1,fields2{f}) | ||
if isstruct(struc2.(fields2{f})) | ||
struc1.(fields2{f}) = copyfields... | ||
(struc1.(fields2{f}),struc2.(fields2{f}),overWrite) ; | ||
else | ||
try %#ok<TRYNC> avoid errors thrown by graphics objects | ||
struc1.(fields2{f}) = struc2.(fields2{f}) ; | ||
end | ||
end | ||
end | ||
end | ||
|
||
end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
% gridplot.m - creates a grid of plots (alternative to MATLAB's 'subplot') | ||
% | ||
% /--------------------------------------------------------------\ | ||
% | Date: 01/08/2023 | | ||
% | Author: Jonathan Cody | | ||
% | Affiliation: Pienaar Computational Systems Pharmacology Lab | | ||
% | Weldon School of Biomedical Engineering | | ||
% | Purdue University | | ||
% \--------------------------------------------------------------/ | ||
% | ||
%% ======================================================================== | ||
% INPUTS | ||
% ======================================================================== | ||
% | ||
% PROPS = cell array of scalar structures that define axis properties | ||
% -> Index is {left-to-right,bottom-to-top} | ||
% (EX: {2,1} is 2nd axis from the left, on the bottom) | ||
% -> See 'Axes Properties' in MATLAB help for a list of fields | ||
% | ||
% LINES = cell array that defines line data and properties | ||
% -> Index is {left-to-right,bottom-to-top} (same as 'PROPS') | ||
% -> Each element is a cell array of scalar structures | ||
% -> Order determines plot rank ({1} is plotted on top of other lines) | ||
% -> See 'linemaker.m' for a description of fields in these structures | ||
|
||
% Optional inputs are entered after 'LINES' as (string name),(value) pairs | ||
% -> See line 44 for definitions and default values | ||
% | ||
%% ======================================================================== | ||
% OUTPUTS | ||
% ======================================================================== | ||
% | ||
% figH = figure handle | ||
% | ||
% AxisH = matrix of axis handles (Index is left-to-right,bottom-to-top) | ||
% | ||
%% ======================================================================== | ||
% FUNCTION | ||
% ======================================================================== | ||
function [figH,AxisH] = gridplot(PROPS,LINES,varargin) | ||
|
||
[nX,nY] = size(PROPS) ;% number of x,y axes | ||
|
||
% Set default values for optional inputs | ||
AxisProps = [] ;% scalar structure of properties shared by all axes | ||
% -> see 'Axes Properties' in MATLAB help | ||
|
||
FigColor = [1 1 1] ;% figure background color [R G B] | ||
|
||
figName = 'figure' ;% figure name (and file name) | ||
|
||
FigSizes = [0 0] ;% figure [horizontal,vertical] size | ||
% -> axes will adapt to ensure figure size | ||
% -> (ignored in that direction if zero) | ||
% -> use 'Units' to define units | ||
|
||
imageRes = '-r300' ;% image resolution (see MATLAB 'print' function) | ||
|
||
imageType = '-dtiff' ;% image file type (see MATLAB 'print' function) | ||
|
||
isBroken = [0 0] ;% treat [x,y] axes as broken axes | ||
% -> EX: [1 0] shares lines and axis properties between | ||
% all axes in each row and hides y-axes after column 1 | ||
% -> if 'FigSizes' is also set, axes lengths will be | ||
% proportional to number of ticks | ||
|
||
Gaps = [.25 .25] ;% [horizontal,vertical] gaps between axes | ||
% -> use 'Units' to define units | ||
|
||
LineProps = [] ;% scalar structure of properties shared by all lines | ||
% -> see 'linemaker.m' for a descriptions of fields | ||
|
||
Margins = [1 1 .5 .5] ;% [left,bottom,right,top] figure margins | ||
% -> use 'Units' to define units | ||
|
||
Units = 'inches' ;% length units for figure | ||
% -> see 'Figure Properties' in MATLAB help for options | ||
|
||
XLengths = ones(1,nX) ;% lengths of x-axes (left-to-right) | ||
% -> If FigSizes(1)~=0, treated as relative size | ||
|
||
YLengths = ones(1,nY) ;% lengths of y-axes (bottom-to-top) | ||
% -> If FigSizes(2)~=0, treated as relative size | ||
|
||
for n = 1:length(varargin) | ||
if strcmp('AxisProps',varargin(n)) ; AxisProps = varargin{n+1} ; end | ||
if strcmp('FigColor', varargin(n)) ; FigColor = varargin{n+1} ; end | ||
if strcmp('figName', varargin(n)) ; figName = varargin{n+1} ; end | ||
if strcmp('FigSizes', varargin(n)) ; FigSizes = varargin{n+1} ; end | ||
if strcmp('imageRes', varargin(n)) ; imageRes = varargin{n+1} ; end | ||
if strcmp('imageType',varargin(n)) ; imageType = varargin{n+1} ; end | ||
if strcmp('isBroken', varargin(n)) ; isBroken = varargin{n+1} ; end | ||
if strcmp('Gaps', varargin(n)) ; Gaps = varargin{n+1} ; end | ||
if strcmp('LineProps',varargin(n)) ; LineProps = varargin{n+1} ; end | ||
if strcmp('Margins', varargin(n)) ; Margins = varargin{n+1} ; end | ||
if strcmp('Units', varargin(n)) ; Units = varargin{n+1} ; end | ||
if strcmp('XLengths', varargin(n)) ; XLengths = varargin{n+1} ; end | ||
if strcmp('YLengths', varargin(n)) ; YLengths = varargin{n+1} ; end | ||
end | ||
|
||
% If 'LINES' is not full size, make it full size | ||
if size(LINES,1) < nX ; LINES{nX,1} = [] ; end | ||
if size(LINES,2) < nY ; LINES{1,nY} = [] ; end | ||
|
||
% Update axis lengths to enforce figure size | ||
if FigSizes(1)~=0 | ||
if isBroken(1) | ||
for x = 1:nX | ||
XLengths(x) = length(PROPS{x,1}.XTick) ; | ||
end | ||
end | ||
axisSpace = FigSizes(1) - (nX-1)*Gaps(1) - Margins(1) - Margins(3) ; | ||
XLengths = XLengths * axisSpace / sum(XLengths) ; | ||
end | ||
if FigSizes(2)~=0 | ||
if isBroken(2) | ||
for y = 1:nY | ||
YLengths(y) = length(PROPS{1,y}.YTick) ; | ||
end | ||
end | ||
axisSpace = FigSizes(2) - (nY-1)*Gaps(2) - Margins(2) - Margins(4) ; | ||
YLengths = YLengths * axisSpace / sum(YLengths) ; | ||
end | ||
|
||
LongestAxis = max( [YLengths XLengths] ) ;% used for equalizing tick length | ||
|
||
figH = figure( 'Name' , figName ... | ||
, 'Color' , FigColor ... | ||
, 'Units' , Units ... | ||
, 'PaperUnits' , Units ) ;% figure handle | ||
|
||
AxisH = gobjects(nX,nY) ;% axis handles | ||
|
||
xPos = Margins(1) ;% distance from left of figure | ||
|
||
for x = 1:nX | ||
|
||
yPos = Margins(2) ;% distance from bottom of figure | ||
|
||
for y = 1:nY | ||
|
||
% Generate axis and define axis position | ||
AxisH(x,y) = axes(figH,'Units',Units,... | ||
'Position',[xPos yPos XLengths(x) YLengths(y)]) ; | ||
|
||
% Modify axis per 'AxisProps' and 'PROPS{y,x}' | ||
AxisH(x,y) = copyfields(AxisH(x,y),AxisProps ) ; | ||
AxisH(x,y) = copyfields(AxisH(x,y),PROPS{x,y}) ; | ||
|
||
% Copy x/y tick from bottom/left axis | ||
% Hide x/y axis if y/x axis is broken | ||
if x~=1 | ||
AxisH(x,y).YTick = AxisH(1,y).YTick ; | ||
AxisH(x,y).YTickLabel = [] ; | ||
if isBroken(1) | ||
AxisH(x,y).YColor = 'none' ; | ||
LINES{x,y} = LINES{1,y} ; | ||
end | ||
end | ||
if y~=1 | ||
AxisH(x,y).XTick = AxisH(x,1).XTick ; | ||
AxisH(x,y).XTickLabel = [] ; | ||
if isBroken(2) | ||
AxisH(x,y).XColor = 'none' ; | ||
LINES{x,y} = LINES{x,1} ; | ||
end | ||
end | ||
|
||
% Plot lines, modifying 'LINES' per 'LineProps' | ||
if ~isempty(LINES{x,y}) | ||
for n = length(LINES{x,y}):-1:1 | ||
LINES{x,y}{n} = copyfields(LINES{x,y}{n},LineProps,0) ; | ||
linemaker(LINES{x,y}{n}) ; | ||
end | ||
end | ||
|
||
% Fit axis limits to tick marks | ||
AxisH(x,y).XLim = [AxisH(x,y).XTick(1) AxisH(x,y).XTick(end)] ; | ||
AxisH(x,y).YLim = [AxisH(x,y).YTick(1) AxisH(x,y).YTick(end)] ; | ||
|
||
% Correct MATLAB's normalized tick lengths | ||
AxisH(x,y).TickLength = AxisH(x,y).TickLength * ... | ||
LongestAxis / max( [XLengths(x) YLengths(y)] ) ; | ||
|
||
yPos = yPos + YLengths(y) + Gaps(2) ; | ||
end | ||
xPos = xPos + XLengths(x) + Gaps(1) ; | ||
end | ||
|
||
% Declare figure width and height | ||
FigSizes = [xPos yPos] - Gaps + Margins(3:4) ; | ||
|
||
% Print figure | ||
figH.Position = [0 0 FigSizes] ; | ||
figH.PaperSize = FigSizes ; | ||
figH.InvertHardcopy = "off" ; | ||
print(figName,imageType,imageRes) | ||
|
||
end |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
% linemaker.m - plots lines to current axis, with a variety of options | ||
% | ||
% /--------------------------------------------------------------\ | ||
% | Date: 01/08/2023 | | ||
% | Author: Jonathan Cody | | ||
% | Affiliation: Pienaar Computational Systems Pharmacology Lab | | ||
% | Weldon School of Biomedical Engineering | | ||
% | Purdue University | | ||
% \--------------------------------------------------------------/ | ||
% | ||
%% ======================================================================== | ||
% INPUTS | ||
% ======================================================================== | ||
% | ||
% s = structure variable that defines line | ||
% -> At minimum, s must contain fields 'X' and 'Y' (data) | ||
% -> See 'Line Properties' in MATLAB help for a list of fields | ||
% -> Additional optional fields are defined on line 35 | ||
% | ||
%% ======================================================================== | ||
% OUTPUTS | ||
% ======================================================================== | ||
% | ||
% Handles = cell array of line handles | ||
% | ||
%% ======================================================================== | ||
% FUNCTION | ||
% ======================================================================== | ||
function Handles = linemaker(s) | ||
hold on | ||
|
||
X = s.X ;% data x-values (each column is different line) | ||
Y = s.Y ;% data y-values (each column is different line) | ||
|
||
% Set default values for optional fields in 's' | ||
CensorID = [] ;% index in Y to mark as censored (white marker face) | ||
% -> use only with single line of marked data points | ||
|
||
ColorMap = [] ;% [R1 G1 B1 ; R2 G2 B2 ; etc.] matrix of line colors | ||
% -> similar to MATLAB's 'colormap' | ||
|
||
ErrorBars = [] ;% vector of error bar lengths (same size as Y) | ||
% -> using with 'CensorID' will generate a trivial warning | ||
|
||
FillColor = [] ;% [R G B (transparency)] fill color between first two lines | ||
|
||
GradENDS = [] ;% [R1 G1 B1 ; R2 G2 B2] corresponding to min(1) and max(2) | ||
% of values in 'GradGuide' (alternative to 'ColorMap') | ||
|
||
GradGuide = [] ;% interpolation vector between GradENDS(1,:) and (2,:) | ||
% -> must be the same length as the number of lines | ||
|
||
if isfield(s,'CensorID') ; CensorID = s.CensorID ; end | ||
if isfield(s,'ColorMap') ; ColorMap = s.ColorMap ; end | ||
if isfield(s,'ErrorBars') ; ErrorBars = s.ErrorBars ; end | ||
if isfield(s,'FillColor') ; FillColor = s.FillColor ; end | ||
if isfield(s,'GradENDS') ; GradENDS = s.GradENDS ; end | ||
if isfield(s,'GradGuide') ; GradGuide = s.GradGuide ; end | ||
|
||
% Plot lines and modify per 's' | ||
if ~isempty(ErrorBars) | ||
Handles = errorbar(X,Y,ErrorBars) ; | ||
else | ||
Handles = plot(X,Y) ; | ||
end | ||
for n = 1:length(Handles) | ||
Handles(n) = copyfields(Handles(n),s) ; | ||
end | ||
|
||
% Color line based on 'ColorMap | ||
if ~isempty(ColorMap) | ||
for n = 1:length(Handles) | ||
Handles(n).Color = ColorMap(n,:) ; | ||
end | ||
end | ||
|
||
% Color line based on 'GradGuide' and 'GradENDS' | ||
if ~isempty(GradGuide) | ||
G = ( GradGuide - min(GradGuide) ) / range(GradGuide) ; | ||
for n = 1:length(Handles) | ||
Handles(n).Color = ... | ||
GradENDS(1,:) + ( GradENDS(2,:) - GradENDS(1,:) )*G(n) ; | ||
end | ||
end | ||
|
||
% Mark specified points as hidden | ||
if ~isempty(CensorID) | ||
Handles(n+1) = copyobj(Handles(n),ancestor(Handles(n),'axes')) ; | ||
Handles(n+1).XData = Handles(n).XData(CensorID) ; | ||
Handles(n+1).YData = Handles(n).YData(CensorID) ; | ||
Handles(n+1).LineStyle = 'none' ; | ||
Handles(n+1).MarkerFaceColor = [1 1 1] ; | ||
end | ||
|
||
% Shade region between lines | ||
if ~isempty(FillColor) | ||
XPATCH = [ Handles(1).XData' ; flip(Handles(2).XData') ] ; | ||
YPATCH = [ Handles(1).YData' ; flip(Handles(2).YData') ] ; | ||
Handles(n+1) = patch( XPATCH, YPATCH, FillColor(1:3) ... | ||
, 'FaceAlpha' , FillColor(4) ... | ||
, 'LineStyle' , 'none' ) ; | ||
end | ||
|
||
hold off | ||
end |
Oops, something went wrong.