4

I am having trouble plotting a histogram of the x-values of my data points together with a line showing the relationship between x and y, mainly because the scale in the y direction of the histogram is not of the same magnitude as the scale in the line plot. For example:

% generate data
rng(1, 'twister')
x = randn(10000,1);
y = x.^2

% plot line, histogram, then histogram and line.
subplot(3,1,1)
scatter(x, y, 1, 'filled')
ax = gca;
maxlim = max(ax.XLim); % store maximum y-value to rescale histogram to this value

subplot(3,1,2)
h = histogram(x, 'FaceAlpha', 0.2)

subplot(3,1,3)
scatter(x, y, 1, 'filled')
hold on
h = histogram(x, 'FaceAlpha', 0.2)

Produces the following:

enter image description here

where the line chart is completely obscured by the histogram.

Now, one might naively try to rescale the histogram using:

h.Values = h.Values/max(h.Values) * maxlim;

which gives

You cannot set the read-only property 'Values' of Histogram.

Alternatively one can get the bin counts using histcounts, but as far as I can tell, the bar function does not allow one to set the face alpha or have other configurability as per the call to histogram.

Alex
  • 15,186
  • 15
  • 73
  • 127
  • You can change the face alpha of a bar chart (https://www.mathworks.com/matlabcentral/newsreader/view_thread/243589) and so using `histc` is likely the smarter way to go. – Dan May 12 '16 at 06:36
  • thanks, can the other properties configured by `histogram` also be accessible in a similarly arcane way? – Alex May 12 '16 at 06:38
  • Very likely. Another option for you is to plot the line chart or the histogram on a secondary y axis – Dan May 12 '16 at 06:39
  • Like how I have done it in a subplot, or some other way? – Alex May 12 '16 at 06:44
  • no done another way. See MATLAB docs on [Create Chart with Two y-Axes](http://www.mathworks.com/help/matlab/creating_plots/plotting-with-two-y-axes.html). This way you line plot and your histogram can be plotted with different scales – Dan May 12 '16 at 06:46
  • thanks, that is a great solution but that only works with `2016a`. – Alex May 12 '16 at 06:49
  • You could always add another axis - try this sort of approach http://stackoverflow.com/questions/6573862/two-y-axis-with-the-same-x-axis – Dan May 12 '16 at 07:17
  • Your first link no longer works after 2014a: see http://au.mathworks.com/matlabcentral/answers/213991-matlab-put-transparancy-on-a-bar-plot – Alex May 12 '16 at 07:54
  • 1
    @Dan: `histc` is [deprecated](http://www.mathworks.com/help/matlab/creating_plots/replace-discouraged-instances-of-hist-and-histc.html) and has been for several releases now. – horchler May 12 '16 at 15:10
  • I recommend reading through the documentation for `histogram` and `histcounts`. They can do a lot of things. Have you tried any of the `'Normalization'` options? It's not clear to me if you want to reduce the height of your histogram or increase the height of your scatter plot. You can easily [modify `histogram` object properties](http://www.mathworks.com/help/matlab/ref/histogram-object.html). – horchler May 12 '16 at 15:13
  • I would like to reduce the height of my histogram, using the rescale factor `maxlim / max(h.Values)`. – Alex May 12 '16 at 23:30

1 Answers1

1

As discussed in the comments there are several solutions that depend on the version of Matlab you are using. To restate the problem, the histogram function allows you to control many graphics properties like transparency, but only gives you a limited number of options to change the height of the bars. With histcounts you can get the bar heights and rescale them however you want, but you must plot the bars yourself.

First option: use histogram

As you cannot rescale the histogram heights, you must plot them on separate axis.

From release 2016a and onwards, you can use yyaxis left for the scatter plot and yyaxis right for the histogram, see Matlab documentation:

Prior to this one must manually create and set separate y-axis. Although I have not found a good simple example of this, this is perhaps the most relevant answer here: plot two histograms (using the same y-axis) and a line plot (using a different y-axis) on the same figure

Using histcounts and manually creating a bar chart

Using my example, we can get counts as follows:

[Values, Edges] = histcounts(x);

And rescaling:

Values = Values / max(Values) * maxlim;

and finding centres of bars:

bar_centres = 0.5*(Edges(1:end-1) + Edges(2:end));

Up to release 2014a, bar charts had a 'children' property for the patches that allows transparency to be controlled, e.g.:

% plot histogram
b1 = bar(bar_centres,Values);
% change transparency
set(get(b1,'Children'),'FaceAlpha',0.3)

After 2014a bar charts no longer have this property, and to get around it I plot the patches myself using the code from this mathworks q&a, replicated here:

function ptchs = createPatches(x,y,offset,c,FaceAlpha)
%createPatches.m
% This file will create a bar plot with the option for changing the
% FaceAlpha property. It is meant to be able to recreate the functionality
% of bar plots in versions prior to 2014b. It will create the rectangular
% patches with a base centered at the locations in x with a bar width of
% 2*offset and a height of y.

% Ensure x and y are numeric vectors
validateattributes(x,{'numeric'},{'vector'});
validateattributes(y,{'numeric'},{'vector'});
validateattributes(c,{'char'},{'scalar'});
%#TODO Allow use of vector c

% Check size(x) is same as size(y)
assert(all(size(x) == size(y)),'x and y must be same size');

% Default FaceAlpha = 1
if nargin < 5
    FaceAlpha = 1;
end
if FaceAlpha > 1 || FaceAlpha <= 0
    warning('FaceAlpha has been set to 1, valid range is (0,1]');
    FaceAlpha = 1;
end

ptchs = cell(size(x)); % For storing the patch objects

for k = 1:length(x)
    leftX = x(k) - offset; % Left Boundary of x
    rightX = x(k) + offset; % Right Boundary of x
    ptchs{k} = patch([leftX rightX rightX leftX],...
        [0 0 y(k) y(k)],c,'FaceAlpha',FaceAlpha, ...
        'EdgeColor', 'none');
end




end

I made one change: that is, imposed the no edge condition. Then, it is perfectly fine to use:

createPatches(bin_centres, Values, 1,'k', 0.2)

to create the bars.

Community
  • 1
  • 1
Alex
  • 15,186
  • 15
  • 73
  • 127