none
Chartへの注釈について RRS feed

  • 質問

  • Chartコントロールを利用してグラフを描きました。画像のように、注釈(問題数10正答数9など)を入れたいと考えているのですが、うまくいきません。宜しくお願いします。

    Private Sub SetDataToChart() 'データテーブルの作成 Dim dt As New DataTable Dim dr As DataRow '表の1行目の項目名とデータのタイプを設定 dt.Columns.Add(New DataColumn("氏名", GetType(String))) dt.Columns.Add(New DataColumn("得点", GetType(Integer))) dr = dt.NewRow dr(0) = "A君" dr(1) = 90 dt.Rows.Add(dr) dr = dt.NewRow dr(0) = "B君" dr(1) = 80 dt.Rows.Add(dr) dr = dt.NewRow dr(0) = "Cさん" dr(1) = 50 dt.Rows.Add(dr) dr = dt.NewRow dr(0) = "D君" dr(1) = 70 dt.Rows.Add(dr) dr = dt.NewRow dr(0) = "Eさん" dr(1) = 100 dt.Rows.Add(dr) With Chart1 .Series.Clear() .Legends.Clear() .BorderColor = Color.Green .BorderWidth = 2 .BorderDashStyle = ChartDashStyle.Solid .Legends.Add("得点") 'データバインド .DataSource = dt '系列追加 Dim cName As String = dt.Columns(1).ColumnName .Series.Add(cName) With .Series(cName) .ChartType = DataVisualization.Charting.SeriesChartType.Bar .XValueMember = dt.Columns(0).ColumnName .YValueMembers = cName .Color = Color.Aqua .BorderColor = Color.Blue .BorderWidth = 1 End With With .ChartAreas(0) .AxisX.TitleFont = New Font("メイリオ", 10) .AxisX.Title = "氏 名" 'X軸の起点を上にする(チャートタイプがBarのとき、X軸は縦軸) .AxisX.IsReversed = True .AxisX.LabelStyle.Font = New Font("メイリオ", 8) 'X軸の項目を1つずつ表示する .AxisX.Interval = 1 .AxisX.MajorGrid.LineColor = Color.LightGray 'Y軸の最大値(チャートタイプがBarのとき、Y軸は横軸) .AxisY.TitleFont = New Font("メイリオ", 10) .AxisY.Title = "得 点" .AxisY.Maximum = 100 .AxisY.Interval = 20 .AxisY.MajorGrid.LineColor = Color.LightGray End With End With End Sub

    2019年11月7日 5:06

