none
WPF toolkit Chartについての質問いくつか RRS feed

  • 質問

  • いくつかまとめて質問させて頂きます

    もともとは、グラフで、Y軸のある値を境に背景色を変えたいというのがありました(例えば、100点満点のテストで90点以上は優秀で緑、その下は黄色、30点未満は赤点で背景を赤にするなど…というのを、グラフの背景でやりたいのです。軸の数字を見なくてもパッとある境目より上か下かわかる感じで)。

    質問① 上記のようなことは、グラフエリア内だけでする方法はあるのでしょうか? もしありましたら教えてください。

    とりあえず、質問①の方法は自力で見つけられなかったので、強引に、縦方向のグラデーションブラシを背景に設定して、境目のところで急激に色を変化させるという方法を考えました。ChartのControlTemplateでBorderBrushにLinearGradientBrushを使う方法です。

    ところがこの方法だと、純粋なグラフエリア本体だけでなく、目盛や上下までが、このブラシで塗られてしまうため、グラフエリアの背景だけを塗りたいという元々やりたいものと少し違ってしまいますし、また、GradientStopのOffset設定も、単純に最低値と最高値の間のどこに当たるかという計算から出すことができず、上下の空白まで含んだOffsetを出すことが必要になりますし、グラフの上下のところは、Window自体の背景色で塗るようLinearGradientBrushに含める必要が出てきます。

    質問② 上下左右の目盛や空白部分を含めず、純粋にグラフエリアの背景だけにBrushは設定できないでしょうか? もしできるのでしたら、やり方を教えてください(Webであちこち見ても、グラフの外側まで一緒に塗られてしまっているサンプルしか見つかりませんでした)。

    とりあえず、質問②の方法もわからないので、グラフの外側も一緒に塗る方法でやっているのですが、これだと当然、純粋なグラフエリアの縦サイズと、Window全体の比率が変わってしまうと、GradientStopの位置もずれてしまい、本来は30点以下を赤に塗りたいのに、それが25とか35にずれてしまったりします。

    そこで、Windowの縦サイズはユーザーが変更できないように固定にしたのですが、ここでまた別の問題が出てしまいました。

    X軸は日付にしているのですが、これが、横方向を何日分持つかによって、

    のように、一行の中に全て入る場合と

    のように、互い違いに二行で表示される場合があります。

    これで目盛であるAxis自体の高さが変わってしまうと、Window全体に対してのグラフエリアの比率が変わってしまうため、GradientStopのOffset値もずれてしまうのです。

    とりあえずは、AxisのHeightを、Autoから、2行分の固定値に変えたところ、一行の場合でも二行分の高さを確保して、グラフエリアもずれなくはなりましたが、今度は、全てが一行で表示されるようになってしまいました。

    そこで、Heightの代わりに、MinHeight=2行分固定値 として設定したところ、高さは1行でも2行でも固定のまま、場合により1行、2行と表示させるーれるようになりました(この挙動も原理がよくわかりませんが)

    しかし、2行分のところに1行しか表示されないと、なにか間延びした感じがしますし、正直、1行表示は横の感覚が詰まり過ぎている感じなので、できれば、常時2行で表示したいのです。というわけで

    質問③常に2行に互い違いに表示できないでしょうか?

    2012年2月7日 23:37

