So,I have an HtmlChart that I'm using for some graphs a client of mine needs. I've managed to get everything done up just so, but I noticed when I looked at the tooltip for the points,that the points appear to be plotted in the wrong location. (See image)
I've double-checked that the tooltip is showing the correct values for the points. But as you can see in the image, the points are off.
Any help with this is greatly appreciated.
4 Answers, 1 is accepted
Turns out, but subtracting an additional .5 from the MinValues of the X and Y Axis and adding an additional .5 to the MaxValues of the X and Y Axis, it plots correctly.
So, it appears, if you set the MinValues to the minimum point values and set the MaxValues to the maximum point values + 1, the chart will not plot correctly.It doesn't make much sense to me, but at least now I have a work-around.
I tried to replicate the same situation locally, but to no avail.
Here is the code I used:
<
telerik:RadHtmlChart
runat
=
"server"
ID
=
"ScatterLineChart1"
Transitions
=
"true"
>
<
PlotArea
>
<
Series
>
<
telerik:ScatterLineSeries
Name
=
"0.8C"
MissingValues
=
"Gap"
>
<
MarkersAppearance
MarkersType
=
"Circle"
/>
<
SeriesItems
>
<
telerik:ScatterSeriesItem
X
=
"28.6"
Y
=
"89.8"
/>
<
telerik:ScatterSeriesItem
X
=
"30"
Y
=
"90"
/>
</
SeriesItems
>
</
telerik:ScatterLineSeries
>
</
Series
>
<
XAxis
MinValue
=
"27"
MaxValue
=
"35"
>
<
MinorGridLines
Visible
=
"false"
/>
</
XAxis
>
<
YAxis
MinValue
=
"84"
MaxValue
=
"91"
>
<
MinorGridLines
Visible
=
"false"
/>
</
YAxis
>
</
PlotArea
>
</
telerik:RadHtmlChart
>
And here is the result I get:
Regards,
Ianko
Telerik
I am postingg the ASP.NET code and the C# code I have in the code-behind in this post so you can create a single page ASP.NET WebForms app and duplicate the results:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="HtmlChartProblem.Default" %>
<%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
<!DOCTYPE html>
<
html
xmlns
=
"http://www.w3.org/1999/xhtml"
>
<
head
runat
=
"server"
>
<
title
></
title
>
</
head
>
<
body
>
<
form
id
=
"form1"
runat
=
"server"
>
<
div
>
<
asp:ScriptManager
ID
=
"ScriptManager1"
runat
=
"server"
></
asp:ScriptManager
>
<
telerik:RadHtmlChart
ID
=
"chartProctor"
runat
=
"server"
Width
=
"300"
Height
=
"275"
BackColor
=
"WhiteSmoke"
BorderColor
=
"Black"
BorderWidth
=
"1"
>
<
PlotArea
>
<
XAxis
AxisCrossingValue
=
"0"
Color
=
"Black"
MajorTickType
=
"Outside"
MinorTickType
=
"Outside"
Reversed
=
"false"
Step
=
"1"
Type
=
"Auto"
>
<
LabelsAppearance
DataFormatString
=
"{0:D}"
RotationAngle
=
"0"
/>
<
MajorGridLines
Color
=
"#000000"
Width
=
"1"
/>
<
MinorGridLines
Color
=
"Black"
Width
=
"1"
Visible
=
"false"
/>
<
TitleAppearance
Position
=
"Center"
RotationAngle
=
"0"
Text
=
"Moisture Content (%)"
/>
</
XAxis
>
<
YAxis
AxisCrossingValue
=
"0"
Color
=
"Black"
MajorTickSize
=
"1"
MajorTickType
=
"Outside"
MinorTickSize
=
"1"
MinorTickType
=
"None"
MinValue
=
"0"
Reversed
=
"false"
Step
=
"2"
Type
=
"Numeric"
>
<
LabelsAppearance
DataFormatString
=
"{0:D}"
RotationAngle
=
"0"
/>
<
MajorGridLines
Color
=
"#000000"
Width
=
"1"
/>
<
MinorGridLines
Color
=
"#F7F7F7"
Width
=
"1"
Visible
=
"false"
/>
<
TitleAppearance
Position
=
"Center"
RotationAngle
=
"-90"
Text
=
"Dry Density (pcf)"
/>
</
YAxis
>
</
PlotArea
>
<
Legend
>
<
Appearance
Visible
=
"false"
Position
=
"Bottom"
/>
</
Legend
>
</
telerik:RadHtmlChart
>
</
div
>
</
form
>
</
body
>
</
html
>
And here is the code I put in the code-behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Telerik.Web.UI;
namespace HtmlChartProblem
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
PlotProctorGraph();
}
private void solveTridiag(decimal[] sub, decimal[] diag, decimal[] sup, ref decimal[] b, int n)
{
/* solve linear system with tridiagonal n by n matrix a
using Gaussian elimination *without* pivoting
where a(i,i-1) = sub[i] for 2<=i<=n
a(i,i) = diag[i] for 1<=i<=n
a(i,i+1) = sup[i] for 1<=i<=n-1
(the values sub[1], sup[n] are ignored)
right hand side vector b[1:n] is overwritten with solution
NOTE: 1...n is used in all arrays, 0 is unused */
int i;
/* factorization and forward substitution */
for (i = 2; i <= n; i++)
{
sub[i] = sub[i] / diag[i - 1];
diag[i] = diag[i] - sub[i] * sup[i - 1];
b[i] = b[i] - sub[i] * b[i - 1];
}
b[n] = b[n] / diag[n];
for (i = n - 1; i >= 1; i--)
{
b[i] = (b[i] - sup[i] * b[i + 1]) / diag[i];
}
}
private void PlotProctorGraph()
{
ScatterLineSeries series = new ScatterLineSeries();
ScatterSeries scatterSeries = new ScatterSeries();
scatterSeries.LabelsAppearance.DataFormatString = "{0}";
scatterSeries.LabelsAppearance.Visible = false;
scatterSeries.TooltipsAppearance.DataFormatString = "{0}, {1}";
scatterSeries.TooltipsAppearance.BackgroundColor = System.Drawing.Color.White;
scatterSeries.Appearance.FillStyle.BackgroundColor = System.Drawing.Color.Red;
ScatterSeriesItem item;
//Simulate reading data from the database and performing calculations to determine
//point coordinates for plot. They are hard-coded here for simplicity so I don't have
//to provide the database along with this sample
// Plot 1
item = new ScatterSeriesItem(16M, 100.9M, System.Drawing.Color.Red);
scatterSeries.SeriesItems.Add(item);
// Plot 2
item = new ScatterSeriesItem(17.6M, 102.7M, System.Drawing.Color.Red);
scatterSeries.SeriesItems.Add(item);
// Plot 3
item = new ScatterSeriesItem(19.8M, 100.6M, System.Drawing.Color.Red);
scatterSeries.SeriesItems.Add(item);
// Plot 4
item = new ScatterSeriesItem(21.9M, 95M, System.Drawing.Color.Red);
scatterSeries.SeriesItems.Add(item);
chartProctor.PlotArea.Series.Add(scatterSeries);
int numberOfPoints = scatterSeries.SeriesItems.Count;
if (numberOfPoints > 1)
{
int precision = 10;
decimal[] xcoords = new decimal[numberOfPoints], ycoords = new decimal[numberOfPoints];
for (int i = 0; i <
numberOfPoints
; i++)
{
xcoords[i] = (decimal) scatterSeries.SeriesItems[i].X;
ycoords[i] = (decimal) scatterSeries.SeriesItems[i].Y;
}
series
=
new
ScatterLineSeries();
series.LabelsAppearance.DataFormatString
=
"{0}"
;
series.LabelsAppearance.Visible
=
false
;
series.TooltipsAppearance.DataFormatString
=
"{0:N1}, {1:N1}"
;
series.TooltipsAppearance.BackgroundColor
=
System
.Drawing.Color.White;
series.Appearance.FillStyle.BackgroundColor
=
System
.Drawing.Color.Gray;
series.LineAppearance.LineStyle
=
Telerik
.Web.UI.HtmlChart.Enums.LineStyle.Smooth;
series.MarkersAppearance.Visible
=
false
;
decimal[]
a
=
new
decimal[numberOfPoints];
decimal x1, x2, x, y;
decimal[]
h
=
new
decimal[numberOfPoints];
for (int
i
=
1
; i <= numberOfPoints - 1; i++)
{
h[i] = xcoords[i] - xcoords[i - 1];
}
if (numberOfPoints > 2)
{
decimal[] sub = new decimal[numberOfPoints - 1];
decimal[] diag = new decimal[numberOfPoints - 1];
decimal[] sup = new decimal[numberOfPoints - 1];
for (int i = 1; i <= numberOfPoints - 2; i++)
{
diag[i] = (h[i] + h[i + 1]) / 3;
sup[i] = h[i + 1] / 6;
sub[i] = h[i] / 6;
a[i] = (ycoords[i + 1] - ycoords[i]) / h[i + 1] - (ycoords[i] - ycoords[i - 1]) / h[i];
}
solveTridiag(sub, diag, sup, ref a, numberOfPoints - 2);
}
// note that a[0]=a[np-1]=0
// draw
for (int i = 1; i <= numberOfPoints - 1; i++)
{ // loop over intervals between nodes
for (int j = 1; j <= precision; j++)
{
x1 = (h[i] * j) / precision;
x2 = h[i] - x1;
y = ((-a[i - 1] / 6 * (x2 + h[i]) * x1 + ycoords[i - 1]) * x2 +
(-a[i] / 6 * (x1 + h[i]) * x2 + ycoords[i]) * x1) / h[i];
x = xcoords[i - 1] + x1;
item = new ScatterSeriesItem(x, y, System.Drawing.Color.Red);
series.SeriesItems.Add(item);
}
}
chartProctor.PlotArea.Series.Add(series);
}
series = new ScatterLineSeries();
series.LabelsAppearance.DataFormatString = "{0}";
series.LabelsAppearance.Visible = false;
series.TooltipsAppearance.DataFormatString = "{0:N1}, {1:N1}";
series.TooltipsAppearance.BackgroundColor = System.Drawing.Color.White;
series.Appearance.FillStyle.BackgroundColor = System.Drawing.Color.Gray;
series.LineAppearance.LineStyle = Telerik.Web.UI.HtmlChart.Enums.LineStyle.Smooth;
series.MarkersAppearance.Visible = false;
//Normally the arrays would contain data from the database, but as the values are hard-coded
//for simplicity, I hard-code the array values here
chartProctor.PlotArea.XAxis.MinValue = Convert.ToDecimal(GetMinNumber(new string[] { "16", "17.6", "19.8", "21.9" }) - .5);
chartProctor.PlotArea.YAxis.MinValue = Convert.ToDecimal(GetMinNumber(new string[] { "100.9", "102.7", "100.6", "95" }) - .5);
chartProctor.PlotArea.XAxis.MaxValue = Convert.ToDecimal(GetMaxNumber(new string[] { "16", "17.6", "19.8", "21.9" }) + 1.5);
chartProctor.PlotArea.YAxis.MaxValue = Convert.ToDecimal(GetMaxNumber(new string[] { "100.9", "102.7", "100.6", "95" }) + 1.5);
}
protected double GetMaxNumber(string[] arrNumbers)
{
double MaxNumber = 0;
foreach (string strNumber in arrNumbers)
{
if (strNumber.Length > 0)
{
if (Convert.ToDouble(strNumber) > MaxNumber)
{
MaxNumber = Convert.ToDouble(strNumber);
}
}
}
return MaxNumber;
}
protected double GetMinNumber(string[] arrNumbers)
{
double MinNumber = 1000000000;
foreach (string strNumber in arrNumbers)
{
if (strNumber.Length > 0)
{
if (Convert.ToDouble(strNumber) < MinNumber)
{
MinNumber = Convert.ToDouble(strNumber);
}
}
}
return MinNumber;
}
}
}
This produces the graph in the image file attached.
The encountered result is due to the used formatting. The used one ({0:D}) rounds the value. Thus, 102.5 will become 103. This is applied only to the labels, thus, plot area is accurately rendered. It is the X and Y labels that mislead that points are not rendered at the proper position.
I suggest you using proper formatting that does not round values. You can see this article on the matter—http://docs.telerik.com/kendo-ui/framework/globalization/numberformatting. On my end using this formatting works properly: DataFormatString="{0:n1}".
Regards,
Ianko
Telerik