I'm having an issue where my chart is displaying values on that minmum axis that should be below that axis. This is using a PointTemplate to show a BarSeries as points. This happens for both logarithmic and linear axes. Example is as follows:
<
Window
x:Class
=
"ZeroLogAxis.MainWindow"
xmlns:telerik
=
"http://schemas.telerik.com/2008/xaml/presentation"
Title
=
"MainWindow"
Height
=
"350"
Width
=
"525"
>
<
Grid
>
<
telerik:RadCartesianChart
>
<
telerik:RadCartesianChart.Resources
>
<
DataTemplate
x:Key
=
"PointTemplate"
>
<
Ellipse
Width
=
"8"
Height
=
"8"
VerticalAlignment
=
"Top"
Margin
=
"-4,-4,0,0"
Fill
=
"Black"
/>
</
DataTemplate
>
<
Style
TargetType
=
"telerik:BarSeries"
>
<
Setter
Property
=
"PointTemplate"
Value
=
"{StaticResource PointTemplate}"
/>
</
Style
>
</
telerik:RadCartesianChart.Resources
>
<
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:DateTimeContinuousAxis
LabelFitMode
=
"Rotate"
LabelFormat
=
"dd-MMM-yy"
/>
</
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LinearAxis
Minimum
=
"3"
Maximum
=
"6"
/>
</
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:RadCartesianChart.Series
>
<
telerik:BarSeries
Name
=
"BarSeries"
/>
</
telerik:RadCartesianChart.Series
>
</
telerik:RadCartesianChart
>
</
Grid
>
</
Window
>
Code Behind:
public
MainWindow()
{
InitializeComponent();
for
(
int
i = 1; i < 6; i++)
BarSeries.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint()
{ Category = DateTime.Today.AddDays(i), Value = i });
}
With a Minimum="3" on my VerticalAxis, I would expect to see half of the "3" point, and the full 4 and 5 point. However, I'm also seeing half a point on the axis for the 1 and 2 values, as indicated by the red arrows in the attached screenshot.
Any suggestions on how to not display points that should not be on the chart?
Thanks,
Louis
15 Answers, 1 is accepted
Here's an even stranger result.
Using a log axis:
<
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LogarithmicAxis
Minimum
=
"0.1"
Maximum
=
"10"
/>
</
telerik:RadCartesianChart.VerticalAxis
>
and a bit different data:
for
(
int
i = 0; i < 11; i++)
BarSeries.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint()
{ Category = DateTime.Today.AddDays(i), Value = i/5.0 });
Now even points that should be on the chart are shown at value 1 (some half points, some full) instead of being where they should be!
The described behavior is observed because the BarSeries of the chart always starts drawing its visual elements from the Minimum of the numeric axis. In order to achieve your requirement you can consider using PointSeries or RangeBarSeries instead of BarSeries. Please try this and let me know if it works for you.
Regards,
Martin
Telerik
Thanks Martin, at least the explanation makes sense. I thought there was a reason I couldn't use PointSeries, but cannot recall what it was. This component was started ​more than 2 years ago, so maybe the chart support has changed since then.
However, just trying to ​change my logarithmic example above to use PointSeries instead still shows an incorrect point for value 0 (shown at 1). See attached. Changing the Min to 0 does hide points past 0, but 0 point is still a problem. Linear axis seems to work correctly.
Thanks again,
Louis
Sorry, I take it back about making sense on the log chart. It's not starting at the Minimum of the numeric axis (0.1), it's in the middle of the axis (1.0). Your explanation makes sense for the linear chart though.
Louis
We are unsure why you have decided to use a BarSeries and make it look like a PointSeries via a PointTemplate.
The reason that the points are incorrectly plotted in the first image you attached is because the BarSeries considers its visuals to be bars. Bars do not have their own desired size and are usually positioned between the 0 (the origin) and the value in mind. However, these are coerced when they are not in the visible area, so the bar is positioned at the bottom of the chart. If you were to use a template that does not have a desired size - the bar would be given a height of 0 and would not be visible. In your case, the template does have a desired size and the Ellipse is rendered.
You can avoid this by simply using the PointSeries, because we think that this is what you intended. Perhaps two years ago, when you started the project, the chart didn't have a built-in support for point series, but now it does and you should take advantage of that. If you had contacted us two years ago, I think that we would have proposed to use a LineSeries (with a transparent stroke) because it has a much more similar notion.
Let us know if you have any other questions.
Regards,
Petar Marchev
Telerik
Hi Petar,
As I mentioned a few posts above, PointSeries has the same problem. Please see PointSeries.png above. Non-zero points below the minimum of the log axis are not displayed (correctly). However, points with value 0 are displayed on the bottom axis (regardless of value).
Louis
I created a small project based on the code you provided. Find the project and images attached.
Chart1.png - I used a logarithmic axis and a bar series with a point template. When I run the project, I get to see a chart with points in it, where the points do not seem to match the data of the series. Some of the points get clipped. Both of these effects are due to the point template you have used. The clipping occurs due to the data point visual having a height of 0 and the incorrect positioning is due to the choice of combination of series and a point template with horizontal alignment top.
Chart2.png - I used a point template similar to the first one, but also added a border so that it is clear where the Bar is displayed. Now it should be clear why the points were displayed in a manner that seemed mismatched (because of the VerticalAlignment Top). As Martin mentioned earlier, the bars are drawn from the origin of the axis to the value.
Chart3.png - I used a point series with no template and the chart is properly rendered. I suggest you update your chart to use a point series and no point template (use the DefaultVisualStyle if you need to customize the points and the chart's Palette don't work for you).
As I explained, the behavior you observe with a bar series and a point template is due to the nature of the bar and the template you chose to use. The chart may have not supported a point series two years ago, but it does now, so it makes no sense not to use it.
If you think that I did not address all your questions properly, please send us an atomic response that contains the code you use, the output you get and the question you have. I ask this because if you refer to a previous image or code, it may not be very clear to which you are referring to. Thank you for understanding.
Regards,
Petar Marchev
Telerik
Hi Petar,
Thanks for the reply. However, if you look at your own Chart3.png again, you'll find that your first point, of value 0, is actually showing incorrectly on your chart on the 1 log line.
This appears to be a general problem with the Log axis. LineSeries has the same problem. Here's a full example for you.
PointSeries: Every other point has value 0. Notice that all the 0 points are being show on the 1 log value; these shouldn't be shown on the chart at all.
LineSeries: Starts > 0, goes down to 0, then below 0.Notice that all the 0 and negative values are being shown on the 1 log value. Here again, the 0 and negavie points shouldn't be shown on the chart at all.
Thanks,
Louis
<
telerik:RadCartesianChart
>
<
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:DateTimeContinuousAxis
LabelFitMode
=
"Rotate"
LabelFormat
=
"dd-MMM-yy"
/>
</
telerik:RadCartesianChart.HorizontalAxis
>
<
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:LogarithmicAxis
Minimum
=
"0.1"
Maximum
=
"10"
/>
</
telerik:RadCartesianChart.VerticalAxis
>
<
telerik:RadCartesianChart.Series
>
<
telerik:PointSeries
Name
=
"PointSeries"
/>
<
telerik:LineSeries
Name
=
"LineSeries"
/>
</
telerik:RadCartesianChart.Series
>
</
telerik:RadCartesianChart
>
And the code behind:
public
MainWindow()
{
InitializeComponent();
for
(
int
i = 0; i < 11; i++)
{
PointSeries.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint()
{Category = DateTime.Today.AddDays(i),
Value = i%2 == 0 ? 0 : i/5.0});
LineSeries.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint()
{ Category = DateTime.Today.AddDays(i),
Value = 4.0-i/2.0 });
}
}
Your original question was about a BarSeries with a point template not being plotted properly. If we have now resolved this, and you have a new question about how the logarithmic axis chooses to plot its items, you can open a new thread. I ask this because we prefer to keep issues separated, because it is easier to follow a conversation.
A short answer to your inquiry here - the 0 and negative values are undefined in the context of a logarithmic axis, due to the nature of the logarithm. We have chosen one very simple way to handle these undefined cases. The chart can't simply close its eyes for these data points, it must calculate some LayoutSlot for them, because after all, the user put them there. If you want these values not to appear, you can simply not add them.
Let us know if you need more information.
Regards,
Petar Marchev
Telerik
Hi Petar, thanks for the reply.
I don't think we've resolved the orignial issue, as it is still an issue for BarSeries even without point templates (see below). Now that we understand it better, it's more an issue with logarithmic axes than any particular type of series, so if you're able to edit the subject please go ahead and rename it to something more appropriate for future searchers.
For my part, I think your explanation is sufficient to close the need for any further discussion. I will open a support ticket instead, since there doen't seem to be a reasonable work-around. Simply not adding 0 data points would be like saying you have to remove data points that are below your "Minimum" value on any of your axes; not reasonable for something working with real data, and certainly not something you'd expect to have to do with toolkit controls. Not drawing points/bars/lines that fall below the minimum value of your axis isn't "simply closing its eyes", it's doing what the control was asked to do by the establishment of a minimum on that axis.
A more reasonable handling of points that fall off the bottom of a log axis would be to "plot" them at double.Epsilon (the smallest positive number), which yields the expected chart (see epsilon.png) for lineseries and pointseries (not actually plotting them at all). This was achieved by substituting the following in my above example for the point generation:
PointSeries.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint()
{Category = DateTime.Today.AddDays(i),
Value = i%2 == 0 ?
double
.Epsilon : i/5.0});
LineSeries.DataPoints.Add(
new
Telerik.Charting.CategoricalDataPoint()
{ Category = DateTime.Today.AddDays(i),
Value = Math.Max(
double
.Epsilon,4.0-i/2.0) });
Again, not something that should be necessary in production code.
Interestingly, doing this shows that what's actually happening with BarSeries is that the bars are being drawn from 1 to the desired value, whether that is going up or down. This means any BarSeries on a Log axis with values < 1 will be incorrect. See barseries.png.
Thanks again,
Louis
From what you are saying it is obvious that the issue here is not resolved. I see no value in having the ticket you opened, because it essentially has the same content, same requirements. This is why I have decided to close it. Let us continue our communication in a single location, otherwise it will get too hard to follow.
"not reasonable for something working with real data"
I am sure that even in real data scenarios you should be able to have a separate source for the chart that does not contain these undefined values. While this could be considered a work-around, we think that it is easy to implement.
"A more reasonable handling of points that fall off the bottom of a log axis would be to "plot" them at double.Epsilon"
Again I want to emphasize on the fact that these values are undefined. This means that everybody has the right to interpret them in the way they find appropriate. While we understand that in your case, plotting them as double.Epsilon is adequate, we do not think that this is the case in general. We have decided to plot them at 1 (the origin of the log axis) because it was the easiest thing to do. We do not have any strong argument against your proposal not to plot them at all. Plotting these undefined values as 1 may mislead the reader. The only argument I have is that these are undefined values in the context of the log axis and it is better if they do not appear in the items source at all.
We like your proposal and will most likely implement this change - do not plot these values at all, because their position cannot be determined.
"Interestingly, doing this shows that what's actually happening with BarSeries is that the bars are being drawn from 1 to the desired value, whether that is going up or down. This means any BarSeries on a Log axis with values < 1 will be incorrect. See barseries.png."
If you are saying that the bars are drawn incorrectly, because they always start at 1, you are mistaken. You can see in other charts, too (such as in Excel) that bars are indeed drawn from the origin of the axis, which in this case is 1. This is by design and it is the correct behavior of the bar series when using a logarithmic axis.
Regards,
Petar Marchev
Telerik
Hi Petar,
Sorry about the "duplicate" ticket. I thought this was for discussions, and support tickets was for things like bug reports needing action. I'll talk with our development manger here to see how he wants to proceed.
Yes, we could have a separate source for the chart that does not contain 0 values (or rather, contains double.Epsilon values, since not having the values will again produce the wrong results on a line chart). However, this is at the expense of more code to maintain, more processing required, and more memory consumed. It is also quite messy if you're adhering to the MVVM design principals, as this is clearly a view-related work around, and thus strictly speaking should be in the View layer.
"This means that everybody has the right to interpret them in the way they find appropriate." - But it should be done in such a way as to produce a chart that looks least-unreasonable to a user. My impression was that it was done the way it was expecting that the minimum axis value would be 1; it doesn't look too bad when this is the case. It really breaks down when the minimum axis drops below 1, as in my examples.
"most likely implement this change - do not plot these values at all" - Note that this doesn't work for line charts, as that would presumably connect the 2 surrounding points directly. double.Epsilon produces something that looks more accurate for line charts. (Not plotting works just as well as double.Epsilon for bar and point charts however.)
"If you are saying that the bars are drawn incorrectly, because they always start at 1, you are mistaken. You can see in other charts, too (such as in Excel) that bars are indeed drawn from the origin of the axis, which in this case is 1." - Please review barseries.png again. The origin of the axis is not 1, but rather 0.1, and the bars are not being drawn from the origin of the axis, but rather down from 1 to the actual value (all the way down for the 0 values, but only part way down for the values between 0 and 1).
Louis
Perhaps I was unclear when I said that zero and negative values are undefined. This also means that the chart struggles with them, does not how to show them, so it is best not to have them at all. It is not strictly a View related thing, because this is invalid mathematically - there is no power of 10 that would result in a negative number, so it should not be in the items source in the first place.
You mentioned that dropping the points will result in a wrong chart. When plotting a chart with a log axis and a line series that has some negative values - there is no correct way to do it. The negative values cannot be located, hence there is no way to properly connect the points, because you do not know where all the points are. Excel has a strategy to resolve this, and our chart may adopt that strategy, too.
I examined the barseries.png again and I can say with certainty that the bars start from 1 (the origin of the log axis). Note how all bars start from 1 and stretch all the way to wherever the value should be, regardless of whether this is up or down.
Note that it is common for the log axis to have its origin at 1. If you need a different layout you can use a range bar series.
I hope you understand that the core problem here is not how the chart handles zero and negative values, but that the zero and negative values simply make no sense here. You cannot find the position of the zero on the axis and you cannot plot such a value. For an example, you can open an Excel and create a chart with a log axis and negative values. Excel prompts a message explaining the problem.
Let us know if you need more information.
Regards,
Petar Marchev
Telerik
Hi Petar, thanks for the reply! I think we're getting closer to a common understanding.
Yes, I absolutely understand the problem, that 0 and negative values are undefined on a log chart (would be plotted at negative infinitiy). My preference in deciding how to show the un-showable is to use the principle-of-least-astonishment, and draw something that doesn't look blatently wrong given the difficult situation.
I disagree that it's not a View related thing, because how you are visualizing the data is a View thing itself. The same data set can be shown on a Linear chart, Logarithmic chart, data table, etc. Removing those points from your collection means you have to have a different collection depending on how it's being viewed. This probably falls into the category of opinion or religion, so I'll agree to disagree here.
"I examined the barseries.png again and I can say with certainty that the bars start from 1 (the origin of the log axis)." - Terminology got us mixed up here... I completely agree that it starts from 1; I interpreted "origin of the log axis" to be the lowest value on the axis, which was 0.1. I wasn't aware of 1 being commonly used as the origin.
Thanks again for the reply!
Louis