|
48 | 48 | defaultDose = []; |
49 | 49 | defaultCst = []; |
50 | 50 | defaultSlice = floor(min(ct.cubeDim)./2); |
51 | | -defaultAxesHandle = gca; |
| 51 | +defaultAxesHandle = []; |
52 | 52 | defaultCubeIdx = 1; |
53 | 53 | defaultPlane = 1; |
54 | 54 | defaultDoseWindow = []; |
|
61 | 61 | defaultBoolPlotLegend = false; |
62 | 62 | defaultColorBarLabel = []; |
63 | 63 | defaultShowCt = true; |
| 64 | +defaultTitle = []; |
64 | 65 |
|
65 | 66 | isDose = @(x) isnumeric(x) && all(size(x) == ct.cubeDim); |
66 | 67 | isSlice = @(x) x>=1 && x<=max(ct.cubeDim) && floor(x)==x; |
67 | | -isAxes = @(x) strcmp(get(gca, 'type'), 'axes'); |
| 68 | +isAxes = @(x) strcmp(get(x, 'type'), 'axes') || isempty(x); |
68 | 69 | isCubeIdx = @(x) isscalar(x); |
69 | 70 | isPlane = @(x) isscalar(x) && (sum(x==[1, 2, 3])==1); |
70 | 71 | isDoseWindow = @(x) (length(x) == 2 && isvector(x)); |
|
77 | 78 | isBoolPlotLegend = @(x) x==0 || x ==1; |
78 | 79 | isColorBarLabel = @(x) isstring(x) || ischar(x) || isempty(x); |
79 | 80 | isShowCt = @(x) isscalar(x) && (x==0) || (x==1); |
| 81 | +isTitle = @(x) isstring(x) || ischar(x) || isempty(x); |
80 | 82 |
|
81 | 83 | p = inputParser; |
82 | 84 | p.KeepUnmatched = true; |
83 | | -addRequired(p, 'ct') |
84 | | - |
85 | | -addParameter(p, 'dose', defaultDose, isDose) |
86 | | -addParameter(p, 'cst', defaultCst) |
87 | | -addParameter(p, 'slice', defaultSlice, isSlice) |
88 | | -addParameter(p, 'axesHandle', defaultAxesHandle, isAxes) |
89 | | -addParameter(p, 'cubeIdx', defaultCubeIdx, isCubeIdx) |
90 | | -addParameter(p, 'plane', defaultPlane, isPlane) |
91 | | -addParameter(p, 'doseWindow', defaultDoseWindow, isDoseWindow) |
92 | | -addParameter(p, 'thresh', defaultThresh, isThresh) |
93 | | -addParameter(p, 'alpha', defaultAlpha, isAlpha) |
94 | | -addParameter(p, 'doseColorMap', defaultDoseColorMap, isDoseColorMap) |
95 | | -addParameter(p, 'doseIsoLevels', defaultDoseIsoLevels, isDoseIsoLevels) |
96 | | -addParameter(p, 'voiSelection', defaultVOIselection, isVOIselection) |
97 | | -addParameter(p, 'contourColorMap', defaultContourColorMap, isContourColorMap) |
98 | | -addParameter(p, 'boolPlotLegend', defaultBoolPlotLegend, isBoolPlotLegend) |
99 | | -addParameter(p, 'colorBarLabel', defaultColorBarLabel, isColorBarLabel) |
100 | | -addParameter(p, 'showCt', defaultShowCt, isShowCt) |
101 | | - |
102 | | -parse(p, ct, varargin{:}); |
| 85 | + |
| 86 | +addRequired(p, 'ct'); |
| 87 | + |
| 88 | +addParameter(p, 'dose', defaultDose, isDose); |
| 89 | +addParameter(p, 'cst', defaultCst); |
| 90 | +addParameter(p, 'slice', defaultSlice, isSlice); |
| 91 | +addParameter(p, 'axesHandle', defaultAxesHandle, isAxes); |
| 92 | +addParameter(p, 'cubeIdx', defaultCubeIdx, isCubeIdx); |
| 93 | +addParameter(p, 'plane', defaultPlane, isPlane); |
| 94 | +addParameter(p, 'doseWindow', defaultDoseWindow, isDoseWindow); |
| 95 | +addParameter(p, 'thresh', defaultThresh, isThresh); |
| 96 | +addParameter(p, 'alpha', defaultAlpha, isAlpha); |
| 97 | +addParameter(p, 'doseColorMap', defaultDoseColorMap, isDoseColorMap); |
| 98 | +addParameter(p, 'doseIsoLevels', defaultDoseIsoLevels, isDoseIsoLevels); |
| 99 | +addParameter(p, 'voiSelection', defaultVOIselection, isVOIselection); |
| 100 | +addParameter(p, 'contourColorMap', defaultContourColorMap, isContourColorMap); |
| 101 | +addParameter(p, 'boolPlotLegend', defaultBoolPlotLegend, isBoolPlotLegend); |
| 102 | +addParameter(p, 'colorBarLabel', defaultColorBarLabel, isColorBarLabel); |
| 103 | +addParameter(p, 'showCt', defaultShowCt, isShowCt); |
| 104 | +addParameter(p, 'title', defaultTitle, isTitle); |
| 105 | + |
| 106 | +p.parse(ct, varargin{:}); |
103 | 107 |
|
104 | 108 | %% Unmatched properties |
105 | 109 | % General properties |
106 | | -lineFieldNames = fieldnames(set(line)); |
107 | | -textFieldNames = fieldnames(set(text)); |
| 110 | +% This is a hack with an invisible figure to obtain the properties |
| 111 | +hTmpFig = figure('Visible','off','HandleVisibility','off'); |
| 112 | +hTmpAx = axes(hTmpFig); |
| 113 | +axesFieldNames = fieldnames(set(hTmpAx)); |
| 114 | +lineFieldNames = fieldnames(set(line(hTmpAx))); |
| 115 | +textFieldNames = fieldnames(set(text(hTmpAx))); |
| 116 | +delete(hTmpAx); |
| 117 | +close(hTmpFig); |
| 118 | + |
108 | 119 | % Filter line properties from Unmatched |
109 | 120 | unmParamNames = fieldnames(p.Unmatched); |
110 | 121 | lineFields = unmParamNames(ismember(unmParamNames, lineFieldNames)); |
111 | 122 | lineValues = struct2cell(p.Unmatched); |
112 | 123 | lineValues = lineValues(ismember(unmParamNames, lineFieldNames)); |
113 | 124 | lineVarargin = reshape([lineFields, lineValues]', 1, []); |
| 125 | + |
114 | 126 | % Filter text properties from Unmatched |
115 | 127 | textFields = unmParamNames(ismember(unmParamNames, textFieldNames)); |
116 | 128 | textValues = struct2cell(p.Unmatched); |
117 | 129 | textValues = textValues(ismember(unmParamNames, textFieldNames)); |
118 | 130 | textVarargin = reshape([textFields, textValues]', 1, []); |
| 131 | +% |
| 132 | +axesFields = unmParamNames(ismember(unmParamNames, axesFieldNames)); |
| 133 | +axesValues = struct2cell(p.Unmatched); |
| 134 | +axesValues = axesValues(ismember(unmParamNames, axesFieldNames)); |
| 135 | +axesVarargin = reshape([axesFields, axesValues]', 1, []); |
| 136 | + |
119 | 137 |
|
120 | 138 | %% Plot ct slice |
121 | 139 | matRad_cfg = MatRad_Config.instance(); |
122 | 140 |
|
| 141 | +if isempty(p.Results.axesHandle) |
| 142 | + axesHandle = axes(figure()); |
| 143 | +else |
| 144 | + axesHandle = p.Results.axesHandle; |
| 145 | +end |
| 146 | + |
123 | 147 | % Flip axes direction |
124 | | -set(p.Results.axesHandle,'YDir','Reverse'); |
| 148 | +set(axesHandle,'XTick',[],'YTick',[]); |
| 149 | +set(axesHandle,'YDir','Reverse'); |
125 | 150 | % plot ct slice |
126 | 151 | if p.Results.showCt |
127 | | - hCt = matRad_plotCtSlice(p.Results.axesHandle,p.Results.ct.cubeHU,p.Results.cubeIdx,p.Results.plane,p.Results.slice, [], []); |
| 152 | + hCt = matRad_plotCtSlice(axesHandle,p.Results.ct.cubeHU,p.Results.cubeIdx,p.Results.plane,p.Results.slice, [], []); |
128 | 153 | end |
| 154 | +axis(axesHandle, 'off'); |
| 155 | + |
129 | 156 | hold on; |
130 | 157 |
|
131 | 158 | %% Plot dose |
|
134 | 161 | if ~isempty(p.Results.doseWindow) && p.Results.doseWindow(2) - p.Results.doseWindow(1) <= 0 |
135 | 162 | doseWindow = p.Results.doseWindow; |
136 | 163 | end |
137 | | - [hDose,doseColorMap,doseWindow] = matRad_plotDoseSlice(p.Results.axesHandle, p.Results.dose, p.Results.plane, p.Results.slice, p.Results.thresh, p.Results.alpha, p.Results.doseColorMap, doseWindow); |
| 164 | + [hDose,doseColorMap,doseWindow] = matRad_plotDoseSlice(axesHandle, p.Results.dose, p.Results.plane, p.Results.slice, p.Results.thresh, p.Results.alpha, p.Results.doseColorMap, doseWindow); |
138 | 165 | hold on; |
139 | 166 |
|
140 | 167 | %% Plot iso dose lines |
141 | 168 | hIsoDose = []; |
142 | 169 | if ~isempty(p.Results.doseIsoLevels) |
143 | | - hIsoDose = matRad_plotIsoDoseLines(p.Results.axesHandle,p.Results.dose,[],p.Results.doseIsoLevels,false,p.Results.plane,p.Results.slice,p.Results.doseColorMap,p.Results.doseWindow, lineVarargin{:}); |
| 170 | + hIsoDose = matRad_plotIsoDoseLines(axesHandle,p.Results.dose,[],p.Results.doseIsoLevels,false,p.Results.plane,p.Results.slice,p.Results.doseColorMap,p.Results.doseWindow, lineVarargin{:}); |
144 | 171 | end |
145 | 172 |
|
146 | 173 | %% Set Colorbar |
147 | | - hCMap = matRad_plotColorbar(p.Results.axesHandle,doseColorMap,doseWindow,'Location','EastOutside'); |
| 174 | + hCMap = matRad_plotColorbar(axesHandle,doseColorMap,doseWindow,'Location','EastOutside'); |
148 | 175 | set(hCMap,'Color',matRad_cfg.gui.textColor); |
149 | 176 | if ~isempty(p.Results.colorBarLabel) |
150 | 177 | set(get(hCMap,'YLabel'),'String', p.Results.colorBarLabel,'FontSize',matRad_cfg.gui.fontSize); |
|
154 | 181 | %% Plot VOI contours & Legend |
155 | 182 |
|
156 | 183 | if ~isempty(p.Results.cst) |
157 | | - [hContour,~] = matRad_plotVoiContourSlice(p.Results.axesHandle, p.Results.cst, p.Results.ct, p.Results.cubeIdx, p.Results.voiSelection, p.Results.plane, p.Results.slice, p.Results.contourColorMap, lineVarargin{:}); |
| 184 | + [hContour,~] = matRad_plotVoiContourSlice(axesHandle, p.Results.cst, p.Results.ct, p.Results.cubeIdx, p.Results.voiSelection, p.Results.plane, p.Results.slice, p.Results.contourColorMap, lineVarargin{:}); |
158 | 185 |
|
159 | 186 | if p.Results.boolPlotLegend |
160 | 187 | visibleOnSlice = (~cellfun(@isempty,hContour)); |
|
163 | 190 | if ~isempty(p.Results.voiSelection) |
164 | 191 | voiSelection = visibleOnSlice(find(p.Results.voiSelection)); |
165 | 192 | end |
166 | | - hLegend = legend(p.Results.axesHandle,[hContourTmp{:}],[p.Results.cst(voiSelection,2)],'AutoUpdate','off','TextColor',matRad_cfg.gui.textColor); |
| 193 | + hLegend = legend(axesHandle,[hContourTmp{:}],[p.Results.cst(voiSelection,2)],'AutoUpdate','off','TextColor',matRad_cfg.gui.textColor); |
167 | 194 | set(hLegend,'Box','On'); |
168 | 195 | set(hLegend,'TextColor',matRad_cfg.gui.textColor); |
169 | 196 | if ~isempty(textVarargin) |
|
177 | 204 | end |
178 | 205 |
|
179 | 206 | %% Adjust axes |
180 | | -axis(p.Results.axesHandle,'tight'); |
181 | | -set(p.Results.axesHandle,'xtick',[],'ytick',[]); |
182 | | -colormap(p.Results.axesHandle,p.Results.doseColorMap); |
| 207 | +axis(axesHandle,'tight'); |
| 208 | +set(axesHandle,'xtick',[],'ytick',[]); |
| 209 | +colormap(axesHandle,p.Results.doseColorMap); |
183 | 210 | fontSize = []; |
184 | 211 | if isfield(p.Unmatched, 'FontSize') |
185 | 212 | fontSize = p.Unmatched.FontSize; |
186 | 213 | end |
187 | | -matRad_plotAxisLabels(p.Results.axesHandle,p.Results.ct,p.Results.plane,p.Results.slice, fontSize, []) |
| 214 | +matRad_plotAxisLabels(axesHandle,p.Results.ct,p.Results.plane,p.Results.slice, fontSize, []) |
188 | 215 |
|
189 | 216 | % Set axis ratio. |
190 | 217 | ratios = [1/p.Results.ct.resolution.x 1/p.Results.ct.resolution.y 1/p.Results.ct.resolution.z]; |
191 | 218 |
|
192 | | -set(p.Results.axesHandle,'DataAspectRatioMode','manual'); |
| 219 | +set(axesHandle,'DataAspectRatioMode','manual'); |
193 | 220 | if p.Results.plane == 1 |
194 | 221 | res = [ratios(3) ratios(2)]./max([ratios(3) ratios(2)]); |
195 | | - set(p.Results.axesHandle,'DataAspectRatio',[res 1]) |
| 222 | + set(axesHandle,'DataAspectRatio',[res 1]) |
196 | 223 | elseif p.Results.plane == 2 % sagittal plane |
197 | 224 | res = [ratios(3) ratios(1)]./max([ratios(3) ratios(1)]); |
198 | | - set(p.Results.axesHandle,'DataAspectRatio',[res 1]) |
| 225 | + set(axesHandle,'DataAspectRatio',[res 1]) |
199 | 226 | elseif p.Results.plane == 3 % Axial plane |
200 | 227 | res = [ratios(2) ratios(1)]./max([ratios(2) ratios(1)]); |
201 | | - set(p.Results.axesHandle,'DataAspectRatio',[res 1]) |
| 228 | + set(axesHandle,'DataAspectRatio',[res 1]) |
| 229 | +end |
| 230 | + |
| 231 | +%% Title |
| 232 | +if ~isempty(p.Results.title) |
| 233 | + title(axesHandle,p.Results.title); |
202 | 234 | end |
203 | 235 |
|
204 | 236 | %% Set text properties |
205 | 237 | if ~isempty(textVarargin) |
206 | | - set(p.Results.axesHandle, textVarargin{:}) |
207 | | - set(p.Results.axesHandle.Title, textVarargin{:}) |
| 238 | + set(axesHandle, textVarargin{:}) |
| 239 | + set(axesHandle.Title, textVarargin{:}) |
208 | 240 | end |
209 | 241 |
|
210 | 242 | if ~exist('hCMap', 'var') |
|
0 commit comments