How can statistical data be shown in a chart format using the Razor Chart Helper of MVC ?
When you want to display your data in graphical form, you can use Chart helper. The Chart helper can render an image that displays data in a variety of chart types.
You can create a view having razor code for chart as follows(lets say its MyChart.cshtml).
Bar chart from Array with theam
#{
var myChart = new Chart(width: 600, height: 400, theme: ChartTheme.Green)
.AddTitle("Chart Title")
.AddSeries(
name: "ChartTitle",
xValue: new[] { "Col1", "Col2", "Col3", "Col4", "Col5" },
yValues: new[] { "2", "6", "4", "5", "3" })
.Write();
}
Pie chart from Array
#{
var myChart = new Chart(width: 600, height: 400, theme: ChartTheme.Green)
.AddTitle("Chart Title")
.AddSeries(
name: "ChartTitle",
chartType: "Pie",
xValue: new[] { "Col1", "Col2", "Col3", "Col4", "Col5" },
yValues: new[] { "2", "6", "4", "5", "3" })
.Write();
}
Pie chart from Array with theam
#{
var myChart = new Chart(width: 600, height: 400)
.AddTitle("Chart Title")
.AddSeries(
name: "ChartTitle",
chartType: "Pie",
xValue: new[] { "Col1", "Col2", "Col3", "Col4", "Col5" },
yValues: new[] { "2", "6", "4", "5", "3" })
.Write();
}
Bar Chart Using DB Query
#{
var db = Database.Open("DBName");
var data = db.Query("SELECT Col1, Col2 FROM Table");
var myChart = new Chart(width: 600, height: 400)
.AddTitle("Chart Title")
.DataBindTable(dataSource: data, xField: "Col1")
.Write();
}
You can use these chart views/PartialView where ever required as a src of image.
ex.
<html>
<body>
<img src="MyChart.cshtml" />
<!-- or <img src='#Url.Action("Controler","ActionNameOfChartRenderingView")' />-->
<body>
<html>
Chart Theams
Vanilla Displays red columns on a white background.
Blue Displays blue columns on a blue gradient background.
Green Displays blue columns on a green gradient background.
Yellow Displays orange columns on a yellow gradient background.
Vanilla3D Displays 3-D red columns on a white background.
SeriesChartType enumeration supports the following:
Area
Bar
BoxPlot
Bubble
Candlestick
Column
Doughnut
ErrorBar
FastLine
FastPoint
Funnel
Kagi
Line
Pie
Point
PointAndFigure
Polar
Pyramid
Radar
Range
RangeBar
RangeColumn
Renko
Spline
SplineArea
SplineRange
StackedArea
StackedArea100
StackedBar
StackedBar100
StackedColumn
StackedColumn100
StepLine
Stock
ThreeLineBreak
This is the list of names that you can pass, as strings, to the Chart helper in a Razor page.
This is Helper
namespace System.Web.Helpers
{
public class Chart
{
public Chart(int width, int height, string template = null, string templatePath = null);
public string FileName { get; }
public int Height { get; }
public int Width { get; }
public Chart AddLegend(string title = null, string name = null);
public Chart AddSeries(string name = null, string chartType = "Column", string chartArea = null, string axisLabel = null, string legend = null, int markerStep = 1, IEnumerable xValue = null, string xField = null, IEnumerable yValues = null, string yFields = null);
public Chart AddTitle(string text = null, string name = null);
public Chart DataBindCrossTable(IEnumerable dataSource, string groupByField, string xField, string yFields, string otherFields = null, string pointSortOrder = "Ascending");
public Chart DataBindTable(IEnumerable dataSource, string xField = null);
public byte[] GetBytes(string format = "jpeg");
public static Chart GetFromCache(string key);
public Chart Save(string path, string format = "jpeg");
public string SaveToCache(string key = null, int minutesToCache = 20, bool slidingExpiration = true);
public Chart SaveXml(string path);
public Chart SetXAxis(string title = "", double min = 0, double max = 0.0 / 0.0);
public Chart SetYAxis(string title = "", double min = 0, double max = 0.0 / 0.0);
public WebImage ToWebImage(string format = "jpeg");
public Chart Write(string format = "jpeg");
public static Chart WriteFromCache(string key, string format = "jpeg");
}
}
example ...
Controler
namespace MVC3ChartTest.Controllers
{
public class ChartsController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult BasicChart()
{
return View();
}
public ActionResult BasicChartWithMasterPage()
{
return View();
}
}
}
non-strongly-typed view
#model dynamic
#{
View.Title = "BasicChart";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Basic Chart</h2>
<p>
#{
var key = new Chart(width: 600, height: 400)
.AddTitle("Staff Mobility")
.AddSeries(
name: "Employee",
xValue: new[] { "Jan", "Feb", "Mar", "Api", "May", "Jun", "Jul", "Aug", "Sep"},
yValues: new[] { "2", "6", "4", "5", "3","4","9","2","5"}
)
.Write();
}
</p>
BasicChartWithMasterPage
#model dynamic
#{
View.Title = "BasicChartWithMasterPage";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>BasicChartWithMasterPage</h2>
<p><img src="BasicChart" /> </p>
Example 2
Model
//other omitted...
using System.Collections;
using System.Web.Helpers;
namespace MVC3ChartTest.Models
{
internal class PieChartData
{
public string Title { get; set; }
public Category_Sales_for_1997[] Data { get; set; }
}
public class NorthModel
{
NorthwindEntities db = new NorthwindEntities();
List<Category_Sales_for_1997> pieData;
public Chart PieChart
{
get
{
return BuildServerPieChart();
}
}
public NorthModel()
{
pieData = db.Category_Sales_for_1997.ToList<Category_Sales_for_1997>();
}
//other omitted...
Functions to return chart
private Chart BuildServerPieChart()
{
var data = new PieChartData
{
Title = "Total: " + (from y in pieData select y.CategorySales).Sum().ToString(),
Data = (from x in pieData orderby x.CategoryName descending select x).ToArray(),
};
return BindChartData(data);
}
private Chart BindChartData(PieChartData data)
{
Chart chart = new Chart(
width: 400,
height: 300,
template: ChartTheme.Green);
chart.AddTitle(data.Title);
chart.AddLegend(title: "Lengend Title", name: null);
ArrayList x_ValueArray = new ArrayList();
ArrayList y_ValuesArray = new ArrayList();
for (int i = 0; i < data.Data.Length; i++)
{
x_ValueArray.Add(data.Data[i].CategoryName);
y_ValuesArray.Add(data.Data[i].CategorySales);
}
chart.AddSeries(
name: "Employee",
chartType: "Pie",
axisLabel: "Name",
xValue: x_ValueArray,
yValues: y_ValuesArray);
return chart;
}
Controller Action
public ActionResult Index()
{
NorthModel model = new NorthModel();
return View(model);
}
View
#model MVC3ChartTest.Models.NorthModel
#{
View.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<div>
#{Model.PieChart.Write();}
</div>
Related
I'm using the Kendo UI scheduler with the timeline view and I need to populate the left column with data from my database. I'm struggling to understand how to do it.
The part I'm talking about is where in the demo appears:
resources: [{
field: "roomId",
name: "Rooms",
dataSource: [{
text: "Meeting Room 101",
value: 1,
color: "#6eb3fa"
}, {
text: "Meeting Room 201",
value: 2,
color: "#f58a8a"
}],
title: "Room"
}]
So instead of saying "meeting Room 101", I want it to load data from the server and the number of cells will vary, so the column will be dynamic.
Is this possible? Could someone point me to a good explanation on how to do it?
I don't know if the solution is still of interest to you, but intended for Google;)
You can use the Kendo DataSource:
var rooms = new kendo.data.DataSource({
transport: {
read: {
url: "/get/rooms",
dataType: "json"
}
}
and then just assign the datasource
resources: [
{
field: "roomId",
name: "Room",
dataSource: rooms,
title: "Room"
}
Model (Example):
public class RoomResourcesModel
{
public string text { get; set; }
public int value { get; set; }
public string color { get; set; }
}
Controller (Example):
public ActionResult Rooms()
{
var model = new List<RoomResourcesModel>();
model.Add(new RoomResourcesModel { text = "Room 1", value = "1", color = "#CD6600" });
model.Add(new RoomResourcesModel { text = "Room 2", value = "2", color = "#FF3030" });
model.Add(new RoomResourcesModel { text = "Room 3", value = "3", color = "#FFD700" });
return Json(model, JsonRequestBehavior.AllowGet);
}
I have created a horizontal bar chart. I have generated the data for the bar chart from the database in the code behind.
I have two questions regarding the bar chart:
The bar charts are displaying but few of them are overlapping. I have tried setting "barPadding" and "barMargin" but that doesn't work.
I want to display label against each bar chart stating what each bar represents. These labels are retrieved from the database in code behind and stored in string array. That is against each bar in the bar chart I want to display label like "Accounts", "Telecommunication" etc. These labels are in the array retrieved from database in code behind.
Any inputs on above queries would be much appreciated.
The following is the JQPlot Script
<script type="text/javascript">
function RunTest() {
$.jqplot.config.enablePlugins = true;
<% var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();%>
var industryName = <%= serializer.Serialize(arrIndustryName) %>
industryPostings = <%= serializer.Serialize(arrIndustryPostings)%>
plot = $.jqplot('dispStats', [industryPostings], {
captureRightClick: true,
seriesDefaults: {
renderer: $.jqplot.BarRenderer,
showAngel: 135,
rendererOptions: {
barDirection: 'horizontal',
barMargin: 200,
barPadding: 500,
barWidth: 10,
highlightMouseDown: true
},
pointLabels: { show: true, formatString: '%d' }
},
legend: {
show: true,
location: 'e',
placement: 'outside'
},
axes: {
yaxis: {
renderer: $.jqplot.CategoryAxisRenderer
}
}
});
return false;
}
</script>
//asp.net button control to invoke code behind code and run the bar chart script
<asp:Button ID="btnTrends" runat="server" Text="Get Data" OnClick="GetPostingStatistics"
style="margin-right:10px"/>
<asp:Button ID="test" runat="server" Text="Show Trend" OnClientClick="return RunTest()" />
The following is the Code Behind Code
protected void GetPostingStatistics(object sender, EventArgs e)
{
string strFromDate = txtFromDate.Text;
string strToDate = txtToDate.Text;
switch (ddlTrend.SelectedValue)
{
case "Industries":
{
//Code for Sql Connection
sql = "select Value from mpats_FieldValue where FieldID =15";
cmd = new SqlCommand(sql, conn);
adapter = new SqlDataAdapter(cmd);
postingRecords = new DataSet();
adapter.Fill(postingRecords);
List<string> industryNames = new List<string>();
// Code for retrieving labels against each bar from database
foreach (DataRow name in postingRecords.Tables[0].Rows)
{
industryNames.Add(name.Field<string>("Value"));
}
int[] numberOfPostings = new int[industryNames.Count];
for (int i = 0; i < industryNames.Count; i++)
{
sql = "select count(p.PostingId) as PostingsCount from
mpats_AdvertPosting p left join mpats_Advert a on p.AdvertID =
a.AdvertID " +
"where p.PostingStatusID between 400 and 451 " +
"and a.Industry = #Industry";
cmd = new SqlCommand(sql, conn);
cmd.Parameters.Add("#Industry", industryNames[i]);
adapter = new SqlDataAdapter(cmd);
postingRecords = new DataSet();
adapter.Fill(postingRecords);
numberOfPostings[i] = Convert.ToInt32(postingRecords.Tables
[0].Rows[0]
["PostingsCount"]);
}
arrIndustryName = industryNames.ToArray();
arrIndustryPostings =
numberOfPostings;
}
conn.Close();
break;
}
default:
{
break;
}
}
}
Thanks
Shwetha
I am trying a method to bind data to the Pie chart
Public ActionResult Charts
{
Highcharts chart = new Highcharts("chart")
.InitChart(new Chart { PlotShadow = false })
.SetTitle(new Title { Text = "Browser market shares at a specific website, 2010" })
.SetTooltip(new Tooltip { Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ this.percentage +' %'; }" })
.SetPlotOptions(new PlotOptions
{
Pie = new PlotOptionsPie
{
AllowPointSelect = true,
Cursor = Cursors.Pointer,
DataLabels = new PlotOptionsPieDataLabels
{
Color = ColorTranslator.FromHtml("#000000"),
ConnectorColor = ColorTranslator.FromHtml("#000000"),
Formatter = "function() { return '<b>'+ this.point.name +'</b>: '+ this.percentage +' %'; }"
}
}
})
.SetSeries(new Series
{
Type = ChartTypes.Pie,
Name = "Browser share",
Data = new Data(new object[]
{
new object[] { "Firefox", 45.0 },
new object[] { "IE", 26.8 },
new DotNet.Highcharts.Options.Point
{
Name = "Chrome",
Y = 12.8,
Sliced = true,
Selected = true
},
new object[] { "Safari", 8.5 },
new object[] { "Opera", 6.2 },
new object[] { "Others", 0.7 }
})
});
}
}
public JsonResult GetData()
{
int Param1;
Param1 = 1;
var reports = db.ExecuteStoreQuery<ResourceReports>("ResourceReports #EmployeeID", new SqlParameter("#EmployeeID", Param1)).ToList();
return Json(reports, JsonRequestBehavior.AllowGet);
}
i want to replace
.SetSeries(new Series
{
Type = ChartTypes.Pie,
Name = "Browser share",
Data = new Data(new object[]
{
new object[] { "Firefox", 45.0 },
new object[] { "IE", 26.8 },
new DotNet.Highcharts.Options.Point
{
Name = "Chrome",
Y = 12.8,
Sliced = true,
Selected = true
},
new object[] { "Safari", 8.5 },
new object[] { "Opera", 6.2 },
new object[] { "Others", 0.7 }
})
});
}
with my GetData() how can i do this,the Data in .SetSeries should be my returned data in GetData method
It appears you are using Dotnet.Highcharts. You could create a list of Series and a list of Point.
List<Series> mySeries = new List<Series>();
List<Point> myPoints = new List<Point>();
I would loop through each series you need to create and generate the point data like so:
myPoints.Add(new Point {
X = (detailRec.RecordTime - new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds,
Y = detailRec.TotalCount
});
Then you could create the series itself using the list of points for its data like so:
mySeries.Add(new Series{
Name = distinctDistrict.Name,
Data = new Data(myPoints.ToArray())
});
Then to set the Series you could use the following statement:
.SetSeries(mySeries.Select(s => new Series {
Name = s.Name,
Data = s.Data
}).ToArray())
If you use the object browser in Visual Studio, you can see the other properties and methods of the Series and Point class. To use the above code you will have to include the the following using statements:
using DotNet.Highcharts;
using DotNet.Highcharts.Enums;
using DotNet.Highcharts.Helpers;
using DotNet.Highcharts.Options;
using Point = DotNet.Highcharts.Options.Point;
I'm trying to create charts in a view , the content (name/ series/type etc) will all be determined by the controls a user selects in the view.
As long as I load an already created chart all is fine, for example:
Inside my View:
<controls above my graph>
<img src="#Url.Action("StatusGraph")"/>
<controls below my graph>
Inside the Controller
//Creates status graph as specified by the controls in parent partial view or using defaults
public ActionResult StatusGraph(){
return View();
}
And finally the StatusGraph View: (the generic chart this microsoft tutorial uses as example)
#{
// TODO: use the data from the model to draw a chart
var myChart = new Chart(width: 600, height: 400)
.AddTitle("Chart title")
.AddSeries(
name: "Employee",
xValue: new[] { "Peter", "Andrew", "Julie", "Mary", "Dave" },
yValues: new[] { "2", "6", "4", "5", "3" })
.Write();
}
As I said this works perfectly and actually renders the chart inside the parent view as opposed in its own separate window (really microsoft, why?), However as soon as I try to extend the StatusGraph method to accept parameters (simply the chart title to start with) and pass that to StatusGraph I get a 404 error when the browser tries to load the picture.
When I set breakpoints in the extended StatusGraph method where I try to pass the title to the view, the code never stops, as if it is never called.
My question is: how can I make this work? How can I pass data from the view to an action to another view.
Thank you!
You could/should use a view model:
public class MyViewModel
{
public string Title { get; set; }
}
and then:
public ActionResult StatusGraph(MyViewModel model)
{
return View(model);
}
and finally:
#model MyViewModel
#{
var myChart = new Chart(width: 600, height: 400)
.AddTitle(Model.Title)
.AddSeries(
name: "Employee",
xValue: new[] { "Peter", "Andrew", "Julie", "Mary", "Dave" },
yValues: new[] { "2", "6", "4", "5", "3" })
.Write();
}
and when rendering the chart pass the value:
<img src="#Url.Action("StatusGraph", new { title = "Chart title" })"/>
Of course the values could also be defined in your controller action instead of passing them as parameters to the img source:
public ActionResult StatusGraph()
{
var model = new MyViewModel
{
// TODO: could come from a database or something
Title = "Chart title"
};
return View(model);
}
I'm trying to place a DropDownList inside a WebGrid but I can't figure out how to do it :(
Things I've tried:
grid.Column("Id", "Value", format: ((item) =>
Html.DropDownListFor(item.SelectedValue, item.Colors)))
and
grid.Column(header: "", format: (item => Html.DropDownList("Colors", item.Colors)))
and
grid.Column(header: "", format: Html.DropDownList("Colors"))
and various others but I couldn't get it to work.
Any help is much appreciated.
Model
public class PersonViewModel
{
public string Name { get; set; }
public int Age { get; set; }
public SelectList Colors { get; set; }
public int SelectedValue { get; set; }
}
public class ColorViewModel
{
public int ColorID { get; set; }
public string ColorName { get; set; }
}
Controller
public ActionResult Index()
{
var colorList = new List<ColorViewModel>() {
new ColorViewModel() { ColorID = 1, ColorName = "Green" },
new ColorViewModel() { ColorID = 2, ColorName = "Red" },
new ColorViewModel() { ColorID = 3, ColorName = "Yellow" }
};
var people = new List<PersonViewModel>()
{
new PersonViewModel() {
Name = "Foo",
Age = 42,
Colors = new SelectList(colorList)
},
new PersonViewModel() {
Name = "Bar",
Age = 1337,
Colors = new SelectList(colorList)
}
};
return View(people);
}
View
#model IEnumerable<PersonViewModel>
#{
var grid = new WebGrid(Model);
}
<h2>DropDownList in WebGrid</h2>
#using (Html.BeginForm())
{
#grid.GetHtml(
columns: grid.Columns(
grid.Column("Name"),
grid.Column("Age"),
grid.Column() // HELP - INSERT DROPDOWNLIST
)
)
<p>
<button>Submit</button>
</p>
}
grid.Column(
"dropdown",
format: #<span>#Html.DropDownList("Color", (SelectList)item.Colors)</span>
)
Also in your controller make sure you set the value and text properties of your SelectList and instead of:
Colors = new SelectList(colorList)
you should use:
Colors = new SelectList(colorList, "ColorID", "ColorName")
Also it seems a bit wasteful to me to define the same SelectList for all row items especially if they contain the same values. I would refactor your view models a bit:
public class MyViewModel
{
public IEnumerable<SelectListItem> Colors { get; set; }
public IEnumerable<PersonViewModel> People { get; set; }
}
public class PersonViewModel
{
public string Name { get; set; }
public int Age { get; set; }
public int SelectedValue { get; set; }
}
and then:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
// define the values used to render the dropdown lists
// for each row
Colors = new[]
{
new SelectListItem { Value = "1", Text = "Green" },
new SelectListItem { Value = "2", Text = "Red" },
new SelectListItem { Value = "3", Text = "Yellow" },
},
// this is the collection we will be binding the WebGrid to
People = new[]
{
new PersonViewModel { Name = "Foo", Age = 42 },
new PersonViewModel { Name = "Bar", Age = 1337 },
}
};
return View(model);
}
}
and in the view:
#model MyViewModel
#{
var grid = new WebGrid(Model.People);
}
<h2>DropDownList in WebGrid</h2>
#using (Html.BeginForm())
{
#grid.GetHtml(
columns: grid.Columns(
grid.Column("Name"),
grid.Column("Age"),
grid.Column(
"dropdown",
format: #<span>#Html.DropDownList("Color", Model.Colors)</span>
)
)
)
<p>
<button>Submit</button>
</p>
}
UPDATE:
And since I suspect that you are not putting those dropdownlists for painting and fun in your views but you expect the user to select values inside them and when he submits the form you might wish to fetch the selected values, you will need to generate proper names of those dropdown lists so that the default model binder can automatically retrieve the selected values in your POST action. Unfortunately since the WebGrid helper kinda sucks and doesn't allow you to retrieve the current row index, you could use a hack as the Haacked showed in his blog post:
grid.Column(
"dropdown",
format:
#<span>
#{ var index = Guid.NewGuid().ToString(); }
#Html.Hidden("People.Index", index)
#Html.DropDownList("People[" + index + "].SelectedValue", Model.Colors)
</span>
)
Now you could have a POST controller action in which you will fetch the selected value for each row when the form is submitted:
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// the model variable will contain the People collection
// automatically bound for each row containing the selected value
...
}
..make my dropdown list to select a value from the list when it loads.The following works for sure. I have tried it out myself. Any questions keep me posted.
#Html.DropDownList("RejectReason", Model.SalesReasonList.Select(u => new SelectListItem
{
Text = u.Text,
Value = u.Value,
Selected = u.Value ==#item.RejectReason
}))