1

I am doing some analysis and need to produce a histogram plot. I know how to create the standard histogram plot but I need something like the image below, where each point is an interval on the x axis. Each bin is based on a value from x-x for example.

Example histogram

SecretAgentMan
  • 2,856
  • 7
  • 21
  • 41
VBA_Novice
  • 27
  • 4
  • 1
    @rinkert , agree on dupe but that answer doesn't use [`histogram`](https://www.mathworks.com/help/matlab/ref/matlab.graphics.chart.primitive.histogram.html) which is now recommended over [`histc`](https://www.mathworks.com/help/matlab/ref/histc.html) used by that answer. – SecretAgentMan Apr 29 '19 at 12:50
  • @SecretAgentMan, ok retracted my flag, since the other answer is not recommended. Then a new answer using `histc` could be added here or in the other post. – rinkert Apr 29 '19 at 13:04
  • i am not sure what answer you are both referring to – VBA_Novice Apr 29 '19 at 13:07
  • @rinkert, Agreed, I think the answer lies in using [`histogram`](https://www.mathworks.com/help/matlab/ref/matlab.graphics.chart.primitive.histogram.html) and adjusting the [histogram properties](https://www.mathworks.com/help/matlab/ref/matlab.graphics.chart.primitive.histogram-properties.html) but don't have time right now to do full quality answer. – SecretAgentMan Apr 29 '19 at 13:08
  • Related post (but not duplicate) [here](https://stackoverflow.com/q/29016872/8239061) but that answer uses function no longer recommended by Matlab. – SecretAgentMan Apr 29 '19 at 13:10
  • What's wrong with just using the argument 'BinWidth' and set the interval to desired spacing? For the 'greater than' bins for histograms, there's a easy sounding solution on Mathworks [link](https://ch.mathworks.com/matlabcentral/answers/397573-histogram-greater-than-bin) – user2305193 Apr 29 '19 at 17:03

1 Answers1

4

You can use the histogram function, and then set the XTick positions and XTickLabels accordingly. See the comments in the code for explanation.

% random normally distrubuted data
x = 1*randn(1000,1);
edges = -5:1:5;

% create vector with labels (for XTickLabel ... to ...)
labels = [edges(1:end-1); edges(2:end)];
labels = labels(:);

% plot the histogram
figure();
ax = axes;
h = histogram(x, 'BinEdges', edges, 'Normalization', 'Probability');

ax.XTick = edges + mean(diff(edges)/2);
ax.XTickLabel = sprintf('%.1f to %.1f\n', labels);
ax.XTickLabelRotation = 90;

% set yticks to percentage
ax.YTickLabel = cellfun(@(a) sprintf('%i%%', (str2double(a)*100)), ax.YTickLabel, 'UniformOutput', false);

% text above bars
bin_props = h.BinCounts/numel(x);  % determine probabilities per bin in axis units
bin_centers = ax.XTick(1:end-1);  % get the bin centers

txt_heigts = bin_props + 0.01; % put the text slightly above the bar
txt_labels = split(sprintf('%.1f%% ', bin_props*100), ' ');
txt_labels(end) = [];  % remove last cell, is empty because of split.
text(ax, bin_centers, txt_heigts, txt_labels, 'HorizontalAlignment', 'center')

% set ylim to fit all text (otherwise text is outside axes)
ylim([0 .4]);

Putting the text at the right location may require some tweaking. Most important is the 'HorizontalAlignment' option, and the distance to the bars. I also used the 'Normalization', 'probability' option from the histogram function, and set the y axis to also show percentages.

I figure you can make the addition below yourself when needed.

enter image description here


When your data can be outside of the defined binedges, you can clip your data, and set the XTickLabels with less than or greater than signs.

% when data can be outside of defined edges
x = 5*randn(1000,1);
xclip = x;
xclip(x >= max(edges)) = max(edges);
xclip(x <= min(edges)) = min(edges);

% plot the histogram
figure();
ax = axes;
h = histogram(xclip, 'BinEdges', edges);

ax.XTick = edges + mean(diff(edges)/2);
ax.XTickLabel = sprintf('%.1f to %.1f\n', labels);
ax.XTickLabelRotation = 90;

% set boundary labels
ax.XTickLabel{1} = sprintf('\\leq %.1f', edges(2));
ax.XTickLabel{end-1} = sprintf('\\geq %.1f', edges(end-1));

enter image description here


You can also set the outer edges to -Inf and Inf, as user2305193 pointed out. Since the outer bins are then much wider (because they actually extend to Inf on the x axis), which you can correct by setting the axis xlim. By the default the XTickLabels will display -Inf to -5.0, which I personally don't like, so I set them to lesser (and equal) than and greater than signs.

step = 1;
edges = -5:step:5;                                  % your defined range
edges_inf = [-Inf edges Inf];                       % for histogram
edges_ext = [edges(1)-step edges];                  % for the xticks

x = 5*randn(1000,1);

% plot the histogram
figure();
ax = axes;
h = histogram(x, 'BinEdges', edges_inf, 'Normalization', 'probability');

labels = [edges_inf(1:end-1); edges_inf(2:end)];
labels = labels(:);

ax.XTick = edges_ext + step/2;
ax.XTickLabel = sprintf('%.1f to %.1f\n', labels);
ax.XTickLabelRotation = 90;

% show all bins with equal width (Inf bins are in fact wider)
xlim([min(edges)-step max(edges)+step])

% set boundary labels
ax.XTickLabel{1} = sprintf('\\leq %.1f', edges(1));
ax.XTickLabel{end-1} = sprintf('\\geq %.1f', edges(end));

enter image description here

rinkert
  • 6,593
  • 2
  • 12
  • 31
  • Brilliant this is exactly what i needed. Is there anyway to show the percentage like in the original figure i attached. I know how to normalise the axis through normalisation - probability. – VBA_Novice Apr 29 '19 at 14:12
  • @VBA_Novice, look at the [`normalization`](https://mathworks.com/help/matlab/ref/matlab.graphics.chart.primitive.histogram-properties.html) property. Choose your normalisation method and use that property when you call the `histogram` function. – Hoki Apr 29 '19 at 14:29
  • 1
    Excellent answer. Answers OP's question & clear for future visitors. (+1) – SecretAgentMan Apr 29 '19 at 14:34
  • @Hoki i know how to normalize when calling the histogram function. What i was asking: is there anyway to show the percentage on top of each bin, as shown in my picture that i posted. – VBA_Novice Apr 29 '19 at 14:43
  • i agree this is an excellent response. It has helped me. thank you @rinkert – VBA_Novice Apr 29 '19 at 14:45