WinForms のチャートタイプ > 特殊チャート > 浮動棒チャート |
浮動棒グラフは、1 つまたは複数の棒が、軸に接しないで、最小値と最大値の間に浮いているように表示されるチャートです。情報は一定の範囲のデータとして表示され、データポイントごとに 2 つの Y 値(低値と高値)がプロットされます。浮動棒グラフは、1 日の最高/最低気温、株価、血圧値など、最高値と最低値から成るデータセットを表示する場合に便利です。
FlexChart では、Series クラスを使用して WinForms 浮動棒グラフを実装できます。初めに、新しい Series オブジェクトを作成し、そのプロパティを指定します。次に、Series クラスから提供される SymbolRendering イベントを使用して、グラフにデータポイントをプロットします。
private void Form1_Load(object sender, EventArgs e) { string[] cities = { "Chicago", "New York" }; List<CityDataItem> data = GetTemperatureData(cities, true, 7, true); this.flexChart1.AxisY.Min = data.Select(x => x.Data.Min(y => y.LowTemp)).Min(); this.flexChart1.AxisY.Max = data.Select(x => x.Data.Max(y => y.HighTemp)).Max(); foreach (var dataItem in data) { Series series = new Series() { Binding = "HighTemp", BindingX = "Date", Name = dataItem.Name, DataSource = dataItem.Data, }; series.SymbolRendering += Series_SymbolRendering; this.flexChart1.Series.Add(series); } this.flexChart1.DataLabel.Content = "{seriesName}"; this.flexChart1.DataLabel.Position = LabelPosition.Bottom; this.flexChart1.LabelRendering += FlexChart1_LabelRendering; this.flexChart1.Header.Content = "Weather Report : Monthly Temperatures"; this.flexChart1.AxisY.Format = "0 °F"; this.flexChart1.Options.ClusterSize = new ElementSize { SizeType = ElementSizeType.Percentage, Value = columnWidthPercentage * 100 }; this.flexChart1.DataLabel.Overlapping = LabelOverlapping.Show; } private void FlexChart1_LabelRendering(object sender, RenderDataLabelEventArgs e) { var temp = (Temperature)e.Item; e.Text = string.Format("{0:0}:{1:0}", temp.LowTemp, temp.HighTemp); } private void Series_SymbolRendering(object sender, RenderSymbolEventArgs e) { e.Cancel = true; Temperature temperature = (Temperature)e.Item; var width = this.flexChart1.PlotRect.Width / ((List<Temperature>)this.flexChart1.Series[0].DataSource).Count * columnWidthPercentage / this.flexChart1.Series.Count; var bottom = 0d; bottom = this.flexChart1.AxisY.Convert(temperature.LowTemp); e.Engine.DrawRect(e.Point.X - width / 2 - 2, e.Point.Y, width - 4, bottom - e.Point.Y); }
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load Dim cities As String() = {"Chicago", "New York"} Dim data As List(Of CityDataItem) = GetTemperatureData(cities, True, 7, True) 'AddressOf Me.flexChart1.AxisY.Min = data.[Select](Function(x) x.Data.Min(Function(y) y.LowTemp)).Min() 'AddressOf Me.flexChart1.AxisY.Max = data.[Select](Function(x) x.Data.Max(Function(y) y.HighTemp)).Max() For Each dataItem As CityDataItem In data Dim series As New Series() With { .Binding = "HighTemp", .BindingX = "Date", .Name = dataItem.Name, .DataSource = dataItem.Data } AddHandler series.SymbolRendering, AddressOf Series_SymbolRendering Me.flexChart1.Series.Add(series) Next Me.flexChart1.DataLabel.Content = "{seriesName}" Me.flexChart1.DataLabel.Position = LabelPosition.Bottom AddHandler Me.flexChart1.LabelRendering, AddressOf FlexChart1_LabelRendering Me.flexChart1.Header.Content = "Weather Report : Monthly Temperatures" Me.flexChart1.AxisY.Format = "0 °F" Me.flexChart1.Options.ClusterSize = New ElementSize() With { .SizeType = ElementSizeType.Percentage, .Value = columnWidthPercentage * 100 } Me.flexChart1.DataLabel.Overlapping = LabelOverlapping.Show End Sub Private Sub FlexChart1_LabelRendering(sender As Object, e As RenderDataLabelEventArgs) Dim temp As Temperature = DirectCast(e.Item, Temperature) e.Text = String.Format("{0:0}:{1:0}", temp.LowTemp, temp.HighTemp) End Sub Private Sub Series_SymbolRendering(sender As Object, e As RenderSymbolEventArgs) e.Cancel = True Dim temperature As Temperature = DirectCast(e.Item, Temperature) Dim width As Single = Me.flexChart1.PlotRect.Width / DirectCast(Me.flexChart1.Series(0).DataSource, List(Of Temperature)).Count * columnWidthPercentage / Me.flexChart1.Series.Count Dim bottom As Double = 0.0 bottom = Me.flexChart1.AxisY.Convert(temperature.LowTemp) e.Engine.DrawRect(e.Point.X - width / 2 - 2, e.Point.Y, width - 4, bottom - e.Point.Y) End Sub
上記のサンプルコードは、GetTemperatureData という名前のカスタムメソッドを使用してチャートにデータを提供しています。要件に基づいてデータソースを設定できます。
private Random rnd = new Random(); public List<CityDataItem> GetTemperatureData(string[] cities, bool monthly = false, int count = 30, bool isFahrenheit = false) { var data = new List<CityDataItem>(); var startDate = new DateTime(2017, 1, 1); foreach (string city in cities) { var dataItem = new CityDataItem() { Name = city }; for (int i = 0; i < count; i++) { var temp = new Temperature(); DateTime date; if (monthly) date = startDate.AddMonths(i); else date = startDate.AddDays(i); temp.Date = date; if (date.Month <= 8) temp.HighTemp = rnd.Next(3 * date.Month, 8 * date.Month); else temp.HighTemp = rnd.Next((13 - date.Month - 2) * date.Month, (13 - date.Month) * date.Month); temp.LowTemp = temp.HighTemp - rnd.Next(6, 8); temp.Precipitation = (date.Month < 4 || date.Month > 8) ? rnd.Next(100, 150) : rnd.Next(150, 200); if (isFahrenheit) temp.HighTemp = temp.HighTemp * 1.8 + 32; dataItem.Data.Add(temp); } data.Add(dataItem); } return data; }
Private rnd As New Random() Public Function GetTemperatureData(cities As String(), Optional monthly As Boolean = False, Optional count As Integer = 30, Optional isFahrenheit As Boolean = False) As List(Of CityDataItem) Dim data As List(Of CityDataItem) = New List(Of CityDataItem)() Dim startDate As DateTime = New DateTime(2017, 1, 1) For Each city As String In cities Dim dataItem As CityDataItem = New CityDataItem() With { .Name = city } For i As Integer = 0 To count - 1 Dim temp As Temperature = New Temperature() Dim [date] As DateTime If monthly Then [date] = startDate.AddMonths(i) Else [date] = startDate.AddDays(i) End If temp.[Date] = [date] If [date].Month <= 8 Then temp.HighTemp = rnd.[Next](3 * [date].Month, 8 * [date].Month) Else temp.HighTemp = rnd.[Next]((13 - [date].Month - 2) * [date].Month, (13 - [date].Month) * [date].Month) End If temp.LowTemp = temp.HighTemp - rnd.[Next](6, 8) temp.Precipitation = If(([date].Month < 4 OrElse [date].Month > 8), rnd.[Next](100, 150), rnd.[Next](150, 200)) If isFahrenheit Then temp.HighTemp = temp.HighTemp * 1.8 + 32 End If dataItem.Data.Add(temp) Next data.Add(dataItem) Next Return data End Function