回答

  • Chart.PostPaintイベントで座標を計算して自分で書きこんでみるとか

    Imports System.Windows.Forms.DataVisualization.Charting
    
    Public Class Form1
    
        Sub New()
    
            ' この呼び出しはデザイナーで必要です。
            InitializeComponent()
    
            SetDataToChart()
        End Sub
    
        Private Sub SetDataToChart()
            'データテーブルの作成
            Dim dt As New DataTable
            Dim dr As DataRow
            '表の1行目の項目名とデータのタイプを設定
            dt.Columns.Add(New DataColumn("氏名", GetType(String)))
            dt.Columns.Add(New DataColumn("得点", GetType(Integer)))
            dt.Columns.Add(New DataColumn("問題数", GetType(Integer))) '項目を増やす
            dt.Columns.Add(New DataColumn("正答数", GetType(Integer))) '項目を増やす
    
            dr = dt.NewRow
            dr(0) = "A君"
            dr(1) = 90
            dr(2) = 10 : dr(3) = 9
            dt.Rows.Add(dr)
    
            dr = dt.NewRow
            dr(0) = "B君"
            dr(1) = 80
            dr(2) = 5 : dr(3) = 4
            dt.Rows.Add(dr)
    
            dr = dt.NewRow
            dr(0) = "Cさん"
            dr(1) = 50
            dr(2) = 10 : dr(3) = 5
            dt.Rows.Add(dr)
    
            dr = dt.NewRow
            dr(0) = "D君"
            dr(1) = 70
            dr(2) = 20 : dr(3) = 14
            dt.Rows.Add(dr)
    
            dr = dt.NewRow
            dr(0) = "Eさん"
            dr(1) = 100
            dr(2) = 10 : dr(3) = 10
            dt.Rows.Add(dr)
    
            With Chart1
                .Series.Clear()
                .Legends.Clear()
                .BorderColor = Color.Green
                .BorderWidth = 2
                .BorderDashStyle = ChartDashStyle.Solid
                .Legends.Add("得点")
                'データバインド
                .DataSource = dt
    
                '系列追加
                Dim cName As String = dt.Columns(1).ColumnName
                .Series.Add(cName)
                With .Series(cName)
                    .ChartType = DataVisualization.Charting.SeriesChartType.Bar
                    .XValueMember = dt.Columns(0).ColumnName
                    .YValueMembers = cName
                    .Color = Color.Aqua
                    .BorderColor = Color.Blue
                    .BorderWidth = 1
                End With
                With .ChartAreas(0)
                    .AxisX.TitleFont = New Font("メイリオ", 10)
                    .AxisX.Title = "氏 名"
                    'X軸の起点を上にする(チャートタイプがBarのとき、X軸は縦軸)
                    .AxisX.IsReversed = True
                    .AxisX.LabelStyle.Font = New Font("メイリオ", 8)
                    'X軸の項目を1つずつ表示する
                    .AxisX.Interval = 1
                    .AxisX.MajorGrid.LineColor = Color.LightGray
                    'Y軸の最大値(チャートタイプがBarのとき、Y軸は横軸)
                    .AxisY.TitleFont = New Font("メイリオ", 10)
                    .AxisY.Title = "得 点"
                    .AxisY.Maximum = 100
                    .AxisY.Interval = 20
                    .AxisY.MajorGrid.LineColor = Color.LightGray
                End With
            End With
        End Sub
    
        Private Sub Chart1_PostPaint(sender As Object, e As ChartPaintEventArgs) Handles Chart1.PostPaint
            '描画イベントが終わったら文字を書き込む
    
            If TypeOf e.ChartElement Is System.Windows.Forms.DataVisualization.Charting.ChartArea Then
    
                Dim chart As Chart = CType(sender, Chart)
    
                Dim dt As DataTable = CType(chart.DataSource, DataTable)
    
                Dim area As ChartArea = CType(e.ChartElement, ChartArea)
                Dim axisX As Axis = area.AxisX
                Dim axisY As Axis = area.AxisY
                Dim series As Series = chart.Series.Item(0)
    
                Dim g As System.Drawing.Graphics = e.ChartGraphics.Graphics
                Dim font As Font = New Font(Me.Font.Name, 8.0F)
    
                For index As Integer = 0 To dt.Rows.Count - 1
                    Dim row As DataRow
                    row = dt.Rows(index)
    
                    Dim value As Integer
                    Dim q As Integer
                    Dim a As Integer
    
                    value = CType(row("得点"), Integer)
                    q = CType(row("問題数"), Integer)
                    a = CType(row("正答数"), Integer)
    
                    '値を画像の座標に変換
                    Dim vy As Double = axisX.ValueToPixelPosition(index + 1)
                    Dim vx As Double = axisY.ValueToPixelPosition(value)
    
                    Dim pos As PointF = New PointF(vx, vy)
    
                    Dim text As String
                    text = "問題数" & q & "正答数" & a
    
                    Dim format As New StringFormat
                    format.Alignment = StringAlignment.Near
                    format.LineAlignment = StringAlignment.Center
    
                    g.DrawString(text, font, Brushes.Black, pos, format) '文字書き込み
                    'g.DrawEllipse(Pens.Red, New RectangleF(vx, vy, 2, 2))
                Next
            End If
    
    
        End Sub
    End Class


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

    • 回答としてマーク nebokken 2019年11月8日 5:27
    2019年11月7日 10:08

