4
$\begingroup$

I am generating a bar chart in which each count is to be represented by a disk (or something similar). This alone seems straightforward: simply set the option ChartElements -> Graphics@Disk[]. But alas, it's not perfect, as shown by the following example:

BarChart[#, ChartElements -> Graphics@Disk[], 
   ChartLabels -> {"bin " /@ #}, FrameLabel -> {"Bins", "Counts"}, 
   LabelStyle -> Directive[Black, Larger], PlotTheme -> "Detailed", 
   ImageSize -> Large] &@Range[8]

enter image description here

The first column should contain one whole disk. The second column should contain two whole disks, so on and so forth. This can be corrected by setting ChartElements -> {Graphics@Disk[], {1, 1}}, which produces

enter image description here

But notice how each column of disks is now off-center from its frame tick and label. This becomes far more evident as the number of counts increases; for example, when the charted values are squared:

enter image description here

I tried re-centering the labels under the columns of disks by changing ChartLabels -> Placed["bin " /@ #, {{0.39, 0}, {1, 1.5}}], which produced the following result:

enter image description here

The labels are now smaller and apparently invisible to FrameLabel, which overlaps them! I suppose that may be corrected by wrapping another Placed around the horizontal frame label, but all of this fine-tuning could be avoided in the first place if I can just get the disks to remain centered within thier columns.

So, is there a way to do that?

(Wrapping Placed around the disks themselves didn't work...)

Thanks!

$\endgroup$
2
  • $\begingroup$ In Mathematica 12.1 this works fine (on Windows). Which version are you using? $\endgroup$ Commented Oct 14, 2020 at 18:07
  • $\begingroup$ @RolfMertig according to $Version, I'm using 12.1.1 for Microsoft Windows (64-bit) (June 19, 2020) But it works fine for you? Can you demonstrate? Is there a newer (or older) version of 12.1? $\endgroup$ Commented Oct 14, 2020 at 20:41

1 Answer 1

5
$\begingroup$

Update: A more convenient approach is to use {All, 1} (or {Scaled[1], 1}) to specify the size of chart elements and use Offset to specify the radius of disks:

BarChart[#, 
   ChartElements -> {Graphics@Disk[{0, 0}, Offset[15]], {All, 1}}, 
   ChartLabels -> {Rotate[#, Pi/2] & /@ "bin " /@ #}, 
   FrameLabel -> {"Bins", "Counts"}, 
   LabelStyle -> Directive[Black, Larger], PlotTheme -> "Detailed", 
   ImageSize -> Large] & @ Range[8]

enter image description here

Replace Range[8] with Range[16] and Offset[15] with Offset[7] to get:

enter image description here

Original answer:

We can post-process the BarChart output and modify the Inset arguments:

ClearAll[centerBars]
centerBars = # /. Graphics[GeometricTransformation[Inset[i_, a__], t_], o___, 
      PlotRange -> {{0, x1_}, yr_}, o2___] :> 
    Graphics[GeometricTransformation[Inset[i, {x1/2, 0}, {Center, Bottom}, {1, 1}], t],
      o, PlotRange -> {{0, x1}, yr}, o2] /. 
    Inset[i_, {x_, 0.}, a_, b_, c_] :> 
      Inset[i, {Ceiling[x], 0.}, {Center, Bottom}, b, c] &;

Examples:

charts = BarChart[(Range@8)^#, 
     ChartElements -> {Graphics[Disk[]], {1, 1}}, 
     ChartLabels -> {"bin " /@ (Range[8]^#)}, 
     FrameLabel -> {"Bins", "Counts"}, 
     LabelStyle -> Directive[Black, Larger], PlotTheme -> "Detailed", 
     PerformanceGoal -> "Speed", ImageSize -> 500] & /@ {1, 2};

Grid[Transpose[{charts, centerBars /@ charts}]]

enter image description here

$\endgroup$
1
  • 1
    $\begingroup$ Amazing. Though unfortunate that post-processing is necessary at all. Nonetheless, thanks for the fix, and I will credit you in any charts I produce using this! $\endgroup$ Commented Oct 15, 2020 at 16:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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