Option 1: use boxplotGroup()
See boxplotGroup() on the file exchange. If your boxplot data are matrices with the same number of columns, you can use this function to group them and provide primary and secondary labels. Option 2: Use newline to create two rows of tick labels
Pro: Easy and clean
Con: Less control of the alignment between the upper and lower labels.
ticks = {'a_peaks','b','a_concat','b','a_F0','b','a_Fs','b'};
ticks = strrep(ticks,'_','\newline');
ax.XTick = [1 2 4 5 7 8 10 11];
This variation below controls the alignment between the upper and lower labels but adds an additional tick between the upper labels.
ticks = {'a','_peaks','b','a','_concat','b','a','_F0','b','a','_Fs','b'};
ticks = strrep(ticks,'_','\newline');
ax.XTick = [1 1.5 2 4 4.5 5 7 7.5 8 10 10.5 11];
Option 2.1: Use cell array with justified text
Added to answer 11-Feb-2021
Pro: Intuitive label arrangement & text justification
ticks = {'a','','b','a','','b','a','','b','a','','b'; ...
'','peaks','','','concat','','','F0','','','Fs',''};
ticksJust = strjust(pad(ticks),'center');
tickLabels = strtrim(sprintf('%s\\newline%s\n', ticksJust{:}));
ax.XTick = [1 1.5 2 4 4.5 5 7 7.5 8 10 10.5 11];
ax.XTickLabel = tickLabels;
Option 3: Use text() to create a second row of tick lables
Pro: More control over the placement of the tick labels.
Con: Axis limits must be set and the lower tick labels will move if the pan feature is used.
upperPosition = sum(ax.Position([2,4]));
ax.Position(4) = ax.Position(4) * .9;
ax.Position(2) = minus(upperPosition, ax.Position(4));
ax.XTick = [1 2 4 5 7 8 10 11];
ax.XTickLabel = {'a' 'b'};
lowerLevel = min(ylim(ax))-range(ylim(ax))*.06;
lowerLabels = {'peaks','concat','F0','FS'};
text([1.5, 4.5, 7.5, 10.5], repmat(lowerLevel,1,numel(lowerLabels)), lowerLabels,...
'VerticalAlignment','Top','HorizontalAlignment','Center')