回答

  • 直接的な回答ではありませんが、サードパーティー製のチャートを使うのもいいかも知れません。

    Infaragistics 社の NetAdvantage for WPF に含まれている XamDataChart はかなり強力で、非常に細かい設定が可能です。
    トライアル版をダウンロード~インストール後、「サンプルブラウザー」を起動し XamDataChart のサンプルを展開すると 60個以上のサンプルが提示されています。私はまだ使ったことがないので何とも言えませんが、今回の質問内容を解決できる機能が含まれているかも知れません。


    また

    > 質問② 上下左右の目盛や空白部分を含めず、純粋にグラフエリアの背景だけにBrushは設定できないでしょうか? もしできるのでしたら、やり方を教えてください(Webであちこち見ても、グラフの外側まで一緒に塗られてしまっているサンプルしか見つかりませんでした)。

    値によってマーカーの色を変えたいとの要望と思われますが、上記 XamDataChart の実装例が公開されてます。

    http://forums.jp.infragistics.com/forums/t/1640.aspx


    ひらぽん http://d.hatena.ne.jp/hilapon/


    2012年2月8日 2:37
    モデレータ
  • 質問②ですが、グラフのプロットエリアの背景色を指定する方法があります。
    あとは、GradientStopで色を区切ってみてはどうでしょう。

    <Window x:Class="wpf.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:ToolKit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <ToolKit:Chart>
                <ToolKit:Chart.Axes>
                    <ToolKit:LinearAxis Orientation="Y" Maximum="100" Minimum="0"/>
                    <ToolKit:LinearAxis Orientation="X" Maximum="100" Minimum="0"/>
                </ToolKit:Chart.Axes>
                <!--プロットリアの背景を白表示-->
                <ToolKit:Chart.PlotAreaStyle>
                    <Style TargetType="Panel">
                        <Setter Property="Background" Value="White"></Setter>
                    </Style>
                </ToolKit:Chart.PlotAreaStyle>
            </ToolKit:Chart>
        </Grid>
    </Window>

    • 編集済み せれ 2012年2月8日 9:44
    • 回答としてマーク minami259 2012年2月9日 5:11
    2012年2月8日 9:42
  • Chartコントロールは使い方がよくわかんないです。
    AreaSeriesでそれっぽく色分けしたり。

    <kit:Chart x:Name="chart">
        <kit:Chart.Series>
            <kit:AreaSeries IndependentValuePath="X" DependentValuePath="Y" x:Name="Q1">
                <kit:AreaSeries.ItemsSource>
                    <PointCollection>
                        <Point>0,100</Point>
                        <Point>5,100</Point>
                    </PointCollection>
                </kit:AreaSeries.ItemsSource>
            </kit:AreaSeries>
    
            <kit:AreaSeries IndependentValuePath="X" DependentValuePath="Y" x:Name="Q2">
                <kit:AreaSeries.ItemsSource>
                    <PointCollection>
                        <Point>0,90</Point>
                        <Point>5,90</Point>
                    </PointCollection>
                </kit:AreaSeries.ItemsSource>
            </kit:AreaSeries>
    
            <kit:AreaSeries IndependentValuePath="X" DependentValuePath="Y" x:Name="Q3" >
                <kit:AreaSeries.ItemsSource>
                    <PointCollection>
                        <Point>0,30</Point>
                        <Point>5,30</Point>
                    </PointCollection>
                </kit:AreaSeries.ItemsSource>
            </kit:AreaSeries>
    
            <kit:LineSeries DependentValuePath="Y" IndependentValuePath="X">
                <kit:LineSeries.ItemsSource>
                    <PointCollection>
                        <Point>1,10</Point>
                        <Point>2,20</Point>
                        <Point>3,30</Point>
                        <Point>4,40</Point>
                    </PointCollection>
                </kit:LineSeries.ItemsSource>
    
                <kit:DataPointSeries.DataPointStyle>
                    <Style TargetType="{x:Type kit:LineDataPoint}">
                        <Setter Property="Template" Value="{x:Null}"/>
                        <Setter Property="Background" Value="Black"/>
                    </Style>
                </kit:DataPointSeries.DataPointStyle>
            </kit:LineSeries>
        </kit:Chart.Series>
    </kit:Chart>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
    
            chart.SizeChanged += new SizeChangedEventHandler(chart_SizeChanged);
        }
    
        void chart_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Path p= Find<Path>(Q1);
            if (p != null)
            {
                p.Fill = Brushes.Green;
            }
            p = Find<Path>(Q2);
            if (p != null)
            {
                p.Fill = Brushes.Yellow;
            }
            p = Find<Path>(Q3);
            if (p != null)
            {
                p.Fill = Brushes.Red;
            }
    
            //Point p1 = Q1.PointToScreen(new Point(0, 0));
            //Point p2 = Q1.PointToScreen(new Point(Q1.ActualWidth,Q1.ActualHeight ));
            
            //p1 =cvs.PointFromScreen(p1);
            //p2 = cvs.PointFromScreen(p2);
    
            //Canvas.SetLeft(grid, p1.X);
            //Canvas.SetTop(grid,p1.Y);
            //grid.Width = p2.X - p1.X;
            //grid.Height = p2.Y - p1.Y;
        }
    
        private static T Find<T>(DependencyObject dpo) where T : DependencyObject 
        {
            T t = dpo as T;
            if (t != null)
            {
                return t;
            }
            int count = VisualTreeHelper.GetChildrenCount(dpo);
            for (int i = 0; i < count; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(dpo, i);
                T tx = Find<T>(child);
                if (tx != null)
                {
                    return tx;
                }
            }
            return null;
        }
    }
    #SeriesのClipが枠っぽいけどハミ出るなぁ

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク minami259 2012年2月9日 5:11
    2012年2月8日 11:27

