This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
I need to be able to label chart data points with text other than the data values. For example, in an X-Y scatter series add a labels that identify the observations with text that I can specify. Is there some way to accomplish this? I was thinking maybe the DataLabel/DataLabelStyle were a possibility, but I can't find much information on them. Also I would also like to be able to specify a tool-tips for individual points or and for series. Is there any way to accomplish this? Thanks. Peter |
|
|
Hello Peter You can customize the appearance of data labels using the DataLabelStyle property of the series. Within the style, you should set the Template property to be a ControlTemplate containing the visual elements that you want to display. In this template, you can use a binding to the DataPoint property which gives you access to information stored in that data point. Below is a simple example of a custom data label style:
To display custom text in you data label, you will need to start by creating a custom data class. This could simply have an X, Y and Text property. Instances of this class will represent individual data points that the chart displays. You can fill the ItemsSource of the scatter series to be instances of this class. Make sure to set the XBinding and YBinding properties of the series to point to the X and Y properties of your custom data points. Then in the custom data label style, you can use {Binding DataPoint.DataContext.Text, ...} to display the custom text property in the label. You can create custom chart symbol styles to add tool tips to the data points. Take a look at the CustomChartSymbols page in the ChartingSampleExplorer demo. This has examples of how to create custom chart symbols. You could set a tool tip to the root visual of a custom chart symbol. Similarly, if you want to set a tool tip on the line in a line series for example, you can create a custom line style, set the ToolTip property of the path, and then use this custom line style to set the LineStyle property of a line series. Please let us know if you need more help with this. - Jason |
|
|
Hi Jason, Thanks for the response, which is clear and works. However, I am finding it a bit difficult to adapt this method to our scenario where I am setting up the charts in code. I am working on a "report designer" component where the main program (a Windows Forms program in the initial application) makes a wide variety of data available to out report designer through an interface, and the user creates reports by selecting from the available data and inserting tables, charts, text, pictures, etc. We bind the X and Y values for chart series in code, such as: chartSeries.XBinding = PxWpfBindingUtils.SetupBinding(xProperty); chartSeries.YBinding = PxWpfBindingUtils.SetupBinding(yProperty); This has given us great flexibility because xProperty and yProperty can be the name of a CLR property, a dependency property, a null (indicating to bind directly to the item), or a property descriptor (subclass of PropertyDescriptor). In particular we have found that property descriptors gives us almost unlimited flexibility because just by overriding the "GetValue" (usually one line) we can access data in practically any form, or calculate values on the fly in the property descriptor (or more likely with a delegate passed to the property descriptor). Now it would be nice to be able to use property descriptors to access the label text or tooltip as well, but I can't see how to do it in a LabelStyle template. For one thing the DataLabel (or DataPoint) does not seem to have access to the ChartSeries that is being labeled. I think I would have to provide different LabelStyle templates for each series I want to label, which would be very difficult to set up in code. I am also not sure how to specify the property (probably a property descriptor) that provides the label in XAML, though I am thinking I could probably do it with a markup extension (if there was a way to determine the ChartSeries for the DataLabel, and I attached a LabelBinding property to the ChartSeries). Maybe I am not thinking correctly here--I am not a WPF expert. Anyway, it occurs to me that this would be a piece of cake if the ChartSeries had a properties like LabelBinding and ToolTipBinding. I am guessing I am not the only one that would like the ability to easily specify labels and tooltips, and it is totally consistent with how the X and Y values are provided. What do you think? Peter |
|
|
Hello Peter, sorry for the late reply. To help me fully understand your scenario, could you please explain what sort of text you are wanting to display in the labels, and where you want to store this text in your data model. The easiest way I've found is to include the text in a custom data point model, and then use the custom template to display the text. I should be able to let data points and data labels have access to the series that created them if you still need this, but I don't plan to implement the LabelBinding or ToolTipBinding properties. Cheers - Jason |
|
|
Hi Jason, Thanks for looking at this problem. I made a demo project (inserted below). The demo creates two models--the first using the flexible approach we prefer to be able to use, and the second the "conventional" approach. I wrote a lot of comments in the code that hopefully will make things clear. The labels are displayed correctly only for the conventional approach. However, this depends on me knowing the name of the property that provides the labels at design time so I can put it in the template (or I have to repackage the data--don't like that). Anyway, I still think a LabelBinding property would be nice, but I think I could make do with the chart series being accessible from the DataPoints (this is probably more generally useful than putting it on the DataLabel). Peter Here is the main window xaml
And here is the code behind
using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Media; using Mindscape.WpfElements.Charting; namespace LabelsTest
{
///
} |
|
|
Hi Jason, I did figure out a somewhat messy workaround. For each series I create an new DataLable style (in C#) that is based a style supplied in XAML. The new style adds a single setter that sets a "LabelProperty" attached property (a PropertyDescriptor) on the DataLabel. The Text binding on the base style is Text="{Binding RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource DataLabelToLabelTextConverter}}" and the converter gets the attached label property from the DataLabel and calls the GetValue on the property descriptor to get the label text. This works, but may be inefficient since it sets an attached property value on every single data label. It is also screwy. I still think the other solutions I suggested would be much nicer, but I can live with this if I have to. Then anybody could easily assign any labels they wanted. Peter |
|
|
Hi Jason, I did figure out a somewhat messy workaround. For each series I create an new DataLable style (in C#) that is based a style supplied in XAML. The new style adds a single setter that sets a "LabelProperty" attached property (a PropertyDescriptor) on the DataLabel. The Text binding on the base style is Text="{Binding RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource DataLabelToLabelTextConverter}}" and the converter gets the attached label property from the DataLabel and calls the GetValue on the property descriptor to get the label text. This works, but may be inefficient since it sets an attached property value on every single data label. It is also screwy. I still think the other solutions I suggested would be much nicer, but I can live with this if I have to. Then anybody could easily assign any labels they wanted. Peter |
|
|
Hello Peter Just letting you know I am looking into this request now. -Jason |
|
|
Hello Peter The next nightly builds (available from around 1200GMT) will include a DataSeries.LabelBinding property. Now you can set labels using any kind of binding technique that you need. Setting this property will result in the DataPoint.LabelContent property being set. This property can be any object. You will still need to create a custom data label style to define how you want the label data to be displayed, but now all you need to do is bind to the DataPoint.LabelContent property like this:
I have also implemented the CartesianDataPoint.DataSeries and PieSlice.PieSeries properties so that the data points have access to the series that created them. Just in case you still need this. Try this out when the next nightly builds are available and let me know if anything needs to be revised. -Jason |
|
|
Hi Jason, This is great news. Thank you! I haven't been able to try it yet because I have had to work on something else for a bit, but it sounds like exactly what I asked for. I hope other Mindscape users find it useful too. Peter |
|
|
Hi Jason, I have been away from this stuff for a while, but now I am back and have found that this solution does work great. Thanks again! I did run into one issue that puzzled me for a bit, though once I figured it out (by stepping through your source code, which we purchased) I easily resolved the issue with a simple change to my code. However, I thought I would bring it to you attention to see what you think about it. I have sometimes been using value types (usually ints or doubles) as my "items" that are assigned to the ItemsSource, which works well with my PropertyDescriptors that I use for bindings, and has worked fine (until now) with your chart control. One advantage to this approach is I can have a kind of "virtual" items source that does not actually bother to store the data items, but just needs a beginning value, an increment, and a count, and then calculates the values as requested. I have found this useful in function plotting, for example. Anyway I found that when I used such value types for my data source my custom data labels did not show up. Initially it appeared that the DataPoint.LabelContent property values were not set properly, but then I found that the LabelContent was being set, but the DataLabels were getting a new data point that did not have LabelContent set. This is because a reference equals (==) comparison is being used in DataSeries.GetDataPoint on different boxed copies of the same data item, so the equality test fails, so it returns a null, so PointSeriesBase.AddDataLabel makes a new data point, rather than using the existing one with LabelContent set. My fix was to box the value types myself. I am just wondering whether or not you think the graph should be able to work with value types as data items. If so, then maybe this reference equals comparison should be modified for value types. Peter |
|
|
Hello Peter Thanks for bringing this to our attention! The chart control is supposed to have support for value types, but seems there was a bug. I tried out something similar to what you described - filling the chart with ints, and reproduced the issue. Changing the equals comparison to support value types did not solve the issue though. I have solved the issue in some other way which can be downloaded through the next nightly builds. It successfully resolves the issue in the repro I made, but let me know how it goes at your end. -Jason |
|
|
Hi Jason, I find that the fix you implemented did not resolve the issue for me. However, I see in the updated source code that you implemented the fix I suggested, then commented it out. When I uncommented this fix it does work fine. In DataSeries.GetDataPoint: from: if (data == o)// || (data != null && NumericalUtils.IsPrimitiveNumerical(data) && data.Equals(o))) to: if (data == o || (data != null && NumericalUtils.IsPrimitiveNumerical(data) && data.Equals(o))) Therefore I think this fix is good. Was there another problem with it? One minor quibble: I am not sure why you would use the IsPrimitiveNumerical(data) instead of something like data.GetType().IsValueType--then it would have a better chance of working with more complex value types so long as an adequate Equals has been implemented, but either one works for me. Peter |
|
|
Hello Peter Good to hear that the commented fix does the trick. There was nothing wrong with it, it just didn't seem to effect anything in the repro I made. I have added it back in and used IsValueType instead of the IsPrimitiveNumerical method. This will be in the next nightly builds. -Jason |
|