すべての返信

  • 以前紹介した Chart Sample は入手・インストールして見ることができるのでしょうか? その中の Chart Features > Annotations あたりを見ると使えるものがあるかもしれません。
    2019年11月7日 5:57
  • ChartSampleはダウンロードして端折って見てはおります。ですが、英語なので深読みはできないでいます。

    また、Annotationを試みましたが、何せ種類がBorderLine,Cloud,Perspective,Rectangle,RoundedRectangle,SimpleLineの7つしかなく、注釈というよりはまさに吹き出しという感じでした。しかも、注釈の表示位置をデータポイントで指定する必要があるということなので、コードのChat1.DataSource=dtが使えないようで(間違っているかも)、手作業でSeriesを作成(CustomLabels利用)したり、ますます、混乱してきます。DataPoint関連では

                Dim srs As Series = New Series
                srs.Name = dt.Columns(1).ColumnName
                '得点
                For i As Integer = 0 To dt.Rows.Count - 1
                    srs.Points.Add(CType(dt.Rows(i)(1), Integer))
                Next
                .Series.Add(srs)
                '途中省略
                '注釈始め
                Dim ca As New CalloutAnnotation()
                '注釈の吹き出しスタイルを取得または設定  
                ca.CalloutStyle = CalloutStyle.Cloud
                ca.Text = "Test"             '注釈の文字
                ca.ForeColor = Color.Red
                ca.Font = New Font("メイリオ", 8)
                '表示位置の設定(Points(2)=Cさんの得点)
                ca.AnchorDataPoint = .Series("得点").Points(2)
                .Annotations.Add(ca)
                '注釈終わり
    
    で、Cさんのグラフのところへは注釈「Test」は出てきます。かわいい吹き出しです。でも、別な方法はないものかとお伺いしています。宜しくお願いします。

    2019年11月7日 7:02
  • Annottaion = 注釈 なのですが・・・

    それは目的に合わなくて、かつデータソースの値を表示する文字列に反映したいということなのですね。

    とすると、以下の記事のように棒グラフ内に Label として表示するぐらいしか自分は知りません。

    チャート・コントロールで積み上げ棒グラフを作成するには?
    https://www.atmarkit.co.jp/fdotnet/dotnettips/1004aspchartstack/aspchartstack.html

    これも NG ですと自分はお手上げです。お役に立てずすみませんが、他の人の回答をお待ちください。

    2019年11月7日 7:39
  • Chart.PostPaintイベントで座標を計算して自分で書きこんでみるとか

    Imports System.Windows.Forms.DataVisualization.Charting
    
    Public Class Form1
    
        Sub New()
    
            ' この呼び出しはデザイナーで必要です。
            InitializeComponent()
    
            SetDataToChart()
        End Sub
    
        Private Sub SetDataToChart()
            'データテーブルの作成
            Dim dt As New DataTable
            Dim dr As DataRow
            '表の1行目の項目名とデータのタイプを設定
            dt.Columns.Add(New DataColumn("氏名", GetType(String)))
            dt.Columns.Add(New DataColumn("得点", GetType(Integer)))
            dt.Columns.Add(New DataColumn("問題数", GetType(Integer))) '項目を増やす
            dt.Columns.Add(New DataColumn("正答数", GetType(Integer))) '項目を増やす
    
            dr = dt.NewRow
            dr(0) = "A君"
            dr(1) = 90
            dr(2) = 10 : dr(3) = 9
            dt.Rows.Add(dr)
    
            dr = dt.NewRow
            dr(0) = "B君"
            dr(1) = 80
            dr(2) = 5 : dr(3) = 4
            dt.Rows.Add(dr)
    
            dr = dt.NewRow
            dr(0) = "Cさん"
            dr(1) = 50
            dr(2) = 10 : dr(3) = 5
            dt.Rows.Add(dr)
    
            dr = dt.NewRow
            dr(0) = "D君"
            dr(1) = 70
            dr(2) = 20 : dr(3) = 14
            dt.Rows.Add(dr)
    
            dr = dt.NewRow
            dr(0) = "Eさん"
            dr(1) = 100
            dr(2) = 10 : dr(3) = 10
            dt.Rows.Add(dr)
    
            With Chart1
                .Series.Clear()
                .Legends.Clear()
                .BorderColor = Color.Green
                .BorderWidth = 2
                .BorderDashStyle = ChartDashStyle.Solid
                .Legends.Add("得点")
                'データバインド
                .DataSource = dt
    
                '系列追加
                Dim cName As String = dt.Columns(1).ColumnName
                .Series.Add(cName)
                With .Series(cName)
                    .ChartType = DataVisualization.Charting.SeriesChartType.Bar
                    .XValueMember = dt.Columns(0).ColumnName
                    .YValueMembers = cName
                    .Color = Color.Aqua
                    .BorderColor = Color.Blue
                    .BorderWidth = 1
                End With
                With .ChartAreas(0)
                    .AxisX.TitleFont = New Font("メイリオ", 10)
                    .AxisX.Title = "氏 名"
                    'X軸の起点を上にする(チャートタイプがBarのとき、X軸は縦軸)
                    .AxisX.IsReversed = True
                    .AxisX.LabelStyle.Font = New Font("メイリオ", 8)
                    'X軸の項目を1つずつ表示する
                    .AxisX.Interval = 1
                    .AxisX.MajorGrid.LineColor = Color.LightGray
                    'Y軸の最大値(チャートタイプがBarのとき、Y軸は横軸)
                    .AxisY.TitleFont = New Font("メイリオ", 10)
                    .AxisY.Title = "得 点"
                    .AxisY.Maximum = 100
                    .AxisY.Interval = 20
                    .AxisY.MajorGrid.LineColor = Color.LightGray
                End With
            End With
        End Sub
    
        Private Sub Chart1_PostPaint(sender As Object, e As ChartPaintEventArgs) Handles Chart1.PostPaint
            '描画イベントが終わったら文字を書き込む
    
            If TypeOf e.ChartElement Is System.Windows.Forms.DataVisualization.Charting.ChartArea Then
    
                Dim chart As Chart = CType(sender, Chart)
    
                Dim dt As DataTable = CType(chart.DataSource, DataTable)
    
                Dim area As ChartArea = CType(e.ChartElement, ChartArea)
                Dim axisX As Axis = area.AxisX
                Dim axisY As Axis = area.AxisY
                Dim series As Series = chart.Series.Item(0)
    
                Dim g As System.Drawing.Graphics = e.ChartGraphics.Graphics
                Dim font As Font = New Font(Me.Font.Name, 8.0F)
    
                For index As Integer = 0 To dt.Rows.Count - 1
                    Dim row As DataRow
                    row = dt.Rows(index)
    
                    Dim value As Integer
                    Dim q As Integer
                    Dim a As Integer
    
                    value = CType(row("得点"), Integer)
                    q = CType(row("問題数"), Integer)
                    a = CType(row("正答数"), Integer)
    
                    '値を画像の座標に変換
                    Dim vy As Double = axisX.ValueToPixelPosition(index + 1)
                    Dim vx As Double = axisY.ValueToPixelPosition(value)
    
                    Dim pos As PointF = New PointF(vx, vy)
    
                    Dim text As String
                    text = "問題数" & q & "正答数" & a
    
                    Dim format As New StringFormat
                    format.Alignment = StringAlignment.Near
                    format.LineAlignment = StringAlignment.Center
    
                    g.DrawString(text, font, Brushes.Black, pos, format) '文字書き込み
                    'g.DrawEllipse(Pens.Red, New RectangleF(vx, vy, 2, 2))
                Next
            End If
    
    
        End Sub
    End Class


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

    • 回答としてマーク nebokken 2019年11月8日 5:27
    2019年11月7日 10:08
  • gekkaさん、感激です。何故、Newなのか、PostPaintイベントの存在、見知らぬプロパティやメソッド、解読するにはかなり時間がかかりそうです。でも、大変ありがとうございます。
    2019年11月8日 5:34