am304
am304

Reputation: 13876

Multiple bar charts in one graph in Octave

Using Octave 4.2.1 on Windows with the qt graphics toolkit (I can't use gnuplot because it crashes in some other part of the code). I have a dataset which is 35x7x4 (35 data points for 7 conditions on 4 channels) - you can use random data for the purpose of this exercise.

I am trying to create 4 subplots (1 for each channel), with 7 bar graphs on each subplot (one per condition) to see how the distribution of data changes with each condition. Each of the 7x4 = 28 distributions has its own set of bins and frequencies, and I can't seem to be able to combine the 7 datasets on one graph (subplot).

Posting the whole of the code would be too complicated, but here's a simplified version:

nb_channels = 4;
nb_conditions = 7;
nbins = 15;
freq = zeros(nbins,nb_conditions,nb_channels);
xbin = zeros(nbins,nb_conditions,nb_channels);

plot_colours = [91 237 165 255 68 112 255;
  155 125 165 192 114 173 0;
  213 49 165 0 196 71 255];
plot_colours = plot_colours / 255;

for k = 1:nb_channels
  for n = 1:nb_conditions
    % some complex calculations to generate temp variable
    [freq(:,n,k),xbin(:,n,k)] = hist(temp,nbins);
  end
end

figure
for k = 1:nb_channels
  subplot(2,2,k)
  for n = 1:nb_conditions
    bar(xbin(:,n,k),freq(:,n,k),'FaceColor',plot_colours(:,n))
    hold on
  end
  hold off
  legend('condition #1','condition #2','condition #3','condition #4','condition #5','condition #6','condition #7')
end

which gives something like this:

enter image description here

So you can't really see anything, all the bars are on top of each other. In addition, Octave doesn't support transparency property for patch objects (which is what bar charts use), so I can't overlay the histograms on top of each other, which I would really quite like to do.

Is there a better way to approach this? It seems that bar will only accept a vector for x data and not a matrix, so I am stuck in having to use hold on and loop through the various conditions, instead of using a matrix approach.

Upvotes: 1

Views: 2892

Answers (1)

am304
am304

Reputation: 13876

OK, so I'll try to answer my own question based on the suggestions made in the comments:

Suggestion 1: make all the bins the same

This does improve the results somewhat but it's still an issue due to the lack of transparency for patch objects.

Code changes:

nbins = 15;
xbin = linspace(5.8,6.5,nbins);

for k = 1:nb_channels
  for n = 1:nb_conditions
    % some complex calculations to generate temp variable
    freq_flow(:,n,k) = hist(temp,xbin);
  end
end

figure
for k = 1:nb_channels
  subplot(2,2,k)
  for n = 1:nb_conditions
    bar(xbin,freq_flow(:,n,k),'FaceColor',plot_colours(:,n))
    hold on
  end
  hold off
  xlim([5.8 6.3])
  legend('condition #1','condition #2','condition #3','condition #4','condition #5','condition #6','condition #7')
end

Which gives the following plot:

enter image description here

Suggestion 2: Use line plots instead of bar charts

This helps a bit more in terms of readability. However, the result is a bit "piece-wise".

Code changes:

 figure
    for k = 1:nb_channels
      subplot(2,2,k)
      for n = 1:nb_conditions
        plot(xbin,freq_flow(:,n,k),'LineStyle','none','marker','.',...
            'markersize',12,'MarkerEdgeColor',plot_colours(:,n),...
            'MarkerFaceColor',plot_colours(:,n))
        hold on
      end
      hold off
      xlim([5.8 6.3])
      legend('condition #1','condition #2','condition #3','condition #4','condition #5','condition #6','condition #7')
    end

Which gives the following result:

enter image description here

The legend is a bit screwed but I can probably sort that out.

A variation on this I also tried was to plot just the points as markers, and then a fitted normal distribution on top. I won't post all the code here, but the result looks something like this:

enter image description here

Suggestion 3: transparency workaround with gnuplot

Unfortunately, before I even got to the transparency workaround, gnuplot keeps crashing when trying to plot the figure. There's something it doesn't like with subplots and legends I think (which is why I moved to qt graphics toolkit in the first place, as I had exactly the same issue in other parts of the code).

Solution 4: use 3D bar graph

I found this on SO: 3D histogram with gnuplot or octave

and used it as such:

figure
for k = 1:size(flow_factor,2)
  subplot(2,2,k)
  h = my_bar3(freq_flow(:,:,k));
  fvcd = kron((1:numel(freq_flow(:,:,k)))', ones(6,1));
  set(h, 'FaceVertexCData',fvcd, 'FaceColor','flat', 'CDataMapping','scaled')
  colormap hsv; axis tight; view(50,25)
  ylbl = cell(length(xbin),1);
  for k=1:length(xbin)
    ylb{k} = num2str(xbin(k));
  end
  set(gca,'YTick',1:2:nbins);
  set(gca,'YTickLabel',ylb(1:2:end));
end

to produce:

enter image description here

Which isn't bad, but probably not as clear as the line plots.

Conclusion

On balance, I will probably end up using one of the line plots approaches, as they tend to be clearer.

Upvotes: 2

Related Questions