Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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.

Mathematica graphics

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:

Mathematica graphics

share|improve this question
    
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 at 2:57

5 Answers 5

up vote 10 down vote accepted

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}]

enter image description here

share|improve this answer
    
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 Mar 7 '12 at 13:31
    
I'm sorry to report that this no longer works in Mathematica 10. –  Mr.Wizard Nov 11 at 2:58

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}}
    ]
]

enter image description here

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.

enter image description here

share|improve this answer
    
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 at 4:10
2  
@Verbeia The second approach should also work with frame ticks. –  Brett Champion Oct 16 at 15:47
    
@Brett I have closed this question as a duplicate. (An action you may review if you like.) I would like to know if you think it would be appropriate to merge this question into that one. That will move this answer to that question, possibly increasing visibility and improving site organization, but it will also cost you an "Accept" since a Question cannot have two accepted answers. –  Mr.Wizard Nov 10 at 4:14
1  
@Mr.Wizard: I'm fine with the merge, and its consequences. –  Brett Champion Nov 10 at 18:38
    
@Mr.Wizard Interesting -- I got a Necromancer badge out of the deal. –  Brett Champion Nov 11 at 20:50

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]}, 
  DisplayForm@AdjustmentBox[
      Style[Rotate[#, rads, If[Sign[rads] == 1, {Left, Bottom}, {Right, Top}]], 
       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]

Example using your data:

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

enter image description here

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]

enter image description here

Another example

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

enter image description here

share|improve this answer

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]}

chart

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.

share|improve this answer

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] &
  ]
]

Mathematica graphics

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):

Mathematica graphics

share|improve this answer
    
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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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