10
$\begingroup$

I have a fairly complex sort of BarChart that I want to overlay with other graphics. For concreteness, let's assume that I want to overlay a LinePlot. In doing so, I found this answer quite helpful, but my chart has some additional wrinkles which complicate things. First, let's invent some data:

data = {Association["a" -> 0.7037417451289036, 
    "b" -> 0.503687396357559, "c" -> 0.8305301936239331, 
    "d" -> 0.23466296631845518], Association[
    "a" -> 0.08369185073518004, "b" -> 0.5808357340946317, 
    "c" -> 1.873919922991976, "d" -> 1.3981710526525974], 
   Association["a" -> 1.6327509774236528, "b" -> 1.3925276568460028, 
    "c" -> 1.1036001759467897, "d" -> 1.0264775292307071], 
   Association["a" -> 3.218464871800018, "b" -> 0.6400499501591295, 
    "c" -> 0.4775621030459698, "d" -> 2.375619997842695], 
   Association["a" -> 3.160797696474269, "b" -> 0.36822672048523586, 
    "c" -> 3.862723785325967, "d" -> 0.41766552167593396]};     

Then I'll whip up a BarChart:

bars = BarChart[data, ChartLegends -> Automatic, 
  PlotRange -> {Automatic, Automatic}]

so a duck walks into a bar...

Now for the ListPlot, using the DataRange trick suggested by that linked answer.

means = Mean /@ data;

lines = ListPlot[means, Joined -> True, PlotStyle -> Black, 
  DataRange -> {2.5, 2.5 + 4*4}]

enter image description here

Now I can Show the two together:

Show[bars, lines, ImagePadding -> {{10, 10}, {10, 10}}]

enter image description here

As you can see, it's almost, but not quite, right. Evidently the spacing between the groups throws things off, but I'm not entirely sure how much, in part because I'm not sure how much spacing there is between bars. It's complicated by the fact that there are two different sorts of spacing, one within groups of bars, and one between bars, and the two seem to affect the $x$-coördinates of the bars in different ways. I could set BarSpacings to {None, None}, but that looks ugly.

Is there a better way? Or a simple way of understanding how bars are spaced when they're divided into groups?

$\endgroup$
7
$\begingroup$

Perhaps this:

Get the tick values:

ticks = FrameTicks /. Options[First @ bars, FrameTicks]

Get the x tick values:

 xticks = ticks[[2, 1, All, 1]]

Visualize the x tick values with dots on top of the bar chart:

Show[bars, Graphics[{AbsolutePointSize[4], Point[{#, 0}]} & /@ xticks]]    

enter image description here

This gives you all the center points of each bar, but also the center points between the groups of bars. Get rid of those:

xticks2 = Drop[xticks, {5, -1, 5}]

Using those x ticks values, use the first and last of each group to find the center x coordinate of each group:

line = Table[
 Line[{
  {(xticks2[[4 i]] + xticks2[[4 i - 3]])/2, means[[i]]}, 
  {(xticks2[[4 (1 + i)]] + xticks2[[1 + 4 i]])/2, means[[i + 1]]}}
 ], 
{i, 1, 4}]

Make the new plot, with the line points centered on the bar groups:

Show[bars, Graphics[{AbsoluteThickness[5], line}]]

enter image description here

$\endgroup$
  • $\begingroup$ +1, since it's pretty clever. Still, it fails if FrameTicks has been replaced with a custom value, which is a possibility. $\endgroup$ – Pillsy Nov 6 '15 at 22:48
  • $\begingroup$ You can probably make this work with any custom FrameTicks, but I haven't tried that case. $\endgroup$ – Arnoud Buzing Nov 6 '15 at 22:54
4
$\begingroup$

Maybe here's a small improvement

Show[
 bars,
 ListLinePlot[means, DataRange -> {2.6, 19}],
 ListPlot[means, DataRange -> {2.6, 19}],
 GridLines -> {{2.6, 6.7, 10.8, 14.9, 19}, {1, 2, 3, 4}},
 ImageSize -> Large,
 ImagePadding -> {{10, 10}, {10, 10}}]

enter image description here

The gridlines run through the centers of the "meshpoints" and are uniformely spaced at

{2.6, 6.7, 10.8, 14.9, 19.0} // Differences

{4.1, 4.1, 4.1, 4.1}

$\endgroup$
  • $\begingroup$ how did you find the gridlines' XX coordinates? (trying to adapt this to my problem) $\endgroup$ – Sosi Nov 10 '15 at 17:32
  • $\begingroup$ By trial and error - but didn't take too long $\endgroup$ – eldo Nov 10 '15 at 17:34
  • $\begingroup$ :P I now remembered there's the "Get coordinates" thing where you can see them quickly! $\endgroup$ – Sosi Nov 10 '15 at 17:39
2
$\begingroup$

Use the option Joined -> Automatic

bars = BarChart[data, ChartLegends -> {"a", "b", "c", "d"}, 
  PlotRange -> {Automatic, All}, Joined -> Automatic]

and post-process the Lines to get the mean of each group:

ppF = # /. Line[x_] /; FreeQ[x, _Offset] :> Point[Mean[x]] /. 
 pts : {___, ({dirs__, _Point} ..)} :> {Thickness[.01], 
   CapForm["Round"], PointSize[Large], 
   Through[{Point, Line}[(pts /. {} -> Sequence[])[[All, -1, 1]]]]}&;

ppF @ bars 

enter image description here

Using a different option value for BarSpacing:

bars2 = BarChart[data, ChartLegends -> {"a", "b", "c", "d"}, 
  PlotRange -> {Automatic, All}, BarSpacing->{Large, Large}, Joined -> Automatic]

ppF @ bars2

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.