74 views (last 30 days)

Show older comments

Hey,

I think this question has been asked before:

But I could not find any proper solution;

so is there a way to achieve something like this:

I'm looking forward to hear your suggestions :)

Sambit Supriya Dash
on 6 May 2021

Yes it is possible to get boxplot and histogram in one plot,

Example,

x = [1 2 3;4 5 6;7 8 9];

y = [5 4 3; 5 7 9; 1 9 3];

figure(1)

hist(x)

hold on

boxplot(y)

hold off

Hope, it helps.

Adam Danz
on 7 May 2021

Edited: Adam Danz
on 7 May 2021

This method uses patch objects to display histograms next to each boxplot. It's based on another answer that displays probability density distributions next to vertical scatter plots.

You only need to replace the x and y data and can copy-paste the rest of the code.

Inputs.

x : 1xn vector defining the x coordinate of n boxplots.

y : mxn matrix of raw data for n boxplots

rng('default') % for reproducibility

x = 0:5:30;

y = (randn(300, numel(x)) + linspace(.5,5,numel(x))) .* linspace(.5,2,numel(x));

Set spacing

binWidth = 0.4; % histogram bin widths

hgapGrp = .05; % horizontal gap between pairs of boxplot/histograms (normalized)

hgap = 0.2; % horizontal gap between boxplot and hist (normalized)

Compute histogram counts & edges

hcounts is an nx2 cell array containing the {counts, edges} for each distribution.

maxCount is the maximum bin count across all distributionts, used to normalize patch heights

hcounts = cell(size(y,2),2);

for i = 1:size(y,2)

[hcounts{i,1}, hcounts{i,2}] = histcounts(y(:,i),'BinWidth',binWidth);

end

maxCount = max([hcounts{:,1}]);

Plot boxplots

fig = figure();

ax = axes(fig);

hold(ax,'on')

xInterval = mean(diff(sort(x))); % x-interval (best if x is at a fixed interval)

normwidth = (1-hgapGrp-hgap)/2;

boxplotWidth = xInterval*normwidth;

boxplot(ax,y,'Positions',x,'Widths',boxplotWidth,'OutlierSize',3,'Labels',compose('%d',x))

Add vertical histograms (patches)

histX0 = x + boxplotWidth/2 + hgap; % histogram base

maxHeight = xInterval*normwidth; % max histogram height

patchHandles = gobjects(1,size(y,2));

for i = 1:size(y,2)

% Normalize heights

height = hcounts{i,1}/maxCount*maxHeight;

% Compute x and y coordinates

xm = [zeros(1,numel(height)); repelem(height,2,1); zeros(2,numel(height))] + histX0(i);

yidx = [0 0 1 1 0]' + (1:numel(height));

ym = hcounts{i,2}(yidx);

% Plot patches

patchHandles(i) = patch(xm(:),ym(:),[0 .75 1],'FaceAlpha',.4);

end

xlim([-2.5, 32.5])

Method 2 with color control

With just a few changes to the code above, you can use boxplotGroup() from the file exchange to set up colors of boxplots and histogram similar to the example in your question.

%% Inputs

rng('default') % for reproducibility

x = 0:5:30;

y = (randn(300, numel(x)) + linspace(.5,5,numel(x))) .* linspace(.5,2,numel(x));

%% Set Spacing

binWidth = 0.4; % histogram bin widths

hgapGrp = .15; % horizontal gap between pairs of boxplot/histograms (normalized)

hgap = 0.06; % horizontal gap between boxplot and hist (normalized)

%% Compute histogram counts & edges

hcounts = cell(size(y,2),2);

for i = 1:size(y,2)

[hcounts{i,1}, hcounts{i,2}] = histcounts(y(:,i),'BinWidth',binWidth);

end

maxCount = max([hcounts{:,1}]);

%% Plot boxplotsGroup()

fig = figure();

ax = axes(fig);

hold(ax,'on')

% Convert y (mxn matrix) to 1xn cell array of mx1 vectors, required by boxplotWidths

yc = mat2cell(y,size(y,1),ones(1,size(y,2)));

xInterval = 1; %x-interval is always 1 with boxplot groups

normwidth = (1-hgapGrp-hgap)/2;

boxplotWidth = xInterval*normwidth;

% Define colors for each boxplot

colors = lines(size(y,2));

% Plot colored boxplots

bph = boxplotGroup(ax,yc,'Widths',boxplotWidth,'OutlierSize',3,'PrimaryLabels',compose('%d',x),'Colors',colors);

set(findobj(bph.boxplotGroup,'-property','LineWidth'), 'LineWidth', 1) % increase line widths

%% Add vertical histograms (patches) with matching colors

xCoordinate = 1:size(y,2); %x-positions is always 1:n with boxplot groups

histX0 = xCoordinate + boxplotWidth/2 + hgap; % histogram base

maxHeight = xInterval*normwidth; % max histogram height

patchHandles = gobjects(1,size(y,2));

for i = 1:size(y,2)

% Normalize heights

height = hcounts{i,1}/maxCount*maxHeight;

% Compute x and y coordinates

xm = [zeros(1,numel(height)); repelem(height,2,1); zeros(2,numel(height))] + histX0(i);

yidx = [0 0 1 1 0]' + (1:numel(height));

ym = hcounts{i,2}(yidx);

% Plot patches

patchHandles(i) = patch(xm(:),ym(:),colors(i,:),'EdgeColor',colors(i,:),'LineWidth',1,'FaceAlpha',.45);

end

Scott MacKenzie
on 6 May 2021

Edited: Scott MacKenzie
on 7 May 2021

This solution uses tiledlayout and boxchart, but you can adjust to use subplot and boxplot if you are running an older version of MATLAB:

n = 7;

y = randn(100,n);

tiledlayout(1, 2*n);

for i=1:n

nexttile;

boxchart(y(:,i));

set(gca,'visible', 'off', 'ylim', [-4 4]);

nexttile;

histogram(y(:,i), 20, 'orientation', 'horizontal');

set(gca,'visible', 'off', 'ylim', [-4 4]);

end

f = gcf;

f.Color = 'w';

f.Units = 'normalized';

f.Position = [.1 .2 .8 .4];

Scott MacKenzie
on 7 May 2021

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

Start Hunting!