Silverlight と WPF を対象とする Infragistics XamDataChart では、バインドした項目のプロパティに基づいてマーカーの外観が異なるシリーズを作成できます。
ScatterSeries、RangeColumnSeries などの MarkerSeries で MarkerTemplate プロパティを使用することができます。UI 要素のプロパティが項目の DataContext プロパティにバインドされるカスタム DataTemplate を作成できます。
<DataTemplate x:Key="bubbleTemplate" > <Ellipse Stretch="Fill" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" StrokeThickness="0.5" MinWidth="10" MinHeight="10" Width="{Binding Item.Width}" Height="{Binding Item.Width}"> <ToolTipService.ToolTip> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Item.YValue, StringFormat='Value: {0}'}" /> </StackPanel> </ToolTipService.ToolTip> </Ellipse> </DataTemplate>
RgbValueConverter は、数値を連続色パレットの SolidColorBrush に変換します。
項目の DataContext の値に基づいてマーカーの色を変更する場合があります。値は別のタイプが可能です。値を指定したタイプから特定の色の Brush に変換するために ValueConverter が必要です。
この記事では 数値型から個別の色パレットに変換、または数値型から連続色パレットに変換する 2 種類のコンバーターを紹介します。
サンプル アプリケーションでは Silverlight を対象としています。WPF の XamDataChart を使用すると、同じように WPF アプリケーションを作成できます。
サンプルアプリケーション作成の要件:
ソフトウェア:
- Visual Studio 2010
- NetAdvantage for Silverlight Data Visualization (このサンプルは 2010.2 バージョン) の Infragistics XamMap コンポーネント
作成手順:
Silverlight の場合:
- Silverlight アプリケーションを作成します。
- ValueConverter を作成します。NumberToBrush は数値から個別の色パレットの Brush に変換します。RgbValueConverter は数値から連続色パレットの Brush に変換します。ほとんどのコンポーネントでは Background、Stroke などのプロパティで Brush が使用されます。
- XamDataChart の DataContext で使用されるサンプル データを作成します。
- 丸を表す MarkerTemplate を作成します。色は YValue プロパティにバインドされます。ここでは 2 つのコンバーターを使用します。
- 作成した MarkerTemplate 定義を使用して、散布図シリーズの XamDataChart を作成します。
- サンプル アプリケーションを実行します。
1. Visual Studio 2010 で Silverlight アプリケーションを作成します。
2. 2 つの ValueConverter を追加します。
NumberToBrush は数値 (double 型) を SolidColorBrush に変換します。Brush は個別の色パレットから取得される色です。パレットには 6 つの SolidColorBrush があります。色は白い、赤い、オレンジ、黄色、緑、と青です。パラメーターであるため、範囲があり、コンバーターは数値に相対する SolidColorBrush を返します。値が範囲外にある場合、白い SolidColorBrush を返します。
public sealed class NumberToBrush : IValueConverter { private Brush[] _brushes = new Brush[] { new SolidColorBrush(Colors.White), new SolidColorBrush(Colors.Red), new SolidColorBrush(Colors.Orange), new SolidColorBrush(Colors.Yellow), new SolidColorBrush(Colors.Green), new SolidColorBrush(Colors.Blue)}; #region Property Accessors public Brush[] Brushes { get { return this._brushes; } set { this._brushes = value; } } #endregion #region IValueConverter public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if ((typeof(Brush) != targetType || typeof(double) != value.GetType())) { return null; } Range range = parameter as Range; if(range == null) { range = new Range(); range.Min = 0; range.Max = 10; } var i = (double)value; double interval = (double)(range.Max - range.Min)/(_brushes.Length - 1); int index = (int)(i / interval + 0.5); if (index <= 0 || index >= this._brushes.Length) return this._brushes[0]; return this._brushes[index]; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } public class Range : BaseViewModel { #region Min private int _min; public int Min { get { return this._min; } set { this._min = value; OnPropertyChanged("Min"); } } #endregion // Min #region Max private int _max; public int Max { get { return this._max; } set { this._max = value; OnPropertyChanged("Max"); } } #endregion // Max }
コンバーターは HSV (Hue-Saturation-Value) を使用します。
http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
詳細について、Wikipedia リンクを参照してください。
RgbValueConverter では、数値は Min と Max 値の範囲内で正規化されます。
var normValue = i * 360/(range.Max – range.Min);
RgbValueConverter のコードは以下です。
public sealed class RgbValueConverter : IValueConverter { private static Color ColorFromHsv(double hue, double saturation, double value) { int hi = (int)(Math.Floor(hue / 60)) % 6; double f = hue / 60 - Math.Floor(hue / 60); value = value * 255; int v = (int)(value); int p = (int)(value * (1 - saturation)); int q = (int)(value * (1 - f * saturation)); int t = (int)(value * (1 - (1 - f) * saturation)); if (hi == 0) { return Color.FromArgb(255, (byte)v, (byte)t, (byte)p); } if (hi == 1) { return Color.FromArgb(255, (byte)q, (byte)v, (byte)p); } if (hi == 2) { return Color.FromArgb(255, (byte)p, (byte)v, (byte)t); } if (hi == 3) { return Color.FromArgb(255, (byte)p, (byte)q, (byte)v); } if (hi == 4) { return Color.FromArgb(255, (byte)t, (byte)p, (byte)v); } return Color.FromArgb(255, (byte)v, (byte)p, (byte)q); } #region IValueConverter public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if ((typeof(Brush) != targetType || typeof(double) != value.GetType())) { return null; } Range range = parameter as Range; if(range == null) { range = new Range(); range.Min = 0; range.Max = 10; } var i = System.Convert.ToDouble(value); if (i <= range.Min || range.Min >= range.Max) { return new SolidColorBrush(Colors.White); } var normValue = i * 360/(range.Max - range.Min); return new SolidColorBrush(ColorFromHsv(normValue, 1, 1)); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion }
3. XamDataChart の DataContext で使用されるサンプル データを作成します。
public class BubbleDataCollection : ObservableCollection<BubblePoint> { public BubbleDataCollection() { this.Add(new BubblePoint { XValue = 4, YValue = 10, Width = 30 }); this.Add(new BubblePoint { XValue = 4, YValue = 4, Width = 40 }); this.Add(new BubblePoint { XValue = 8, YValue = 8, Width = 20 }); this.Add(new BubblePoint { XValue = 10, YValue = 1, Width = 50 }); this.Add(new BubblePoint { XValue = 1, YValue = 10, Width = 40 }); } } public class BubblePoint { public double XValue { get; set; } public double YValue { get; set; } public double Width { get; set; } }
<UserControl.Resources> ... <XamDataChartCustomTemplatesDemo:BubbleDataCollection x:Key="bubbleCollection" /> .... <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource bubbleCollection}">
4. 丸を表す MarkerTemplate を作成します。色は YValue プロパティにバインドされます。ここでは 2 つのコンバーターを使用します。
<UserControl.Resources> <Converters:NumberToBrush x:Key="indexToBrush"/> <Converters:RgbValueConverter x:Key="RgbToBrush"/> <XamDataChartCustomTemplatesDemo:BubbleDataCollection x:Key="bubbleCollection" /> <Converters:Range x:Key="range" Min="0" Max="10"/> <DataTemplate x:Key="bubbleTemplate" > <Ellipse Stretch="Fill" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="{Binding Item.YValue, Converter={StaticResource indexToBrush}, ConverterParameter={StaticResource range}}" Stroke="{Binding Series.ActualMarkerOutline}" StrokeThickness="0.5" MinWidth="10" MinHeight="10" Width="{Binding Item.Width}" Height="{Binding Item.Width}"> <ToolTipService.ToolTip> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Item.YValue, StringFormat='Value: {0}'}" /> </StackPanel> </ToolTipService.ToolTip> </Ellipse> </DataTemplate> <DataTemplate x:Key="bubbleTemplate2" > <Ellipse Stretch="Fill" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="{Binding Item.YValue, Converter={StaticResource RgbToBrush}, ConverterParameter={StaticResource range}}" Stroke="{Binding Series.ActualMarkerOutline}" StrokeThickness="0.5" MinWidth="10" MinHeight="10" Width="{Binding Item.Width}" Height="{Binding Item.Width}"> <ToolTipService.ToolTip> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Item.YValue, StringFormat='Value: {0}'}" /> </StackPanel> </ToolTipService.ToolTip> </Ellipse> </DataTemplate> </UserControl.Resources>
MarkerTemplate 定義は BubblePoint オブジェクトの YValue に基づいて Brush で塗りつぶされた楕円を含みます。
5. 作成した MarkerTemplate 定義を使用して、散布図シリーズの XamDataChart を作成します。
<igChart:XamDataChart x:Name="theChart"> <igChart:XamDataChart.Axes> <igChart:NumericXAxis x:Name="xAxis" MinimumValue="0" MaximumValue="15"/> <igChart:NumericYAxis x:Name="yAxis" MinimumValue="0" MaximumValue="15"/> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:ScatterSeries x:Name="scatter" MarkerTemplate="{StaticResource bubbleTemplate}" ItemsSource="{Binding}" XMemberPath="XValue" YMemberPath="YValue" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}"></igChart:ScatterSeries> </igChart:XamDataChart.Series> </igChart:XamDataChart> ... <igChart:XamDataChart x:Name="theChart2"> <igChart:XamDataChart.Axes> <igChart:NumericXAxis x:Name="xAxis2" MinimumValue="0" MaximumValue="15"/> <igChart:NumericYAxis x:Name="yAxis2" MinimumValue="0" MaximumValue="15"/> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:ScatterSeries x:Name="scatter2" MarkerTemplate="{StaticResource bubbleTemplate2}" ItemsSource="{Binding}" XMemberPath="XValue" YMemberPath="YValue" XAxis="{Binding ElementName=xAxis2}" YAxis="{Binding ElementName=yAxis2}"></igChart:ScatterSeries> </igChart:XamDataChart.Series> </igChart:XamDataChart>
6. アプリケーションを実行します。