Formatting Data into Chart C# WPF - c#

I have a database where a user can select a date range and pull the data back. This is saved into three columns, Date, Time, Value. if it's temperature it's a Line Chart, if it's a Meter it's Bar Chart.
I have the below code but it's not working, I'm getting confused how to send this data.
Setting different values:
eChartType chartType = eChartType.ColumnClustered;
if (plotName.Contains("temp") || plotName.Contains("Temp"))
{
chartType = eChartType.Line;
}
var chart = worksheet.Workbook.Worksheets.AddChart($"{plotName} Chart", chartType);
var label = worksheet.Cells["A2:B2571"];
var values = worksheet.Cells["C2:C2571"];
chart.Chart.Series.Add(label, values);
chart.Chart.Legend.Position = eLegendPosition.Right;
Throwing all information into bottom area of chart and not in chart.

You should try something different like this:
//not chart type you should change it.
//change var to int and chart to double or float as you will wish
// again change var into int and worksheet is equal to ToString in C# then take off the string "" and change the : to referring after that you should just change 3 main things
// change chart to double or float suggesting float here because of the complex
// Chart is not good!!!! you can get the position in many different ways just set a .point = new Location (X,Y) then just set it twice and not once

Related

C# Chart control : X value of a horizontal bar chart is 0 for all points in the serie

I have a horizontally stacked bar chart in my app, and I'm trying to figure out how to get the X axis value when the user clicks on a bar. The problem is when I look at the values at runtime, the Y values are fine but the X values are all 0.
Screen capture
In the image above, light blue bars are from Series[0] and represent the MTD sales and the darker ones from Series[1] represent last year's sales for the same month. My goal is that when the user double-clicks on a bar, he is taken to the detailed sales report for that salesperson.
I haven't tried switching my chart to a regular bar chart because this is what I will need to look like in the end. But I'm starting to wonder if the reason I'm getting all 0's in the XValue field is because of this or because I am using strings as the type of value.
Has anyone ever encountered this or have any clues as to how to fix it?
Screen capture of points at runtime
You use one of the Bar chart types.
They have their x-axis and y-axis switched compared to most normal types.
Therefore in order to get the values along the horizontal axis you actually want to grab the y-values.
To get at the y-value of the double-clicked datapoint you can do a HitTest like in this code:
private void chart1_MouseDoubleClick(object sender, MouseEventArgs e)
{
var hit = chart1.HitTest(e.X, e.Y, ChartElementType.DataPoint);
if (hit.PointIndex >= 0)
{
DataPoint dp = hit.Series.Points[hit.PointIndex];
Console.WriteLine(dp.YValues[0]);
}
}
Note however that in a stacked bar the values look stacked but each point will still only have its own value.
If you wanted to get at the stacked/summed up values you would have to add up all points below and including the one that was hit. 'Below' here means points at the same x-slot but in lower series!
You will not be able to use the x-values if you have added them as strings since in that case they will all be 0, as you can see in your screenshot.
But since all stacked points in your case will have the same e.PointIndex we can use this to access all points in the series below..:
..
int si = 0;
double vsum = 0;
Series s = null;
do
{
s = chart4.Series[si++];
vsum += s.Points[hit.PointIndex].YValues[0];
} while (hit.Series != s);
Console.WriteLine(vsum);
If you actually want to access the x-values you have two options:
You can explicitly add the strings to the AxisLabel of each DataPoint. While the x-values will still be all 0 the AxisLabels now can be accessed.
Or you can add them as numbers, maybe using some scheme to map the strings to numbers and back and, again set the AxisLabels.
OK so I finally managed to put custom labels on the chart using the Chart.Customize event.
Here is the data I am using for this chart:
Vendeur | Total | idDepartement | idEmploye | TotalLastYear
Ghislain 5256.30 1 56 0.00
Kim 12568.42 1 1 74719.18
Philippe 17565.27 1 44 38454.85
I changed X axis XValueType to Double, and the XValueMember to idEmploye.
Result
As you can see, it's not very user friendly to have employee id's on a chart. This is where the Customize event gets useful.
Here is my event:
private void chart1_Customize(object sender, EventArgs e)
{
// Set X axis interval to 1, label will be centered (between 0.5 and 1.5)
chart1.ChartAreas[0].AxisX.Interval = 1;
double startOffset = 0.5;
double endOffset = 1.5;
chart1.ChartAreas[0].AxisX.CustomLabels.Clear();
// Cycle through chart Datapoints in first serie
foreach (System.Windows.Forms.DataVisualization.Charting.DataPoint pt in chart1.Series[0].Points)
{
// First get the dataset used for the chart (from its bindingsource)
DataSet dsSales = (DataSet)bsViewVentesParUtilisateurSignsMoisCourant.DataSource;
// Second get the datatable from that dataset based on the datamember
// property of the bindingsource
DataTable dtSales = (DataTable)dsSales.Tables[bsViewVentesParUtilisateurSignsMoisCourant.DataMember];
// Get a dataview and filter its result based on the current point's XValue
DataView dv = new DataView(dtSales);
dv.RowFilter = "idEmploye=" + pt.XValue.ToString();
// Get the "Salesperson" (or "Vendeur") column value from the first result
// (other rows will have the same value but row 0 is safe)
string firstname = dv.ToTable().Rows[0].Field<string>("Vendeur").ToString();
// Create new customlabel and add it to the X axis
CustomLabel salespersonLabel = new CustomLabel(startOffset, endOffset, firstname, 0, LabelMarkStyle.None);
chart1.ChartAreas[0].AxisX.CustomLabels.Add(salespersonLabel);
startOffset += 1;
endOffset += 1;
}
}
Final result
I am very happy with the result. And now when I double-click on a bar in the chart, I can get the employee id from the X value and generate the code to get the detailed sales report for that person for the given month.