すべての返信

  • 直接的な回答ではありませんが、サードパーティー製のチャートを使うのもいいかも知れません。

    Infaragistics 社の NetAdvantage for WPF に含まれている XamDataChart はかなり強力で、非常に細かい設定が可能です。
    トライアル版をダウンロード~インストール後、「サンプルブラウザー」を起動し XamDataChart のサンプルを展開すると 60個以上のサンプルが提示されています。私はまだ使ったことがないので何とも言えませんが、今回の質問内容を解決できる機能が含まれているかも知れません。


    また

    > 質問② 上下左右の目盛や空白部分を含めず、純粋にグラフエリアの背景だけにBrushは設定できないでしょうか? もしできるのでしたら、やり方を教えてください(Webであちこち見ても、グラフの外側まで一緒に塗られてしまっているサンプルしか見つかりませんでした)。

    値によってマーカーの色を変えたいとの要望と思われますが、上記 XamDataChart の実装例が公開されてます。

    http://forums.jp.infragistics.com/forums/t/1640.aspx


    ひらぽん http://d.hatena.ne.jp/hilapon/


    2012年2月8日 2:37
    モデレータ
  • 質問②ですが、グラフのプロットエリアの背景色を指定する方法があります。
    あとは、GradientStopで色を区切ってみてはどうでしょう。

    <Window x:Class="wpf.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:ToolKit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <ToolKit:Chart>
                <ToolKit:Chart.Axes>
                    <ToolKit:LinearAxis Orientation="Y" Maximum="100" Minimum="0"/>
                    <ToolKit:LinearAxis Orientation="X" Maximum="100" Minimum="0"/>
                </ToolKit:Chart.Axes>
                <!--プロットリアの背景を白表示-->
                <ToolKit:Chart.PlotAreaStyle>
                    <Style TargetType="Panel">
                        <Setter Property="Background" Value="White"></Setter>
                    </Style>
                </ToolKit:Chart.PlotAreaStyle>
            </ToolKit:Chart>
        </Grid>
    </Window>

    • 編集済み せれ 2012年2月8日 9:44
    • 回答としてマーク minami259 2012年2月9日 5:11
    2012年2月8日 9:42
  • Chartコントロールは使い方がよくわかんないです。
    AreaSeriesでそれっぽく色分けしたり。

    <kit:Chart x:Name="chart">
        <kit:Chart.Series>
            <kit:AreaSeries IndependentValuePath="X" DependentValuePath="Y" x:Name="Q1">
                <kit:AreaSeries.ItemsSource>
                    <PointCollection>
                        <Point>0,100</Point>
                        <Point>5,100</Point>
                    </PointCollection>
                </kit:AreaSeries.ItemsSource>
            </kit:AreaSeries>
    
            <kit:AreaSeries IndependentValuePath="X" DependentValuePath="Y" x:Name="Q2">
                <kit:AreaSeries.ItemsSource>
                    <PointCollection>
                        <Point>0,90</Point>
                        <Point>5,90</Point>
                    </PointCollection>
                </kit:AreaSeries.ItemsSource>
            </kit:AreaSeries>
    
            <kit:AreaSeries IndependentValuePath="X" DependentValuePath="Y" x:Name="Q3" >
                <kit:AreaSeries.ItemsSource>
                    <PointCollection>
                        <Point>0,30</Point>
                        <Point>5,30</Point>
                    </PointCollection>
                </kit:AreaSeries.ItemsSource>
            </kit:AreaSeries>
    
            <kit:LineSeries DependentValuePath="Y" IndependentValuePath="X">
                <kit:LineSeries.ItemsSource>
                    <PointCollection>
                        <Point>1,10</Point>
                        <Point>2,20</Point>
                        <Point>3,30</Point>
                        <Point>4,40</Point>
                    </PointCollection>
                </kit:LineSeries.ItemsSource>
    
                <kit:DataPointSeries.DataPointStyle>
                    <Style TargetType="{x:Type kit:LineDataPoint}">
                        <Setter Property="Template" Value="{x:Null}"/>
                        <Setter Property="Background" Value="Black"/>
                    </Style>
                </kit:DataPointSeries.DataPointStyle>
            </kit:LineSeries>
        </kit:Chart.Series>
    </kit:Chart>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
    
            chart.SizeChanged += new SizeChangedEventHandler(chart_SizeChanged);
        }
    
        void chart_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Path p= Find<Path>(Q1);
            if (p != null)
            {
                p.Fill = Brushes.Green;
            }
            p = Find<Path>(Q2);
            if (p != null)
            {
                p.Fill = Brushes.Yellow;
            }
            p = Find<Path>(Q3);
            if (p != null)
            {
                p.Fill = Brushes.Red;
            }
    
            //Point p1 = Q1.PointToScreen(new Point(0, 0));
            //Point p2 = Q1.PointToScreen(new Point(Q1.ActualWidth,Q1.ActualHeight ));
            
            //p1 =cvs.PointFromScreen(p1);
            //p2 = cvs.PointFromScreen(p2);
    
            //Canvas.SetLeft(grid, p1.X);
            //Canvas.SetTop(grid,p1.Y);
            //grid.Width = p2.X - p1.X;
            //grid.Height = p2.Y - p1.Y;
        }
    
        private static T Find<T>(DependencyObject dpo) where T : DependencyObject 
        {
            T t = dpo as T;
            if (t != null)
            {
                return t;
            }
            int count = VisualTreeHelper.GetChildrenCount(dpo);
            for (int i = 0; i < count; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(dpo, i);
                T tx = Find<T>(child);
                if (tx != null)
                {
                    return tx;
                }
            }
            return null;
        }
    }
    #SeriesのClipが枠っぽいけどハミ出るなぁ

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク minami259 2012年2月9日 5:11
    2012年2月8日 11:27
  • 返信ありがとうございます。

    しかし現状、WPFでの開発に便利というExpression Blendもない状況で、Visual Studioだけで開発をしています。予算を出してサードパーティー製のコンポーネントを使ったりするのは、できない状況ですので、いずれ使えるような状況になったらまた検討させていただきます。

    ありがとうございました。

    2012年2月9日 4:48
  • 返信ありがとうございます。

    このPlotAreaStyleでBackgroundを指定する方法で、うまくグラフの背景だけ塗ることができました。

    ControlTemplateを指定しているので、Chartに指定するだけでは駄目でしたが、ControlTemplateの中でEdgePanelの部分で、Style="{TemplateBinding PlotAreaStyle}" とすることで無事に反映されました。

    今回はこの方法でやらせてもらおうと思います。

    ありがとうございました。

    2012年2月9日 5:00
  • 返信ありがとうございます。

    サンプルコードも動作させて確認させてもらいました。XAMLから見ていると、パッと見、AreaSeriesで色を塗り分けをしているのかと思いましたが、コードビハインドで塗っているんですね。ちょっと内容が高度で、現在の私には全てが理解はできませんでしたが…。

    今回は、ぜれさんの返信の方法でやらせて頂こうと思いますが、大変参考になりました。

    ありがとうございました。

    2012年2月9日 5:10