How to create a figure design that propagates through all axes of subplot figure

4 次查看(过去 30 天)
I am trying to develop a "style" look for a tool I've made. I would like to define things like font color/size, grid lines, background color, etc in one location and apply it to all 6 subplots. Currently I am copy and pasting the relevent code 6 times, but there must be a way to do it more efficently/programmatically.
Part of my struggle seems to be with figure/axis/scatter interactions wiping out my settings, but I haven't gotten my head around the concept apparently.
Logically I would define all common aspects of my axes first, then copy that for each new axes. But after calling scatter my settings are lost, and no combination I try gets around this.
In my example, I begin defining the first and last subplot after they are all created. To finish would be a lot of copy paste, and it wouldn't be easily adjustable for a future change.
Thank you for the help!
load('C:\Starts_Tool_Saves\200226_1311_Starts_Tool_Saved_Results.mat')
names = fieldnames(Results);
names = names(16:26);
metricVsTemp = figure;
ax1 = subplot(3,2,1);
sp = scatter(ax1,[Results.engTemp],[Results.timeStart2Comb],'.');
ax2 = subplot(3,2,2);
sp = scatter(ax2,[Results.engTemp],[Results.timeStart2Thresh],'.');
ax3 = subplot(3,2,3);
hold(ax3, 'on')
sp = scatter(ax3,[Results.engTemp],[Results.engRPMOver],'.');
sp = scatter(ax3,[Results.engTemp],[Results.engRPMUndr],'.');
hold(ax3, 'off')
ax4 = subplot(3,2,4);
sp = scatter(ax4,[Results.engTemp],[Results.timeStart2Stab],'.');
ax5 = subplot(3,2,5);
hold(ax5, 'on')
sp = scatter(ax5,[Results.engTemp],[Results.cyl1LambdaInitMax],'.');
sp = scatter(ax5,[Results.engTemp],[Results.cyl1LambdaInitMin],'.');
sp = scatter(ax5,[Results.engTemp],[Results.cyl2LambdaInitMax],'.');
sp = scatter(ax5,[Results.engTemp],[Results.cyl2LambdaInitMin],'.');
hold(ax5, 'off')
ax6 = subplot(3,2,6);
hold(ax6, 'on')
sp = scatter(ax6,[Results.engTemp],[Results.cyl1LambdaMean],'.');
sp = scatter(ax6,[Results.engTemp],[Results.cyl2LambdaMean],'.');
hold(ax6, 'off')
ax1.XLabel.String = 'Temperature in C';
ax1.XAxis.Limits = [-30 170];
ax1.XGrid = 'on';
ax1.YGrid = 'on';
ax1.GridLineStyle = ":";
ax1.YLabel.String = names(1);
ax6.XLabel.String = 'Temperature in C';
ax6.XAxis.Limits = [-30 170];
ax6.XGrid = 'on';
ax6.YGrid = 'on';
ax6.GridLineStyle = ":";
ax6.YLabel.String = names(10);

回答(1 个)

Steven Lord
Steven Lord 2020-2-28
Some of those properties you could set as default property values for all axes in your figure, but I'd probably just write up a little function that accepts as input an axes handle and your desired Y label string and sets the appropriate properties on the axes. You would have to call the function on each axes handle, but that's one line that you need to execute for each axes rather than six. You could even use a for loop over the list of axes (either stored in an array of axes handles, use gobjects to preallocate it, or found using findobj) to make it even simpler.
  2 个评论
dpb
dpb 2020-2-28
Agree w/ Steven!!!
Couple comments along the line:
ax1 = subplot(3,2,1);
sp = scatter(ax1,[Results.engTemp],[Results.timeStart2Comb],'.');
ax2 = subplot(3,2,2);
sp = scatter(ax2,[Results.engTemp],[Results.timeStart2Thresh],'.');
Use an array of axes handles, don't create sequence of variables with suffixes...that prevents being able to call in a loop of whatever size over the array and is what forces copying code (or another way that is so evil won't even mention it!)
Similarly, you're overwriting the handle to the scatter() object every time so you've lost each one but the last so you can't collect code for it to make some global change if you were to build a GUI that let you click on a given trace in one axes and want to highlight in all, say, or somesuch thing as that.
names = fieldnames(Results);
names = names(16:26);
% Define lookup table here for which field goes in which axes...
% Then the x,y data for each are simply a lookup
xvars={.engTemp'};
yvars={'timeStart2Comb',
'timeStart2Thresh',
'engRPMOver', 'engRPMUndr',
'timeStart2Stab',
'cyl1LambdaInitMax','cyl1LambdaInitMin','cyl2LambdaInitMax','cyl2LambdaInitMin',
'cyl1LambdaMean','cyl2LambdaMean'};
nYvars=[1 1 2 1 4 2];
for i=1:6
hAx(i)=subplot(3,2,i); % create the ith subplot, save handle...
k=0; % counter of indexing to yvars array
for j=1:nYvars(i) % how many variables on each subplot
k=k+1; increment k
hSc(i,j)=scatter(Results.engTemp,Results.(yvars{k}),'.'); % scatter, keep handle
end
% other stuff specific to this axes goes here
...
end
That's a little klunky having just done inline here, but should, I think, almost run.
It would be a little cleaner to have the yvars separated by subplot so could index as 2D array or similarly instead of the continuous counter, but should suffice to give the idea of how to generalize.
One can even do things similar to what Steven was saying about objects like using string matching to find the variables---
% create example structure with data
Results.engTemp=184;
Results.timeStart2Comb=1.234;
% retrieve data by looking up the field name from string match
>> Results.(names{strcmp(names,'timeStart2Comb')})
ans =
1.2340
>>
The string being matched could just as easily also been a variable reference, not a fixed string.

请先登录,再进行评论。

产品


版本

R2019a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by