Since we are in process of evaluation and till now we have been pretty pleased with Infragistics.
One of the serious requirement we have is have a column range chart whereas each column is rendered over a range(just the two values, high and low)
Also can we have the same chart along with line chart on same chart area?
thanks
-S
The XamDataChart has a RangeColumnSeries that can be plotted along with a LineSeries. Can that work for your purposes? Or do you need to use the XamChart in this situation?
-Graham
Graham,
Thanks for your responding. To be precise I was looking for graph like
As you can see it has column series with a range for each column. I could find similar functionality available in syncfusion but can't find any info on infragistic one
You should be able to implement that will a RangeColumnSeries and a RangeAreaSeries in the XamDataChart. It does not provide you with the number annotations out the box, but you can display them in a tooltip, or use other methods.
I really can't find a way to display these text labels. This is very important for us from end user perspective. Any help would be highly appreciated
I'll see if I can give you some sort of assistance in this regard.
It wouldn't be sufficient to display them in a tooltip? They should be persistent next to the columns?
I would also recommend making a feature request for the label display next to the columns, as any solution I provide will likely be more complicated than it would be if it were a native feature of the chart.
Here, this should give you a start on how you might accomplish this:
<Window.Resources> <local:TestData x:Key="data" /> <DataTemplate x:Key="hiloMarker"> <local:HiLowMarker Context="{Binding}" HighMemberPath="High" LowMemberPath="Low"/> </DataTemplate> </Window.Resources> <Grid x:Name="LayoutRoot" Background="White"> <igChart:XamDataChart x:Name="theChart" VerticalZoomable="True" HorizontalZoomable="True"> <igChart:XamDataChart.Axes> <igChart:NumericYAxis x:Name="yAxis" MinimumValue="0" MaximumValue="8" /> <igChart:CategoryXAxis x:Name="xAxis" ItemsSource="{StaticResource data}" Label="{}{Label}"/> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:RangeColumnSeries x:Name="series" MarkerType="Circle" MarkerTemplate="{StaticResource hiloMarker}" ItemsSource="{StaticResource data}" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" LowMemberPath="Low" HighMemberPath="High" > <igChart:RangeColumnSeries.ToolTip> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Text="High:" /> <TextBlock Text="{Binding Item.High}" Grid.Column="1" /> <TextBlock Text="Low:" Grid.Row="1"/> <TextBlock Text="{Binding Item.Low}" Grid.Row="1" Grid.Column="1" /> </Grid> </igChart:RangeColumnSeries.ToolTip> </igChart:RangeColumnSeries> </igChart:XamDataChart.Series> </igChart:XamDataChart>
And code behind:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class TestData : ObservableCollection<TestDataItem> { public TestData() { Add(new TestDataItem() { Label = "A", Low = 1, High = 3 }); Add(new TestDataItem() { Label = "B", Low = 2, High = 3 }); Add(new TestDataItem() { Label = "C", Low = 1, High = 3 }); Add(new TestDataItem() { Label = "D", Low = 2, High = 4 }); } } public class TestDataItem { public string Label { get; set; } public double Low { get; set; } public double High { get; set; } } public class HiLowMarker : ContentControl { public static readonly DependencyProperty ContextProperty = DependencyProperty.Register("Context", typeof(DataContext), typeof(HiLowMarker), new PropertyMetadata(null, (o, e) => (o as HiLowMarker) .OnContextChanged(e.OldValue, e.NewValue))); public DataContext Context { get { return (DataContext)GetValue(DataContextProperty); } set { SetValue(DataContextProperty, value); } } public static readonly DependencyProperty HighProperty = DependencyProperty.Register("High", typeof(double), typeof(HiLowMarker), new PropertyMetadata(0.0, (o, e) => (o as HiLowMarker) .OnHighChanged((double)e.OldValue, (double)e.NewValue))); private void OnHighChanged(double oldValue, double newValue) { UpdateContent(); } public double High { get { return (double)GetValue(HighProperty); } set { SetValue(HighProperty, value); } } public static readonly DependencyProperty LowProperty = DependencyProperty.Register("Low", typeof(double), typeof(HiLowMarker), new PropertyMetadata(0.0, (o, e) => (o as HiLowMarker) .OnLowChanged((double)e.OldValue, (double)e.NewValue))); private void OnLowChanged(double oldValue, double newValue) { UpdateContent(); } public double Low { get { return (double)GetValue(LowProperty); } set { SetValue(LowProperty, value); } } public static readonly DependencyProperty LowMemberPathProperty = DependencyProperty.Register("LowMemberPath", typeof(string), typeof(HiLowMarker), new PropertyMetadata(null, (o, e) => (o as HiLowMarker) .OnLowMemberPathChanged((string)e.OldValue, (string)e.NewValue))); private void OnLowMemberPathChanged(string oldValue, string newValue) { UpdateContent(); } public string LowMemberPath { get { return (string)GetValue(LowMemberPathProperty); } set { SetValue(LowMemberPathProperty, value); } } public static readonly DependencyProperty HighMemberPathProperty = DependencyProperty.Register("HighMemberPath", typeof(string), typeof(HiLowMarker), new PropertyMetadata(null, (o, e) => (o as HiLowMarker) .OnHighMemberPathChanged((string)e.OldValue, (string)e.NewValue))); private void OnHighMemberPathChanged(string oldValue, string newValue) { UpdateContent(); } public string HighMemberPath { get { return (string)GetValue(HighMemberPathProperty); } set { SetValue(HighMemberPathProperty, value); } } public static readonly DependencyProperty ItemProperty = DependencyProperty.Register("Item", typeof(object), typeof(HiLowMarker), new PropertyMetadata(null, (o, e) => (o as HiLowMarker) .OnItemChanged((object)e.OldValue, (object)e.NewValue))); private void OnItemChanged(object oldValue, object newValue) { UpdateContent(); } public object Item { get { return (object)GetValue(ItemProperty); } set { SetValue(ItemProperty, value); } } private XamDataChart watchingChart = null; private void UpdateContent() { if (!Valid()) { return; } UpdateHandlers(); SetBinding(ItemProperty, new Binding("Context.Item") { Source = this }); SetBinding(HighProperty, new Binding("Context.Item." + HighMemberPath) { Source = this }); SetBinding(LowProperty, new Binding("Context.Item." + LowMemberPath) { Source = this }); if (!double.IsNaN(Low) && !double.IsNaN(High) && !double.IsInfinity(Low) && !double.IsInfinity(High)) { var rangeSeries = Context.Series as RangeCategorySeries; var viewport = new Rect( 0, 0, rangeSeries.ActualWidth, rangeSeries.ActualHeight); double scaledLow = rangeSeries.YAxis.GetScaledValue(Low, rangeSeries.Chart.WindowRect, viewport); double scaledHigh = rangeSeries.YAxis.GetScaledValue(High, rangeSeries.Chart.WindowRect, viewport); double mid = (scaledLow + scaledHigh) / 2.0; scaledLow += 10; scaledHigh -= 10; Grid grid = new Grid(); TextBlock tbHigh = new TextBlock() { Text = High.ToString(), RenderTransform = new TranslateTransform() { Y = scaledHigh - mid } }; TextBlock tbLow = new TextBlock() { Text = Low.ToString(), RenderTransform = new TranslateTransform() { Y = scaledLow - mid } }; grid.Children.Add(tbHigh); grid.Children.Add(tbLow); Content = grid; } } private void UpdateHandlers() { if (watchingChart != null) { watchingChart.WindowRectChanged -= watchingChart_WindowRectChanged; watchingChart.SizeChanged -= watchingChart_SizeChanged; watchingChart = null; } if (Context.Series.Chart != null) { watchingChart = Context.Series.Chart; watchingChart.WindowRectChanged += watchingChart_WindowRectChanged; watchingChart.SizeChanged += watchingChart_SizeChanged; } } void watchingChart_SizeChanged(object sender, SizeChangedEventArgs e) { UpdateContent(); } void watchingChart_WindowRectChanged(object sender, Infragistics.RectChangedEventArgs e) { UpdateContent(); } private bool Valid() { if (HighMemberPath == null) { return false; } if (LowMemberPath == null) { return false; } if (Context == null) { return false; } if (Context.Series == null) { return false; } if (Context.Series as RangeCategorySeries == null) { return false; } if ((Context.Series as RangeCategorySeries).YAxis == null) { return false; } return true; } private void OnContextChanged(object oldValue, object newValue) { ClearContent(); UpdateContent(); } private void ClearContent() { Content = null; } }
Hope this helps!-Graham
You don't need to do anything quite so complicated to place text above a normal column series. This marker template should do:
<DataTemplate x:Key="textAboveMarker"> <Grid> <TextBlock Text="{Binding Item.Value}"> <TextBlock.RenderTransform> <TranslateTransform Y="-10" /> </TextBlock.RenderTransform> </TextBlock> </Grid> </DataTemplate>
not yet, but I notice you are using it with column series and it was designed for the range series, as per the original topic of the conversation. To use with regular column, it would need a few adjustments, I warrant. Will try to look at your sample as soon as I'm able.
Did you get a chance to take a look at the sample?
Thanks for the solution, was trying this solution on column series but it seems numbers are NOT correctly aligned i.e. either number show too close to upper bar or too far off.
Here is the sample code
<Window.Resources>
<local:TestData x:Key="data" />
<DataTemplate x:Key="hiloMarker">
<local:HiLowMarker
Context="{Binding}"
ValueMemberPath="Value"/>
</DataTemplate>
</Window.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<ig:XamDataChart x:Name="theChart" VerticalZoomable="True" HorizontalZoomable="True" Width="400" Height="300">
<ig:XamDataChart.Axes>
<ig:NumericYAxis x:Name="yAxis" ReferenceValue="0" />
<ig:CategoryXAxis
x:Name="xAxis"
ItemsSource="{StaticResource data}"
Label="{}{Label}"/>
</ig:XamDataChart.Axes>
<ig:XamDataChart.Series>
<ig:ColumnSeries
x:Name="series"
MarkerType="Circle"
MarkerTemplate="{StaticResource hiloMarker}"
XAxis="{Binding ElementName=xAxis}"
YAxis="{Binding ElementName=yAxis}"
ValueMemberPath="Value" >
</ig:ColumnSeries>
</ig:XamDataChart.Series>
</ig:XamDataChart>
</Grid>
Code Behind :
public class TestData : ObservableCollection<TestDataItem>
{
public TestData()
Add(new TestDataItem()
Label = "A",
Value = 3
});
Label = "B",
Value = 5
Label = "C",
Value = 6
Label = "D",
Value = 4
}
public class TestDataItem
public string Label { get; set; }
public double Value { get; set; }
public class HiLowMarker : ContentControl
public static readonly DependencyProperty ContextProperty =
DependencyProperty.Register("Context",
typeof(DataContext), typeof(HiLowMarker),
new PropertyMetadata(null, (o, e) => (o as HiLowMarker)
.OnContextChanged(e.OldValue, e.NewValue)));
public DataContext Context
get { return (DataContext)GetValue(DataContextProperty); }
set { SetValue(DataContextProperty, value); }
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value",
typeof(double), typeof(HiLowMarker),
new PropertyMetadata(0.0, (o, e) => (o as HiLowMarker)
.OnValueChanged((double)e.OldValue, (double)e.NewValue)));
private void OnValueChanged(double oldValue, double newValue)
UpdateContent();
public double Value
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
public static readonly DependencyProperty ValueMemberPathProperty =
DependencyProperty.Register("ValueMemberPath", typeof(string), typeof(HiLowMarker), new PropertyMetadata(null, (o, e) => (o as HiLowMarker)
.OnValueMemberPathChanged((string)e.OldValue, (string)e.NewValue)));
private void OnValueMemberPathChanged(string oldValue, string newValue)
public string ValueMemberPath
get { return (string)GetValue(ValueMemberPathProperty); }
set { SetValue(ValueMemberPathProperty, value); }
public static readonly DependencyProperty ItemProperty = DependencyProperty.Register("Item", typeof(object), typeof(HiLowMarker),
new PropertyMetadata(null, (o, e) => (o as HiLowMarker).OnItemChanged((object)e.OldValue, (object)e.NewValue)));
private void OnItemChanged(object oldValue, object newValue)
public object Item
get { return (object)GetValue(ItemProperty); }
set { SetValue(ItemProperty, value); }
private XamDataChart watchingChart = null;
private void UpdateContent()
if (!Valid())
return;
UpdateHandlers();
SetBinding(ItemProperty,
new Binding("Context.Item")
Source = this
SetBinding(ValueProperty,
new Binding("Context.Item." + ValueMemberPath)
if (!double.IsNaN(Value) && !double.IsInfinity(Value))
var rangeSeries = Context.Series as ColumnSeries;
var viewport =
new Rect(
0, 0,
rangeSeries.ActualWidth,
rangeSeries.ActualHeight);
double scaledLow = 0;
double scaledHigh = rangeSeries.YAxis.GetScaledValue(Value, rangeSeries.Chart.WindowRect, viewport);
double mid = (scaledLow + scaledHigh) / 2.0;
scaledLow += 10;
scaledHigh -= 10;
Grid grid = new Grid();
TextBlock tbHigh = new TextBlock()
Text = Value.ToString(),
RenderTransform =
new TranslateTransform()
Y = scaledHigh - mid
};
grid.Children.Add(tbHigh);
Content = grid;
private void UpdateHandlers()
if (watchingChart != null)
watchingChart.WindowRectChanged -= watchingChart_WindowRectChanged;
watchingChart.SizeChanged -= watchingChart_SizeChanged;
watchingChart = null;
if (Context.Series.Chart != null)
watchingChart = Context.Series.Chart;
watchingChart.WindowRectChanged += watchingChart_WindowRectChanged;
watchingChart.SizeChanged += watchingChart_SizeChanged;
void watchingChart_SizeChanged(object sender, SizeChangedEventArgs e)
void watchingChart_WindowRectChanged(object sender, Infragistics.RectChangedEventArgs e)
private bool Valid()
if (ValueMemberPath == null)
return false;
if (Context == null)
if (Context.Series == null)
return true;
private void OnContextChanged(object oldValue, object newValue)
ClearContent();
private void ClearContent()
Content = null;
produces result: