In the last post on this topic I showed you how to pull down weather information from your local METAR station and persist it using XPO. In this post we’ll go ahead and use that persisted information to graph some interesting weather data.
First thing we’re going to do is to add a new win forms project to our solution to provide a front end for our graphing application. We’ll add folders for Helpers, Model and Views too:
After that we’ll start the coding by pointing XPO at the Access database we created in the last post. We’ll do this in the form load event:
private void MainView_Load(object sender, EventArgs e)
{
//GS - Connect to the access database created earlier
XpoDefault.ConnectionString =
AccessConnectionProvider.GetConnectionString("pathToYourAccessDatabaseFile");
}
Next we’ll create a UI that will allows us to graph three interesting pieces of weather data; wind speed by direction, temperature fluctuation throughout a day and the prevailing wind direction for this area:
Starting with wind speed by direction, what we’ll do is handle the button click event:
private void btnNorth_Click(object sender, EventArgs e)
{
//GS - Display northerly wind speeds
DisplayWindSpeedByDirectionWithTitle("Northerly Wind Speeds", "N");
}
by calling a method to display the data:
private void DisplayWindSpeedByDirectionWithTitle(string title, string direction)
{
//GS - Get all the Northerly wind direction reports
XPQuery<Report> reportQuery = new XPQuery<Report>(XpoDefault.Session);
var reports = from r in reportQuery
where r.WindDirection.StartsWith(direction)
select r;
//GS - Ask a helper method to create a chart from this info
ChartControl chart = ChartHelper.CreateBarChartFromLinqResult("WindSpeed", "TimeStamp", title, reports);
//GS - Ask a helper method to display this chart
ViewHelper.DisplayChart(chart);
}
This method will firstly use a linq statement to get all the weather reports where the wind direction starts with the required direction: “N” for North; “S” for South; etc. The next thing it will do is call a helper method, passing in the chart title, the qualitative and quantitative properties of the Report object and the result of the linq query. Lastly, this method then calls another helper method in order to display the chart returned by the first helper method.
Let’s have a look at this first helper method:
public static ChartControl CreateBarChartFromLinqResult(
string valueMember,
string dataMember,
string title,
IQueryable<Report> reports)
{
ChartControl chart = new ChartControl();
chart.Titles.Add(new ChartTitle { Text = title });
chart.Legend.Visible = false;
//GS - Create an empty Bar series and add it to the chart.
Series series = new Series(title, ViewType.Bar);
chart.Series.Add(series);
//GS - Supply the data
series.DataSource = reports.ToList<Report>();
//GS - Bind the data
series.ArgumentScaleType = ScaleType.Qualitative;
series.ArgumentDataMember = dataMember;
series.ValueScaleType = ScaleType.Numerical;
series.ValueDataMembers.AddRange(new string[] { valueMember });
//GS - Dock the chart into its parent
chart.Dock = DockStyle.Fill;
//GS - Return the chart
return chart;
}
This method is fairly simple, all it does is create a new chart object and add a series to it. We then attach our linq results as the data source and then tell the chart how to bind to that data. Finally, we set the dock style to fill and return the chart to the calling method.
The second helper method is simpler still:
public static void DisplayChart(ChartControl chart)
{
ChartViewer viewer = new ChartViewer();
viewer.Controls.Add(chart);
viewer.Show();
}
It takes in a chart object and instantiates a ChartViewer form before adding the chart to the form’s controls and then showing the form.
So having explained how we do it, let’s have a look at the results, pressing the “North” button yields this chart:
The remaining “South”, “East” and “West” buttons are a repeat of the same pattern so there is no point in going over those.
The next thing we are going to look at is charting the temperature fluctuations throughout the day. To do this we select a date and press the “Chart” button:
The event handler for the “Chart” button is shown below:
private void bntChartWindSpeedByDay_Click(object sender, EventArgs e)
{
//GS - Get the selected data
DateTime target = dateTimePicker1.Value;
XPQuery<Report> reportQuery = new XPQuery<Report>(XpoDefault.Session);
var reports = from r in reportQuery
where r.TimeStamp.Date == target.Date
select r;
//GS - If there is no matching data for the target date then we're done
if (reports.Count<Report>() < 1)
return;
//GS - Ask a helper method to create a chart from this info
ChartControl chart = ChartHelper.CreateBarChartFromLinqResult(
"Temperature", "TimeStamp",
String.Format("Temperatures for: {0}", target.Date.ToLongDateString()),
reports);
//GS - Ask a helper method to display this chart
ViewHelper.DisplayChart(chart);
}
As you can see, we follow a similar pattern to that already discussed, whereby we execute a linq query against the XPO source, passing the result to a helper method which constructs and returns a chart object and we then pass that chart object to another helper function which displays the chart. The result of selecting a date and pressing the “Chart” button is shown below:
The last interesting piece of information that we are going to graph is the prevailing wind direction. The event handler for the “Show Prevailing Wind Direction” button is shown below:
private void btnMeanWindDirection_Click(object sender, EventArgs e)
{
//GS - Fetch all the reports
XPQuery<Report> reportQuery = new XPQuery<Report>(XpoDefault.Session);
var reports = from r in reportQuery
select r;
//GS - Ask a helper method to create a pie chart of the directionCounts
ChartControl chart = ChartHelper.CreateWindDirectionPieChart(reports);
//GS - Ask a helper method to display this chart
ViewHelper.DisplayChart(chart);
}
You will recognise this now familiar pattern of executing a linq statement and then passing the result to a helper method to construct and return a chart object before passing that chart object, in turn, to another helper method to display the chart. The only difference this time is the helper method which constructs the chart is different, let’s take a look at it now:
public static ChartControl CreateWindDirectionPieChart(IQueryable<Report> reports)
{
ChartControl chart = new ChartControl();
chart.Titles.Add(new ChartTitle { Text = "Prevailing Wind Direction" });
chart.Legend.Visible = true;
//GS - Create an empty Bar series and add it to the chart.
Series series = new Series(String.Empty, ViewType.Pie3D);
series.LegendPointOptions.PointView = PointView.ArgumentAndValues;
series.PointOptions.ValueNumericOptions.Format = NumericFormat.Percent;
chart.Series.Add(series);
//GS - Supply the data
List<WindDirectionCount> directionCounts = new List<WindDirectionCount>();
directionCounts.Add(
new WindDirectionCount
{
Direction = "North",
Count = reports.Count<Report>(x => x.WindDirection.StartsWith("N"))
});
directionCounts.Add(
new WindDirectionCount
{
Direction = "South",
Count = reports.Count<Report>(x => x.WindDirection.StartsWith("S"))
});
directionCounts.Add(
new WindDirectionCount
{
Direction = "East",
Count = reports.Count<Report>(x => x.WindDirection.StartsWith("E"))
});
directionCounts.Add(
new WindDirectionCount
{
Direction = "West",
Count = reports.Count<Report>(x => x.WindDirection.StartsWith("W"))
});
series.DataSource = directionCounts;
//GS - Bind the data
series.ArgumentScaleType = ScaleType.Qualitative;
series.ArgumentDataMember = "Direction";
series.ValueScaleType = ScaleType.Numerical;
series.ValueDataMembers.AddRange(new string[] { "Count" });
//GS - Dock the chart into its parent
chart.Dock = DockStyle.Fill;
//GS - Return the chart
return chart;
}
This helper method is similar, but a little different, to the previous one. Again it creates a chart object and adds a series to it. The series is a little different this time though:
//GS - Create an empty Pie series and add it to the chart.
Series series = new Series(String.Empty, ViewType.Pie3D);
series.LegendPointOptions.PointView = PointView.ArgumentAndValues;
series.PointOptions.ValueNumericOptions.Format = NumericFormat.Percent;
chart.Series.Add(series);
As you can see we are creating a pie chart this time and so we use the PointView.ArgumentAndValues enum to specify that we want to show the wind direction as well as the values and the NumericFormat.Percent enum to specify that we want to show the values as a percentage of the total.
We then go on to count the number of weather reports that state the wind was from a particular direction (N, NNW all count as North etc.) and we go ahead and store this information in a list of objects we created for that purpose. These objects are very simple in nature and they are defined like so:
using System;
namespace XPOWeather2
{
public class WindDirectionCount
{
public string Direction { get; set; }
public int Count { get; set; }
}
}
Then we set the data and bind to is as before, specifying the qualitative and the quantitative properties, before finishing by asking the same helper method to display the chart. The result of all this is shown below:
As you can see, the prevailing wind direction in this part of the world is shown as westerly (which it actually is!).
Well that about wraps it up for this post, ‘til the next time, happy XPOing!