# Labeling a bar chart, changing how rotated labels are centered

I'm trying to label a bar chart with rotated labels

see this simple example:

BarChart[RandomReal[1, 10], BarSpacing -> Large,
ChartLabels ->
Placed[ToString /@ RandomReal[100000, 10], Axis, Rotate[#, Pi/4] &]]


In this case the center of the label is aligned with the center of the bar.

I want the right/top of the label to be aligned with the center of the bar instead, basically shift the labels over a bit to the left. How can this be done?

Also, what if all the labels have different lengths:

-
You could try including an AdjustmentBox in your Placed function. I haven't time to write this up as a full answer just now but someone else might like to try. – Verbeia Mar 6 '12 at 22:08
s0rce, you may wish to revisit this question. belisarius's method no longer works in version 10, while Brett's does, and also for other plots as well. – Mr.Wizard Nov 11 '14 at 2:57

Something like this could also do:

BarChart[RandomReal[1, 10], BarSpacing -> Large,
ChartLabels ->
Placed[ToString /@
RandomChoice[ExampleData[{"Text", "DeclarationOfIndependence"}, "Words"], 10],
Axis, Rotate[#, Pi/4] &]] /.
ImageScaled[{1/2, 1}] -> ImageScaled[{0.9, 1}]


-
Nice to see you at the site. Btw, I wasn't able to get your code to run (even after changing EampleData to ExampleData. – David Carraher Mar 6 '12 at 23:56
@DavidCarraher: Please try now. – István Zachar Mar 7 '12 at 0:07
It works great! – David Carraher Mar 7 '12 at 1:23
@IstvánZachar Thanks for the edit! – belisarius has settled Mar 7 '12 at 13:31
I'm sorry to report that this no longer works in Mathematica 10. – Mr.Wizard Nov 11 '14 at 2:58

See if this works.

b = BarChart[RandomReal[1, 10], BarSpacing -> Large,
ChartLabels ->  Placed[ToString /@ RandomReal[100000, 10], Axis,
Rotate[#, Pi/4] &]];

b /. {Text[p_, Offset[ _, pos_], is_] -> Text[p, Offset[{-10, -2}, pos], is]}


I used AbsoluteOptions[b // InputForm] to inspect the code and identify the Text commands that place the chart labels. I then offset the labels leftward by 10 printer's points.

-

It can be done using the pos parameter of Placed:

BarChart[RandomReal[1, 10], BarSpacing -> Large,
ChartLabels ->
Placed[(ToString /@ 10^RandomInteger[10, 10]),
{{1, 0}, {1, 1}}
(* pos: bar position: lower right corner (1,0),
text box:     upper right corner (1,1)  *),
Rotate[#, Pi/4] &
]
]


Use {0.5,0} instead of {1,0} to align with the bottom center of the bar (which I find slightly less esthetical pleasing, but YMMV):

-
NIce approach. I find {0.75, 0} more pleasing to the eye than {0.5, 0}. – David Carraher Mar 6 '12 at 23:02
I also like {0.75,0} however, the labels are slightly closer to the Axis here then they are with Axis, can this be solved? edit: {{0.75, 0}, {1, 1.1}} looks a bit better but I think it makes the top uneven. – s0rce Mar 7 '12 at 2:49

Here is a function I had lying around to deal with the same problem. Note you need to specify your font and size somewhere first, or your could adapt the following function to take options.

The issue is that Rotate rotates around the center of the item, not around some point corresponding to a top edge or corner. This code works out where the top corner should be, and adds margins to the box so that the top corner stays centred on the bar. Depending on where you actually want the labels to be, you might need to adapt this a little. This function was designed for the case where the labels were always at the bottom of a framed chart.

font = "Arial";
fsize = 12;
rotatelabel[xlist : {(_String | _Style) ..}, rads_]/; Length[xlist]>2 :=
With[{len = Length[xlist], cosdeg = Cos[rads]},
FontFamily -> font, FontSize -> fsize],
BoxMargins -> {{If[rads < 0,  Max[0, cosdeg*(Plus @@
ImageDimensions[Rasterize[Style[#, FontFamily -> font, FontSize -> fsize]]])/(fsize)
- 1.5 ((len-1)/len) * Abs@cosdeg], 0],
If[cosdeg == 0 || cosdeg == 1 || rads < 0, 0,
Max[0, cosdeg*(Plus @@
ImageDimensions[Rasterize[Style[#, FontFamily -> font, FontSize -> fsize]]])/(fsize)
- 1.5 ((len-1)/len)* Abs@cosdeg]]}, {0.3, 0.25}}] & /@ xlist]


BarChart[data,  TicksStyle -> Directive[FontFamily -> "Arial", FontSize -> 12],
ChartLabels -> Placed[rotatelabel[labels, 45 Degree], Axis],   ImageSize -> 500]


The function handles the opposite slant, too, if that is what is desired.

BarChart[data, TicksStyle -> Directive[FontFamily -> "Arial", FontSize -> 12],
ChartLabels -> Placed[rotatelabel[labels, -45 Degree], Axis], ImageSize -> 500]


Another example

 BarChart[data, TicksStyle -> Directive[FontFamily -> "Arial", FontSize -> 12],
ChartLabels -> Placed[rotatelabel[labels, -90 Degree], Axis], ImageSize -> 500]


-

By default the Axis position that you're using centers the label under the bar along the axis. For long text that's rotated at a slant, it generally looks bad. (It works fine for horizontal and vertical text, however.)

Here's one approach, using a different second argument for Placed:

Module[{
labels = {"Learning focused", "Positively oriented", "Continuous",
"Timely", "Clear criteria", "Flexible", "Suited to student level"},
data = {8, 6, 4, 5, 5, 9, 9}
},
BarChart[data,
ChartLabels -> Placed[
labels,
{{0.5, 0}, {0.9, 1}},
Rotate[#, (2/7) Pi] &
],
PlotRange -> {Automatic, {0, 10}}, Ticks -> {None, Range[0, 10, 2]},
ImagePadding -> {{20, 0}, {95, 0}}
]
]


The first part of the argument, {0.5, 0}, says to place the label halfway across the bar, at the bottom.

The second part of the argument, {0.9, 1}, says what part of the label at the first part. In this case it's near, but not quite at, the right-top corner.

It's not exactly at the corner, because I think it looks better if the top of the "ink" is centered below the bars, and that won't be the actual corner unless your label ends with ">" or something similar.

Here's a second approach, using a different third argument of Placed:

Module[{
labels = {"Learning focused", "Positively oriented", "Continuous",
"Timely", "Clear criteria", "Flexible", "Suited to student level"},
data = {8, 6, 4, 5, 5, 9, 9}
},
BarChart[data,
ChartLabels -> Placed[
labels,
Axis,
Block[{text = Rotate[#, (2/7) Pi]},
Row[{text, Invisible[text]},
"\[NegativeMediumSpace]"]
]&
],
PlotRange -> {Automatic, {0, 10}}, Ticks -> {None, Range[0, 10, 2]},
ImagePadding -> {{20, 0}, {95, 0}}
]
]


This uses the normal axes positioning, but for each label, it creates an object that has the label and an invisible copy of the label side-by-side so that the center of the object is the end of the visible label. (I used a negative space between the objects, because again I think it looks better.) The nice thing about this approach is that the basic idea can be used for labels for ticks on axes that don't otherwise allow specific placements.

-
Much more elegant than my version, +1! My function was built to be used with FrameTicks, not Placed, so I didn't have these options. – Verbeia Oct 16 '14 at 4:10
@Verbeia The second approach should also work with frame ticks. – Brett Champion Oct 16 '14 at 15:47