使用DotNet.HighCharts库根据来自Webservice的DataTable结果创建图表
我们正试图从基于Silverlight的图表控件转移到更多的无插件控件。我们喜欢HighCharts,现在正在测试将其实现到现有的代码库中。 我们发现DotNet.HighCharts是一个可能的竞争者,可以快速创建图表,而无需解析所有javascript 我的问题是,当数据包含在使用DotNet.HighCharts库根据来自Webservice的DataTable结果创建图表,highcharts,vb.net-2010,Highcharts,Vb.net 2010,我们正试图从基于Silverlight的图表控件转移到更多的无插件控件。我们喜欢HighCharts,现在正在测试将其实现到现有的代码库中。 我们发现DotNet.HighCharts是一个可能的竞争者,可以快速创建图表,而无需解析所有javascript 我的问题是,当数据包含在数据表中时,如何传入图表中要使用的数据?下面是我看到的答案,即Linq可能是一种方法。然而,我很难让代码真正生成。DotNet.HighCharts的文档没有显示任何拉取非静态数据的示例,因此这里没有运气。这是我迄今为
数据表中时,如何传入图表中要使用的数据?
下面是我看到的答案,即Linq可能是一种方法。然而,我很难让代码真正生成。DotNet.HighCharts的文档没有显示任何拉取非静态数据的示例,因此这里没有运气。这是我迄今为止的代码片段:
Dim da3 As New SqlDataAdapter(sql3, conn3)
da3.Fill(dt3)
da3.Dispose()
conn3.Close()
Dim chart3 As Highcharts = New Highcharts("chart").InitChart(New Chart() With { _
.PlotShadow = False _
}).SetTitle(New Title() With { _
.Text = "Browser market shares at a specific website, 2010" _
}).SetTooltip(New Tooltip() With { _
.Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ this.percentage +' %'; }" _
}).SetPlotOptions(New PlotOptions() With { _
.Column = New PlotOptionsColumn With { _
.AllowPointSelect = True, _
.Cursor = Cursors.Pointer, _
.DataLabels = New PlotOptionsColumnDataLabels() With { _
.Color = ColorTranslator.FromHtml("#000000"), _
.Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ this.percentage +' %'; }" _
} _
} _
}).SetSeries(New Series() With { _
.Type = ChartTypes.Column, _
.Name = "Browser share", _
.Data = New Helpers.Data(dt3.Select(Function(x) New Options.Point() With {.X = x.periodyear, .Y = x.rate}).ToArray()) _
})
ltrChart3.Text = chart3.ToHtmlString()
我得到的错误出现在.Data=New Helpers.Data(dt3.Select(Function(x)New Options.Point(),带有{.x=x.periodyear,.Y=x.rate})。ToArray())
行。我得到的Lambda表达式无法转换为'String',因为'String'不是委托类型
,因为我在函数….rate}
位上出错
编辑:
首次尝试修改现有代码
Dim chart1 As Highcharts = New DotNet.Highcharts.Highcharts("test")
Dim series As Series = New Series()
series.Name = "CO Rates"
For i As Integer = 0 To dt.Rows.Count - 1
series.Data = New Helpers.Data(New Object() {dt.Rows(i)("periodyear"), dt.Rows(i)("rate")})
Next
chart1.SetSeries(series).InitChart(New Chart() With { _
.Type = ChartTypes.Column})
这只生成2列,第一列位于x位置0,其值为2011,另一列位于x位置1,其值为8.3。这是非常奇怪的,因为在我看来,它好像是取了数据表中的最后一个点,然后将它的{x,y}值({2011,8.3})分成两个不同的点,x和y值都是y值,比如{0,x}和{1,y}。
我需要得到:
- 从数据表中获取{periodyear,rate}的单个序列
- 在未来,我想有一个系列的每个位置与它的 {periodyear,rate}取自数据表
dt.Rows(i)(“periodyear”)
转换为日期时间值。这是迄今为止的代码(在PaseExact方法上失败):
如果我将其更改为字符串值(例如1980),然后将x轴的AxisTypes更改为Linear,我将显示数据。不知怎么的,它刚刚结束——1980年看起来像1980年。婴儿步
编辑N:
这是最终的工作解决方案。这似乎需要一些清理。例如,我不确定是否需要创建一个字典来输入X/Y值,然后在字典上迭代以将数据添加到我的chartData对象。这似乎是双重工作
Dim stfipsList = (From r In dt.AsEnumerable() Select r("stfips")).Distinct().ToList()
Dim SeriesList As New List(Of Series)(stfipsList.Count)
Dim seriesItem(stfipsList.Count) As Series
Dim xDate As DateTime
Dim fakeDate As String
Dim sX As Integer
sX = 1
For Each state In stfipsList
Dim data As New Dictionary(Of DateTime, Decimal)
Dim stateVal As String = state.ToString
Dim recCount As Integer = dt.Rows.Count - 1
For i As Integer = 0 To recCount
If dt.Rows(i)("stfips").ToString = stateVal Then
fakeDate = "1/1/" + dt.Rows(i)("periodyear").ToString
xDate = DateTime.Parse(fakeDate)
data.Add(xDate.Date, dt.Rows(i)("unemprate"))
End If
Next
Dim chartData As Object(,) = New Object(data.Count - 1, 1) {}
Dim x As Integer = 0
For Each pair As KeyValuePair(Of DateTime, Decimal) In data
chartData.SetValue(pair.Key, x, 0)
chartData.SetValue(pair.Value, x, 1)
x += 1
Next
seriesItem(sX) = New Series With {
.Name = state.ToString, _
.Data = New Helpers.Data(chartData)
}
SeriesList.Add(seriesItem(sX))
sX = sX + 1
Next
Dim chart1 As Highcharts = New Highcharts("chart1").InitChart(New Chart() With { _
.Type = ChartTypes.Line _
}).SetTitle(New Title() With { _
.Text = "Annual Unemployment Rate" _
}).SetTooltip(New Tooltip() With { _
.Formatter = "function() { return '<b>'+ this.series.name + ': ' + Highcharts.dateFormat('%Y', this.x) +'</b>: '+ this.y +' %'; }" _
}).SetXAxis(New XAxis() With { _
.Type = AxisTypes.Datetime _
}).SetYAxis(New YAxis() With { _
.Min = 0, _
.Title = New YAxisTitle() With { _
.Text = "Unemployment Rate", _
.Align = AxisTitleAligns.High _
} _
}).SetSeries(SeriesList.[Select](Function(s) New Series() With { _
.Name = s.Name, _
.Data = s.Data _
}).ToArray())
ltrChart1.Text = chart1.ToHtmlString()
Dim stfipsList=(从dt.AsEnumerable()中的r选择r(“stfips”)).Distinct().ToList()
Dim系列列表作为新列表(系列)(stfipsList.Count)
Dim系列项目(stfipsList.Count)作为系列
Dim xDate作为日期时间
将假日期设置为字符串
作为整数的Dim sX
sX=1
对于stfipsList中的每个状态
作为新字典的Dim数据(日期时间,十进制)
Dim stateVal As String=state.ToString
Dim recCount As Integer=dt.Rows.Count-1
对于i作为整数=0进行重新计数
如果dt.Rows(i)(“stfips”).ToString=stateVal,则
fakeDate=“1/1/”+dt.行(i)(“周期年”).ToString
xDate=DateTime.Parse(fakeDate)
添加数据(xDate.Date,dt.Rows(i)(“未计算”))
如果结束
下一个
Dim chartData作为对象(,)=新对象(data.Count-1,1){
尺寸x为整数=0
作为数据中的KeyValuePair(日期时间,十进制)的每对
chartData.SetValue(pair.Key,x,0)
chartData.SetValue(pair.Value,x,1)
x+=1
下一个
系列项目(sX)=具有{
.Name=state.ToString_
.Data=新的助手.Data(图表数据)
}
序列列表。添加(序列项(sX))
sX=sX+1
下一个
Dim chart1 As Highcharts=新的Highcharts(“chart1”).InitChart(新图表(),带{_
.Type=图表类型.Line_
}).SetTitle(带有{_
.Text=“年度失业率”_
}).SetTooltip(带有{_
.Formatter=“function(){return'+this.series.name+':'+Highcharts.dateFormat('%Y',this.x)+':'+this.Y+'%;}”_
}).SetXAxis(带{_
.Type=AxisTypes.Datetime_
}).SetYAxis(带{_
.Min=0_
.Title=带有{_
.Text=“失业率”_
.Align=轴标题对齐。高_
} _
}).SetSeries(SeriesList.[Select](函数)带有{_
.Name=s.Name_
.Data=s.Data_
}).ToArray())
ltrChart1.Text=chart1.ToHtmlString()
在这里,您可以找到如何从DataTable创建系列的示例:
此外,您还可以从中找到如何“从字典绑定数据”和“从对象列表绑定数据”请参见下面的我的控制器操作结果,它执行您所要求的操作。它是用C#编写的,但是可以很容易地用VB修改。有比您要求的更多的信息,但在VisualStudio中使用Highcharts时,可能会看到其他问题 我正在做的是创建一个系列列表,然后将列表传递给highcharts。这样做的好处是,您不必单独创建每个系列
public ActionResult CombinerBarToday(DateTime? utcStartingDate = null,
DateTime? utcEndingDate = null)
{
//TEMPORARILY USED TO FORCE A DATE
//utcStartingDate = new DateTime(2012, 1, 9, 0, 0, 1);
//utcEndingDate = new DateTime(2012, 1, 9, 23, 59, 59);
//GET THE GENERATED POWER READINGS FOR THE SPECIFIED DATETIME
var firstQ = from s in db.PowerCombinerHistorys
join u in db.PowerCombiners on s.combiner_id equals u.id
where s.recordTime >= utcStartingDate
where s.recordTime <= utcEndingDate
select new
{
Combiner = u.name,
Current = s.current,
RecordTime = s.recordTime,
Voltage = s.voltage,
Power = s.current * s.voltage
};
//APPLY THE GROUPING
var groups = firstQ.ToList().GroupBy(q => new
{
q.Combiner,
Date = q.RecordTime.Date,
Hour = q.RecordTime.Hour
});
List<CombinerKwh> stringGroupedKwhlist = new List<CombinerKwh>();
//CALCULATE THE AVERAGE POWER GENERATED PER HOUR AND ADD TO LIST
foreach (var group in groups)
{
stringGroupedKwhlist.Add(new CombinerKwh(
group.Key.Combiner,
new DateTime(group.Key.Date.Year, group.Key.Date.Month, group.Key.Date.Day, group.Key.Hour, 0, 0),
group.Average(g => g.Power) / 1000d
));
}
//GET A LIST OF THE COMBINERS CONTAINS IN THE QUERY
var secondQ = (from s in firstQ
orderby s.Combiner
select new
{
Combiner = s.Combiner
}
).Distinct();
/* THIS LIST OF SERIES WILL BE USED TO DYNAMICALLY ADD AS MANY SERIES
* TO THE HIGHCHARTS AS NEEDEDWITHOUT HAVING TO CREATE EACH SERIES INDIVIUALY */
List<Series> allSeries = new List<Series>();
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
//LOOP THROUGH EACH COMBINER AND CREATE SERIES
foreach (var distinctCombiner in secondQ)
{
var combinerDetail = from h in stringGroupedKwhlist
where h.CombinerID == distinctCombiner.Combiner
orderby TimeZoneInfo.ConvertTimeFromUtc(h.Interval,easternZone)
select new
{
CombinerID = h.CombinerID,
//CONVERT FROM UTC TIME TO THE LOCAL TIME OF THE SITE
Interval = TimeZoneInfo.ConvertTimeFromUtc(h.Interval,easternZone),
KWH = h.KWH
};
//REPRESENTS 24 PLOTS FOR EACH HOUR IN DAY
object[] myData = new object[24];
foreach (var detailCombiner in combinerDetail)
{
if (detailCombiner.KWH != 0)
{
myData[detailCombiner.Interval.Hour] = detailCombiner.KWH;
}
}
allSeries.Add(new Series
{
Name = distinctCombiner.Combiner,
Data = new Data(myData)
});
}
Highcharts chart = new Highcharts("chart")
.InitChart(new Chart { DefaultSeriesType = ChartTypes.Spline })
.SetTitle(new Title { Text = "Combiner History" })
.SetXAxis(new XAxis
{
Categories = new[] { "0:00 AM", "1:00 AM", "2:00 AM", "3:00 AM", "4:00 AM", "5:00 AM", "6:00 AM", "7:00 AM", "8:00 AM", "9:00 AM", "10:00 AM", "11:00 AM", "12:00 PM", "1:00 PM", "2:00 PM", "3:00 PM", "4:00 PM", "5:00 PM", "6:00 PM", "7:00 PM", "8:00 PM", "9:00 PM", "10:00 PM", "11:00 PM" },
Labels = new XAxisLabels
{
Rotation = -45,
Align = HorizontalAligns.Right,
Style = "font: 'normal 10px Verdana, sans-serif'"
},
Title = new XAxisTitle { Text = "Time(Hour)" },
//Type = AxisTypes.Linear
})
.SetYAxis(new YAxis
{
//Min = 0,
Title = new YAxisTitle { Text = "Kwh" }
})
.SetSeries(allSeries.Select(s => new Series { Name = s.Name, Data = s.Data }).ToArray());
return PartialView(chart);
}
public ActionResult CombinerBarToday(日期时间?utcStartingDate=null,
日期时间(utcEndingDate=null)
{
//临时用来强制约会的
//utcStartingDate=新的日期时间(2012,1,9,0,0,1);
//utcEndingDate=新的日期时间(2012,1,9,23,59,59);
//获取指定日期时间的发电量读数
var firstQ=来自s,单位为db.PowerCombinerHistorys
加入我
Dim stfipsList = (From r In dt.AsEnumerable() Select r("stfips")).Distinct().ToList()
Dim SeriesList As New List(Of Series)(stfipsList.Count)
Dim seriesItem(stfipsList.Count) As Series
Dim xDate As DateTime
Dim fakeDate As String
Dim sX As Integer
sX = 1
For Each state In stfipsList
Dim data As New Dictionary(Of DateTime, Decimal)
Dim stateVal As String = state.ToString
Dim recCount As Integer = dt.Rows.Count - 1
For i As Integer = 0 To recCount
If dt.Rows(i)("stfips").ToString = stateVal Then
fakeDate = "1/1/" + dt.Rows(i)("periodyear").ToString
xDate = DateTime.Parse(fakeDate)
data.Add(xDate.Date, dt.Rows(i)("unemprate"))
End If
Next
Dim chartData As Object(,) = New Object(data.Count - 1, 1) {}
Dim x As Integer = 0
For Each pair As KeyValuePair(Of DateTime, Decimal) In data
chartData.SetValue(pair.Key, x, 0)
chartData.SetValue(pair.Value, x, 1)
x += 1
Next
seriesItem(sX) = New Series With {
.Name = state.ToString, _
.Data = New Helpers.Data(chartData)
}
SeriesList.Add(seriesItem(sX))
sX = sX + 1
Next
Dim chart1 As Highcharts = New Highcharts("chart1").InitChart(New Chart() With { _
.Type = ChartTypes.Line _
}).SetTitle(New Title() With { _
.Text = "Annual Unemployment Rate" _
}).SetTooltip(New Tooltip() With { _
.Formatter = "function() { return '<b>'+ this.series.name + ': ' + Highcharts.dateFormat('%Y', this.x) +'</b>: '+ this.y +' %'; }" _
}).SetXAxis(New XAxis() With { _
.Type = AxisTypes.Datetime _
}).SetYAxis(New YAxis() With { _
.Min = 0, _
.Title = New YAxisTitle() With { _
.Text = "Unemployment Rate", _
.Align = AxisTitleAligns.High _
} _
}).SetSeries(SeriesList.[Select](Function(s) New Series() With { _
.Name = s.Name, _
.Data = s.Data _
}).ToArray())
ltrChart1.Text = chart1.ToHtmlString()
public ActionResult CombinerBarToday(DateTime? utcStartingDate = null,
DateTime? utcEndingDate = null)
{
//TEMPORARILY USED TO FORCE A DATE
//utcStartingDate = new DateTime(2012, 1, 9, 0, 0, 1);
//utcEndingDate = new DateTime(2012, 1, 9, 23, 59, 59);
//GET THE GENERATED POWER READINGS FOR THE SPECIFIED DATETIME
var firstQ = from s in db.PowerCombinerHistorys
join u in db.PowerCombiners on s.combiner_id equals u.id
where s.recordTime >= utcStartingDate
where s.recordTime <= utcEndingDate
select new
{
Combiner = u.name,
Current = s.current,
RecordTime = s.recordTime,
Voltage = s.voltage,
Power = s.current * s.voltage
};
//APPLY THE GROUPING
var groups = firstQ.ToList().GroupBy(q => new
{
q.Combiner,
Date = q.RecordTime.Date,
Hour = q.RecordTime.Hour
});
List<CombinerKwh> stringGroupedKwhlist = new List<CombinerKwh>();
//CALCULATE THE AVERAGE POWER GENERATED PER HOUR AND ADD TO LIST
foreach (var group in groups)
{
stringGroupedKwhlist.Add(new CombinerKwh(
group.Key.Combiner,
new DateTime(group.Key.Date.Year, group.Key.Date.Month, group.Key.Date.Day, group.Key.Hour, 0, 0),
group.Average(g => g.Power) / 1000d
));
}
//GET A LIST OF THE COMBINERS CONTAINS IN THE QUERY
var secondQ = (from s in firstQ
orderby s.Combiner
select new
{
Combiner = s.Combiner
}
).Distinct();
/* THIS LIST OF SERIES WILL BE USED TO DYNAMICALLY ADD AS MANY SERIES
* TO THE HIGHCHARTS AS NEEDEDWITHOUT HAVING TO CREATE EACH SERIES INDIVIUALY */
List<Series> allSeries = new List<Series>();
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
//LOOP THROUGH EACH COMBINER AND CREATE SERIES
foreach (var distinctCombiner in secondQ)
{
var combinerDetail = from h in stringGroupedKwhlist
where h.CombinerID == distinctCombiner.Combiner
orderby TimeZoneInfo.ConvertTimeFromUtc(h.Interval,easternZone)
select new
{
CombinerID = h.CombinerID,
//CONVERT FROM UTC TIME TO THE LOCAL TIME OF THE SITE
Interval = TimeZoneInfo.ConvertTimeFromUtc(h.Interval,easternZone),
KWH = h.KWH
};
//REPRESENTS 24 PLOTS FOR EACH HOUR IN DAY
object[] myData = new object[24];
foreach (var detailCombiner in combinerDetail)
{
if (detailCombiner.KWH != 0)
{
myData[detailCombiner.Interval.Hour] = detailCombiner.KWH;
}
}
allSeries.Add(new Series
{
Name = distinctCombiner.Combiner,
Data = new Data(myData)
});
}
Highcharts chart = new Highcharts("chart")
.InitChart(new Chart { DefaultSeriesType = ChartTypes.Spline })
.SetTitle(new Title { Text = "Combiner History" })
.SetXAxis(new XAxis
{
Categories = new[] { "0:00 AM", "1:00 AM", "2:00 AM", "3:00 AM", "4:00 AM", "5:00 AM", "6:00 AM", "7:00 AM", "8:00 AM", "9:00 AM", "10:00 AM", "11:00 AM", "12:00 PM", "1:00 PM", "2:00 PM", "3:00 PM", "4:00 PM", "5:00 PM", "6:00 PM", "7:00 PM", "8:00 PM", "9:00 PM", "10:00 PM", "11:00 PM" },
Labels = new XAxisLabels
{
Rotation = -45,
Align = HorizontalAligns.Right,
Style = "font: 'normal 10px Verdana, sans-serif'"
},
Title = new XAxisTitle { Text = "Time(Hour)" },
//Type = AxisTypes.Linear
})
.SetYAxis(new YAxis
{
//Min = 0,
Title = new YAxisTitle { Text = "Kwh" }
})
.SetSeries(allSeries.Select(s => new Series { Name = s.Name, Data = s.Data }).ToArray());
return PartialView(chart);
}