Turn your head and check out this post [How to: Easily rotate the axis labels of a Silverlight/WPF Toolkit chart]


This blog has moved to a new location and comments have been disabled.

All old posts, new posts, and comments can be found on The blog of dlaa.me.

See you there!

Comments (46)

  1. sidney26stevens says:

    What are you doing? Do you want to confuse me more? Try a more simple code so we illiterate can understand and use it, eventually.

  2. Delay says:

    sidney26stevens,

    Thanks for the feedback – though I’m not sure I fully understand what you’re asking for. :( Are you suggesting that I should have excerpted away more of the XAML?

    When I wrote this post (admittedly on fairly little sleep!), it seemed nice to have the complete code all there in one place for the taking – and to set everything in full context.

    If you have suggestions for making this sample easier to understand, I’d be happy to hear them. You can contact me via the "Email" link at the top of the sidebar on the right if you’d like.

    Thanks!

  3. gregsy says:

    Delay,

    Thanks for this, it helped it is a very useful example.

    I have an issue when this is used with two column series though; if you put the same code on both ColumnSeries you only get one series, or more correctly one series overlayed on another; they no longer appear side by side.

    I have considered using a template for all column series in the chart but that does not seem to resolve the issue either.

    I am happy to provide a code example if you need further explanation.

    Thanks

  4. Delay says:

    gregsy,

    If you want two ColumnSeries instances to share the same Axis instance, you want to put that Axis in the Chart.Axes collection instead of defining it on each ColumnSeries separately (which I did above to be explicit). I’m not sure this is what you’re seeing, but it sounds a lot like it – please let me know if making that change doesn’t solve your problem.

    Thanks!

  5. gregsy says:

    Thanks Delay,

    When I finally got round to testing it it works a treat.

    For those interested

    Assuming I have a class for Price containing a definition :

     double LitrePrice

     string Date

    The following code

    <Grid>

           <charting:Chart>

               <charting:ColumnSeries

                   Title="Petrol (Litre)"

                   DependentValueBinding="{Binding LitrePrice}"

                   IndependentValueBinding="{Binding Date}"

                   ItemsSource="{StaticResource PetrolCollection}">

               </charting:ColumnSeries>

               <charting:ColumnSeries

                   Title="Diesel (Litre)"

                   DependentValueBinding="{Binding LitrePrice}"

                   IndependentValueBinding="{Binding Date}"

                   ItemsSource="{StaticResource DieselCollection}">

               </charting:ColumnSeries>

               <charting:Chart.Axes>

                   <charting:CategoryAxis Orientation="X">

                       <charting:CategoryAxis.AxisLabelStyle>

                           <Style TargetType="charting:AxisLabel">

                               <Setter Property="Template">

                                   <Setter.Value>

                                       <ControlTemplate TargetType="charting:AxisLabel">

                                           <TextBlock Text="{TemplateBinding FormattedContent}">

                                                   <TextBlock.LayoutTransform>

                                                       <RotateTransform Angle="300"/>

                                                   </TextBlock.LayoutTransform>

                                           </TextBlock>

                                       </ControlTemplate>

                                   </Setter.Value>

                               </Setter>

                           </Style>

                       </charting:CategoryAxis.AxisLabelStyle>

                   </charting:CategoryAxis>

               </charting:Chart.Axes>

           </charting:Chart>    

       </Grid>

    Gives a two series chart with rotated axes.

  6. bhb says:

    Thanks for your post. It helped me a lot. I got your sample working but I now need to create my series for the chart dynamically at runtime depending on user input. Is there a way to do the rotattion in code on a newly created series?

    Another question where you could possible help: When creating my series dynamically the colors are randomly choosen each time for a new series. I need them to be fixed so every time a users sees the same chart with the same entries they should have the same color. I found some old posts that referenced a method that could reset the color selection routine somehow but this was removed from silverlight toolkit …

    I hope you have some advice …

    Anyways thanks for your stuff!

  7. Delay says:

    bhb,

    Anything that can be done in XAML can be done in code. :) It should be relatively straightforward to translate the XAML above into code so that you can use it in your code-only scenario. (While I haven't done so for this example specifically, I have done so for similar examples in the past.)

    Regarding the creation of constant-color Series, the trick is to use the DataPointStyle property to assign a Style directly to each Series you care about that sets the Background property to the Brush you want to be associated with that series. I discuss this in the following post which contains an example of this very thing: blogs.msdn.com/…/chart-tweaking-made-easy-how-to-make-four-simple-color-tooltip-changes-with-silverlight-wpf-charting.aspx

    Hope this helps!

  8. Moni says:

    Hello,

    Is there any style that can shrink or reduce the space between series on a bar graph, so that the bars appear closer together despite being different series?

    Thank you.

  9. Delay says:

    Moni,

    I don't believe there's a way to do that today without subclassing BarSeries. FYI that we have a work item to consider adding a "columns/bars should take X% of the slot size" property that would allow people to change the current default of X=80 – this might eventually let you do what you'd like quite easily.

  10. john simmons says:

    I'm using Silverlight 3, and it claims that LayoutTransform isn't a valid property for the TextBlock control.

    Am I not doing something?  

    Beyond that, it would be handy if you could start posting c# code fas well as the XAML for creating a style like this.

  11. Delay says:

    john simmons,

    If you have a closer look at the post, there's one sample for WPF (where the LayoutTransform property exists) and another sample for Silverlight (where it doesn't and my LayoutTransformer class must be used to simulate it). The error you're getting sounds like you're trying to use the WPF XAML on Silverlight. If you switch to the Silverlight sample and add a reference to the System.Windows.Controls.Layout.Toolkit assembly, you should be set. :)

    Regarding C# vs. XAML, I tend to only post a single way of doing things – and in cases where a XAML-only solution is possible (like this one), I tend to prefer that form. For UI issues, I feel that XAML is a more appropriate language to express things – however, it's all just code and it's usually fairly straightforward to translate XAML into the corresponding code.

    If I had all the time in the world, I might translate my samples into more forms – but because I don't, I usually try to pick the one form that I feel is demonstrates the "best practice". I hope that's helpful!

  12. willCodeForFood says:

    Delay, thanks for the code! I have (I think) done exactly what you have here, except I am using it with a StackedAreaSeries. When I implemented it, the X-axis labels disappeared alltogther. Any ideas?

    Thanks again!

  13. Delay says:

    willCodeForFood,

    Offhand, I don't know why this would change based on the type of the Series… Just for fun, have you tried switching to AreaSeries to see if that gets things working? If not, then the problem's something else and StackedAreaSeries isn't responsible.

  14. Carsten says:

    Is there any way to get dynamic rather than static labels? My charts need to resize depending on the size of the browser, so the labels can end up either much to close or much to far apart. If there is a way to dynamically adjust the number of labels that would solve the issue. So far I have only seen examples where the labels are defined staticly at specific intervals. Rotating the labels helps – just not enough. By the way – dynamically rotating the labels as they get closer together would be cool too…

  15. Delay says:

    Carsten,

    For RangeAxis subclasses (like LinearAxis and DateTimeAxis), the interval is both dynamic and customizable. However, for CategoryAxis (used in this example) that is not the case because the intent is to always show all the category names (which typically can't be inferred as they can for RangeAxis). That said, you might be able to get the effect you're looking for by attaching a handler to the Axis's SizeChanged event and manually toggling the Visibility of some of the CategoryAxis AxisLabels or by rotating them as you desire. This would be a bit of a kludge, but seems like it could be made to work fairly well without too much difficulty. :)

    Hope this helps!

  16. Mattes says:

    Hi,

    your blog was really a great help for me.

    In your post you write about the default behavior of putting to long axis labels into alternating rows. Is there any possibility to disble this behavior?

    Best Regards, Mattes

  17. Delay says:

    Mattes,

    It's great to hear my blog's been helpful! :) Regarding your question of disabling the alternating row behavior, this isn't something that's supported by default, but if you're willing to change the code, it's pretty easy to do. Specifically, if you look at the RenderOriented method in RangeAxis.cs, there are calls to OrientedPanel.SetPriority for each item that's added to the Axis. The last section passes "count+1" which alternates between 1 and 2 – to disable the alternating behavior, just change this value to be 1 all the time.

    Hope this helps!

  18. rams says:

    Delay,

      Thanks for great post. The axis labels are not aligned to X-Axis tick mark / grid lines .. Is it possible to get them aligned to tick marks?

    Thanks

    rams

  19. Delay says:

    rams,

    Thanks for the kind words! The behavior you see is deliberate and "by design" for CategoryAxis. As with Excel, the default gridlines/tick marks of a category axis are used to visually separate the different categories (vs. NumericAxis where they show specific values).

    If you'd like to change this behavior, one handy approach is to use a NumericAxis to simulate a CategoryAxis, just like I do in this post for creating text labels on the DependentAxis: blogs.msdn.com/…/please-rate-your-dining-experience-how-to-show-text-labels-on-a-numeric-axis-with-silverlight-wpf-toolkit-charting.aspx

    Alternatively, you could subclass/modify the CategoryAxis code – though I think that'll be more work than you want to take on – and I'm optimistic you won't need to! :)

  20. rams says:

    Thanks for the reply. I've a Column Series with DateTimeAxis as X-Axis. I'm applying 45 degree rotation to the Axis label. Labels are not aligned to tick mark or center of the bar (column) … I wonder if there is any easy way to do this rather than subclassing DateTimeAxis code.

    Thanks

    rams

  21. Delay says:

    rams,

    Based on what I'm thinking things look like in your scenario, you might be able to get what you want pretty easily by fiddling with the RenderTransformProperty on the element(s) inside the LayoutTransformer default Template. Alternatively, some fixed Padding and/or Margin could be enough to do what you want without having to subclass.

    Good luck!

  22. tje.gaab says:

    Can this be done in codebehind (c#) aswell??

  23. Delay says:

    Thomas Jensen,

    Yes – anything that can be done in XAML can be done in code. It's usually just a matter of translating the XAML into a series of object creations and property sets – the names of which are usually explicit in the XAML (though sometimes hidden behind a ContentPropertyAttribute).

  24. Rachel Martin says:

    Delay,

    I love what you've done here.  I copied it and ended up with a slightly different result, which you can see in my stackoverflow question: stackoverflow.com/…/remove-stagger-in-silverlight-chart-x-axis-labels.  Do you know what I might be doing wrong to get two rows of labels?

  25. Delay says:

    Rachel Martin,

    [I've just posted the following answer on Stack Overflow:]

    The labels above are still wide enough that there's not enough room to fit them all next to each other. You could choose to rotate the text more (which will narrow each label) or make the chart wider (which will provide more room for the labels). If you don't like either of those options, you can also remove the stagger behavior, but it's necessary to modify the Data Visualization code to do so; I explain how here: blogs.msdn.com/…/turn-your-head-and-check-out-this-post-how-to-easily-rotate-the-axis-labels-of-a-silverlight-wpf-toolkit-chart.aspx

    Hope this helps!

  26. Sion says:

    Hi, great post.  Do you know how to achieve the same in code?  I can't seem to find appropriate setters to create a style to match what you've done here.  Thanks

  27. Delay says:

    Sion,

    XAML is code. :) The basic approach is to translate XAML by creating a new object for each new element and assigning it to the relevant property of the parent element. However, Silverlight doesn't expose the necessary infrastructure to allow creating ControlTemplate contents in code. (I assume that's what you're having trouble with.) A reasonable workaround is to put the relevant XAML in a Resources section and load it OR to store it as a string in code and use XamlReader.Load to create it. It's not a perfect solution, but it can be used for a code-only approach.

    Hope this helps!

  28. Tu Ma Y says:

    Great post!!! It's really what I'm looking for! Thanks a lot!

  29. vijay says:

    I tried this on WP 7.

    I could not find the layout transform.

    When I tried the SL3 or SL4 toolkit layout transform all the labels disappeared!

    I am using a web service to get data which I display.

    I tried Transform group which seems to work, but the axes labels are in 2 lines.

    Is this approach correct or should I do something else.

    How can I make the axes come in one line?

    Thanks.

    <charting:ColumnSeries.IndependentAxis>

                               <charting:CategoryAxis

                           Orientation="X">

                                   <charting:CategoryAxis.AxisLabelStyle>

                                   </charting:CategoryAxis.AxisLabelStyle>

                               </charting:CategoryAxis>

                           </charting:ColumnSeries.IndependentAxis>

  30. Delay says:

    vijay,

    LayoutTransformer works well on the phone, too, but isn't part of the Windows Phone Toolkit, so you'll need to get it and reference it separately: blogs.msdn.com/…/your-phone-can-turn-into-a-robot-layouttransformer-works-great-on-the-windows-phone-platform.aspx

    Regarding behavior on Silverlight 4, I'd recommend starting from my sample (which should work correctly) and then tweaking bit by bit it to match your scenario. That should help you get to where you want without too much hassle.

    Hope this helps!

  31. Vijay says:

    David,

    Thanks for your prompt response.

    I used your layout transformer. Works great except for one problem.

    I have 7  labels on the X axis.

    They are rotated but come in alternate rows which you say is the default behaviour.

    How to make them come in 1 row?

    Is it possible to have a seperate color for each column in the column series and for bars in the bar chart?

    Thanks.

  32. Delay says:

    Vijay,

    To see how to remove the alternating behavior, please have a look at the comment stream above – particularly the following comment of mine: blogs.msdn.com/…/turn-your-head-and-check-out-this-post-how-to-easily-rotate-the-axis-labels-of-a-silverlight-wpf-toolkit-chart.aspx

    For custom column/bar colors, please see the following blog post: blogs.msdn.com/…/columns-of-a-different-color-customizing-the-appearance-of-silverlight-charts-with-re-templating-and-mvvm.aspx

  33. Sina says:

    hi

    can i do this with C# code in wpf ?

    i need to create this in wpf with C# code because my program is a dynamic program and ,,,,,

    thanks

  34. Delay says:

    Sina,

    Yes – anything you can do in XAML can be done in code. In this case, it would probably be easiest if the code retrieved the Style instance from the page/application's Resources collection, but if you need to, you can create the entire Style in code as well.

    Hope this helps!

  35. Steve says:

    I've tried a few of the things you shared in this post, but I still fail to understand how I can completely hide the X-Axis labels. The problem is, my LineSeries are created and added via code (not XAML) and it seems like any style property setters won't have any effect in XAML because there's just nothing on the chart yet. Unfortunately, I can't find a way to get that done in C# either…  I'd appreciate any help you may have provide on the topic!

  36. Delay says:

    Steve,

    Something similar to the above should work – as I recall you can set the height of the horizontal axis to 1 (not 0) to achieve this effect easily. I think I did something like that here: blogs.msdn.com/…/peanut-butter-jelly-time-how-to-create-a-pleasing-visual-effect-with-silverlight-wpf-charting.aspx

    This should work just as well in code. Remember that an axis is automatically created if an appropriate one isn't available when a series is added to a chart. So you can either add a suitable axis to begin with and customize it to your liking OR you can add the series and then look through the chart's series collection to find the one that got created and then customize it.

    Hope this helps!

  37. Daniel says:

    On a related, but different note…

    I dont mean to hijack the post but web searches turn up nothing.

    Can we remove the axis labels completely? Or at least hide them from view… make them invisible?

  38. Delay says:

    Daniel,

    I thought I'd blogged about this already, but maybe not. I do what you're asking about here:

    blogs.msdn.com/…/peanut-butter-jelly-time-how-to-create-a-pleasing-visual-effect-with-silverlight-wpf-charting.aspx

    As I recall, you can't set Visibilty=Collapsed, but have to set the Width/Height (depending on the axis) to1 instead.

    Hope that helps!

  39. Daniel says:

    Thanks for the reply.

    I've tried that. Instead of being hidden, the X axis labels just move to the top of the chart.

  40. Delay says:

    Daniel,

    That probably means your axis was in the Chart.Axes collection and wasn't suitable for the series+data. The easiest way to troubleshoot this is to define it via the Series.Independent/DependentAxis properties because that way the series knows it's supposed to use that one and can throw if it's not a good match.

  41. Daniel says:

    Update:

    I figured out how to do it. I assigned the X axis a name in XAML (it didnt have one before).

    Then in the code behind… XAxis.Visibility = System.Windows.Visibility.Hidden;

    Sure enough… it worked.

  42. Truyen says:

    Hi David,

    Thank for the post. Great!

    My case is a little different. I use multichart which inherit from chart to dynamically draw multiple columns on the same chart. It is like the post here blog.thekieners.com/…/databinding-multi-series-charts

    So originally I have this in XAML

    <local:MultiChart x:Name="cd_Metrics_MetricsGraph" Height="465" Width="1140" Background="Black" Visibility="Collapsed" DataContext="{StaticResource VendorMetricsGraphCollectionViewSource}"

                                             SeriesSource="{Binding}" LegendStyle="{StaticResource baseStyle}" FontSize="14" FontWeight="Normal">

                               <local:MultiChart.SeriesTemplate>

                                   <DataTemplate>

                                       <chartingToolkit:ColumnSeries Title="{Binding SerieTitle}" ItemsSource="{Binding GraphValues}" IndependentValueBinding="{Binding GraphDate}" DependentValueBinding="{Binding GraphValue}" Background="Black">

                                       </chartingToolkit:ColumnSeries>

                                   </DataTemplate>

                               </local:MultiChart.SeriesTemplate>

                           </local:MultiChart>

    This just draw multi columns charts just fine.

    The issue I face is the same the problem that you mentioned when you start this post. X axis DateTime labels are overlapping.

    So I try to use your code inside ColumnSeries and the result as:

    Well, with this code, it does rotate the X axis labels but there are other issues come up.

    1. The chart is not multile columns now but One column with each of the series stack on each other

    2. The X axis labels are show up for each of the series not just one generic A axis label

    Do you have any idea how to fix this?

    Thank you

  43. Delay says:

    Truyen,

    Sorry, I'm not familiar enough with how MultiChart works to say why this approach doesn't work well with it. :(

  44. Truyen says:

    Thank David, I'll look it up and post back if I found something.

  45. Truyen says:

    I Think i got it David.

    Here is the code

    <local:MultiChart x:Name="cd_Metrics_MetricsGraph" Height="465" Width="1140" Background="Black" Visibility="Collapsed" DataContext="{StaticResource VendorMetricsGraphCollectionViewSource}"

                                             SeriesSource="{Binding}" LegendStyle="{StaticResource HorizontalLegendStyle}" FontSize="14" FontWeight="Normal" Style="{StaticResource MultiChartStyle}" >

    <local:MultiChart.Axes>

                                   <local:MultiChart.SeriesTemplate>

                                      ……

                                  </local:MultiChart.SeriesTemplate>

                                  <local:MultiChart.Axes>

                                    <chartingToolkit:CategoryAxis Orientation="X">

                                       <chartingToolkit:CategoryAxis.AxisLabelStyle>

                                       </chartingToolkit:CategoryAxis.AxisLabelStyle>

                                   </chartingToolkit:CategoryAxis>

                               </local:MultiChart.Axes>

    </local:MultiChart>