Incorrect empty datapoints display in a fastline chart

I have a fast-line chart series where on X I have DateTime and on Y double values - series is added to the chart with such method:
public virtual bool AddOrUpdateSeries(int caIndex, Series newSeries, bool visibleInLegend)
{
var chartArea = GetChartArea(caIndex);
if (chartArea == null) return false;
var existingSeries = _chart.Series.FirstOrDefault(s => s.Name == newSeries.Name);
if (existingSeries != null)
{
existingSeries.Points.Clear();
AddPoints(newSeries.Points, existingSeries);
}
else
{
newSeries.ChartArea = chartArea.Name;
newSeries.Legend = chartArea.Name;
newSeries.IsVisibleInLegend = visibleInLegend;
newSeries.BorderWidth = 2;
newSeries.EmptyPointStyle = new DataPointCustomProperties { Color = Color.Red };
_chart.Series.Add(newSeries);
}
return true;
}
As you can see, I am setting the style for empty point to be shown in red.
The first points that are added to the series are as follows:
So as you can see, first two points have the same Y value, but in addition -
first one has IsEmpty flag set.
Empty point is added to the series with such piece of code:
series.Points.Add(new DataPoint
{
XValue = _beginOADate,
YValues = new[] { firstDbPoint.Y },
IsEmpty = true
});
where _beginOADate is double OADate value = 42563 = 12/07/2016 00:00 as DateTime.
The second point's DateTime is 15/08/2016 22:20
When chart is displayed with the beginning of the X axis, everything looks ok as on the picture below - empty datapoint starts at 12/07/2016 and lasts until 15/08/2016.
But, when I scroll one position on X, the empty datapoint's red line is not being displayed - instead, whole visible part of empty datapoint's line is displayed as it is non-empty:
Anybody knows how to fix this behaviour so that the whole line starting from Empty datapoint until first non-empty datapoint would always be shown in red?
Of course the dummy solution would be to add one more extra empty datapoint very close to the first non-empty point, but I don't like that solution.
The ChartType.FastLine is much faster the the simple Line chart but to be so fast it makes several simplifications in rendering, which means that not all chart features are supported:
The FastLine chart type is a variation of the Line chart that
significantly reduces the drawing time of a series that contains a
very large number of data points. Use this chart in situations where
very large data sets are used and rendering speed is critical.
Some charting features are omitted from the FastLine chart to improve
performance. The features omitted include control of point level
visual attributes, markers, data point labels, and shadows.
Unfortunately EmptyPointStyle is such a 'point level visual attribute'.
So you will need to decide which is more important: The raw speed or the direct and plausible treatment of empty DataPoints.
(I have a hunch that you'll go for your 'dummy solution', which imo is a 1st class workaround ;-)

How to make points more compact using fastpoint chart in

I am new to C# winform. As title, my problem is how to make the points more compact in fastpoint chart. To make it clear, how to proportionally reduce the distance of the blue points like the red line segments shown in the image; that is, make the X axis more compact:
I have searched and found a lot of information about control the interval of X or Y axis labels but which is not the situation here.
You can control the range of data values for each Axis by setting their Minimum and Maximum values.
The syntax is:
someChart.ChartAreas[CAIndexOrName].AxisX.Minimum = someDoubleValue;
Let's prepare a chart to show one day:
Axis ax = chart.ChartAreas[0].AxisX; // a short reference
ax.IntervalType = DateTimeIntervalType.Hours;
ax.Interval = 1;
To set the properties to some DateTime values you need to convert them to doubles; for this conversion there are two built-in functions: DateTime.ToOADate and, to reverse DateTime.FromOADate
This makes the x-axis display 24 hours:
DateTime dt = DateTime.Today;
ax.Minimum = dt.ToOADate();
ax.Maximum = (dt.AddHours(24)).ToOADate();
ax.LabelStyle.Format = "H:mm"; // optional
You also may want to control the data type of the series values:
Series s = chart.Series[0];
s.XValueType = ChartValueType.DateTime; // or some other type, maybe Time
Note you you can also control both the Interval of the Labels and TickMarks and Gridlines on each axis but also set an Offset to start them a little earlier or later..

How to get chart data points value with equal or less than to highlight those data

I'm looking to change my chart series data points if there is an error values. I want to set rule to highlight those data points like below. Please help to get below code working.
// Find first point with a Y2 value of equal or less than 10.
var dataPoint = Chart1.Series[1].Points.Where(x => x.YValues <= 10);
foreach (DataPoint dt in dataPoint)
{
dt.BorderDashStyle = ChartDashStyle.Dot;
dt.Color = Color.Red;
}
DataPoint.YValues is an array.
The YValues property is used to set the Y-values of data points.
Only one Y-value per point is required for all chart types except
bubble, candlestick and stock charts. These chart types require more
than one Y-value because one data point consists of multiple values.
For example, to plot one stock chart column, four values are required:
high, low, open and close values.
The YValues property returns an array of double values when used to
retrieve the Y-values.
Important The YValuesPerPoint property determines the maximum number
of Y-values that all data points in a Series can have. If you specify
more than the allowable number of Y-values, an exception will be
raised.
Unless you are using one of the above special ChartTypes you always will want to use the first element. So simply write:
var dataPoint = Chart1.Series[1].Points.Where(x => x.YValues[0] <= 10);
If you do use one of the three multiple Y-Values chart types you could, depending on the situation for example write this:
var dataPoint = Chart1.Series[1].Points.Where(x => x.YValues.Max() <= 10);
or this:
var dataPoint = Chart1.Series[1].Points.Where(x => x.YValues.Min() <= 10);

Setting startdate on line chart

I am trying to figure out how to my start the X axis in my line chart at the first date in stored in an object. I have been trying for quite some time now, and I am not sure what I am doing wrong. Any help would be appreciated.
It simply says that I can't convert from DateTime to Double, which makes sense, but I have no clue how to get around this.
I have indented the part of the code I am trying to make work. Thanks in advance!
private void loadChart(List<Temperatur> templist)
{
// clear charts
this.chart1.Series.Clear();
this.chart2.Series.Clear();
// add Data to charts
Series series = this.chart1.Series.Add((templist.ElementAt(0).Date).ToString());
Series series2 = this.chart2.Series.Add((templist.ElementAt(0).Date).ToString());
// defines type of chart
series.ChartType = SeriesChartType.Line;
series2.ChartType = SeriesChartType.Line;
// sets line thickness
series.BorderWidth = 3;
series2.BorderWidth = 3;
// sets chart limits and intervals
chart1.ChartAreas[0].AxisY.Maximum = 42;
chart1.ChartAreas[0].AxisY.Minimum = 35;
chart1.ChartAreas[0].AxisY.Interval = 0.5;
//sets X axis labels
chart1.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Days;
chart1.ChartAreas[0].AxisX.Minimum = Convert.ToDouble(templist.ElementAt(0).Date);
// removes legend from chart
chart1.Legends[0].Enabled = false;
chart2.Legends[0].Enabled = false;
foreach (Temperatur tempObj in templist)
{
// Add point.
series.Points.Add(Convert.ToDouble(tempObj.Temp));
}
foreach (Temperatur tempObj in templist)
{
// Add point.
series2.Points.Add(Convert.ToInt32(tempObj.Puls.ToString()));
}
}
You can add DataPoints in several formats.
You want them to have a X-Value of type DateTime and an Y-Value of type double, so use a call like this:
series.Points.AddXY(tempObj.Date, tempObj.Temp);
If you want to start the display at a Minimum you need to use the key of the Points collection, if the X-Values are dates it will be a date, if they are numbers (doubles by default) you use a number.
If you never have set the X-Values they will start at 0 by default (which will be shown as 1899 when cast to a DateTime..)
Doing so is a little tricky, as the Minimum only accepts doubles; that's because even when your type is set to DateTime and even though you have added DateTime X-Values, internally they still are stored as double.
To set the Minimum etc after you have added the DataPoints with their X-Values as DateTimes you can use :
int yourStartIndex = 1;
chart1.ChartAreas[0].AxisX.Minimum = series.Points.ElementAt(yourStartIndex).XValue;
To control the displayed X-Axis label set its Format; here is an example:
chart1.ChartAreas[0].AxisX.LabelStyle.Format = "dd.MM.\\'yy hh\\h";
Note the added 'h' and the added apostrophe resulting in something like: 21.03'15 12h

Categories