Possible cross point function bug - delphi

I'm evaluating TChartProVCL for XE3.
I created 2 manual series:
1) Series1, a stair-step line
2) Series2, a simple line intersecting Series1 at various points
I then created a calculated series, X Cross Points, which should be the cross points of Series1 and Series2.
It looks fine, except at x=6, and x=5.6 (approx.) This looks like a bug to me.
My ultimate goal, FYI, is to color the regions inside the series. A TRegionBandTool would get close, but I need to color the areas above and below Series1 with different colors.

I'm afraid the TCrossPointsFunction doesn't support sources set with the Stairs mode.
I've added it to the wish list to be implemented in future releases.

In the case of using the "stair-step" series with the TCrossPointsFunction I've discovered a simple "cheat" that is good enough for my purposes. I merely:
Turn OFF the stair-step property.
Create the stair step effect by placing two points very close together on the X axis.
For example:
const
UPPER = 85;
LOWER = 75;
begin
SysThresh.Clear;
for i := 0 to 8 do
SysThresh.AddXY(i, UPPER);
SysThresh.AddXY(8.001, LOWER);
SysThresh.AddXY(12.999, LOWER);
for i := 13 to 25 do
SysThresh.AddXY(i, UPPER);
This gives me the stair step effect without confusing the TCrossPointsFunction.

Related

TChart axis labels overlapping when using a lot (more than 100) of TLineSeries

I'm dealing with an application that abuses TChart with potentially hundreds of TLineSeries. I get unreadable X axis labels, because they overlap. According to this, that shouldn't happen, but it does.
I'm now looking for a way to completely disable X axis labels derived from the TLineSeries elements and only show calculated labels at regular intervals, e.g. no labels for individual data points. How would I do that?
The misbehaving application:
My failed attempt to replicate the problem:
If the Bottom Axis for the chart has a scale set with Automatic turned off (default is on) you can get overlap like that depending on your data, the desired increment and if Show all labels is checked.
However your example seems to show non-regular extra labels which might just be manually added using the Items (show in far right tab) or something else to add more axis labels.
I was finally able to reproduce the problem with a small test case. Turns out that the problem was, that the application used function TChartSeries.AddXY(Const AXValue, AYValue: TChartValue; Const ALabel: String; AColor: TColor): Integer; and provided a value for ALabel. Using only X and Y values fixed the problem.

Vaadin heatmap does not support 40x40 (1600) points?

In Vaadin 14.6.1, I tried to create a Vaadin heatmap foollowing the documentation / example from here.
However, I encountered a few problems/questions, listed in descending order of importance below:
The heatmap supported 30 rows by 30 columns; but when I tried 40 rows by 40 columns, the entire heatmap showed a single color (blue in my case).
Is it possible to manually set the minimum numeric value and maximum numeric value for the color scheme. This way, if I plot my data one day and it has values in the range of 0 to 1, but on another dataset from another day, the numeric values range from between 0 and 0.5, the color scheme range won't automatically change (to being between 0 and 0.5) and confuse the user.
In the documentation, it has the following methods listed, but they do not seem to exist in Vaadin 14.6.1
plotOptions.setBorderColor(SolidColor.WHITE);
plotOptions.setBorderWidth(2);
When I hover over the datapoints, is there a way that the tooltip can only show the numeric value (and not the x, y coordinate or the series name etc.?)
Is there any limit to the number of datapoints? I'm hoping that if #1 above is resolved that I can plot a 100 by 100 (ie 10,000) point heatmap.
If I plot 100by100, there will be many labels on the x and y axis. In my case, the x and y axis are actually numerical, so I did what the documentation suggested and just placed category labels in the xaxis and yaxis spots. However, is there any way to only display every "nth" label, so that the x-axis and y-axis is not so crowded? (This would essentially mimic what Vaadin does for normal line charts' xaxis and yaxis).
I'm not that experienced with Vaadin Chart, but these are the questions that I can comment on:
(1) With 40x40 items you go over the threshold of 1000 in which the Chart switches into "turbo" mode for performance reasons. This seems to not be compatible with the heatmap series. You can disable turbo mode by setting plotOptions.setTurboThreshold(0);
(2) Unfortunately the ColorAxis doesn't support this, it only has an API for min and max color. Definitely a valid use-case though, and it seems to be supported by the Highcharts library that the Vaadin Chart uses under the hood. You should consider opening a feature request for this in the Github repo.
(3) This seems to be a documentation issue. The methods are available in later Vaadin platform versions, but not in 14.6.
(5) In theory not, but in practice there will be a huge performance hit in the browser due to the excessive amount of DOM elements (quick test of 100x100 froze the browser for 10s). I'm afraid the component isn't really made for such extreme use-cases. In this case it might be better to utilize a low-level JS drawing library using the canvas, or draw an image on the server-side and display that in the browser. Maybe you can also consider modifying your use-case so that you only display one slice of your data and allow the user to switch between slices.

Howto draw on every pixel, the min and max values of huge TeeChart FastLine series while DrawAllPoints:= false?

With Delphi 10.3, VCL and build-in standard TeeChart. Windows 10 x64.
I've a huge data samples, few millions, to view.
My target is to show the minimum and maximum values related to each pixel.
i.e the minimum and maximum values in a data segment which are drawn due to a screen decimation in one pixel.
Due to processing time response, I tried DrawAllPoints := false.It is x30 faster!
I think in this case, TeeChart is drawing the value of the first sample from the relevant segment.
Thus the min/max values are not drawn.
With DrawAllPoints := true, everything is fine.
I'm also allowing the user to Zoom/Unzoom.
I could define my own short TeeChart series, limited to the number of pixels myself.
However, it is not so trivial due to the user's Zoom option.
Is there any feature in TeeChart for that? i.e DrawAllPoints := false while drawing min and max of a segment on each pixel.
Maybe there is a call back routine or heritage routine I could force this behavior?
Thanks.
Set DrawAllPointsStyle property of series into daMinMax.
Seems some difference does exist.
for var i := 1 to 100000 do begin
Series1.Add(Sin(i/10000) + Random); // left one, daMinMax is set
FastLineSeries1.Add(Sin(i/10000) + Random);
end;

Setting the Left Axis on a TChart to increment the decimal value up to .13?

This question relates to another ongoing question here: Format Stones and Pounds correctly?
I figured it would be more suitable to ask here as a separate question, before deciding what to do.
As described from the link above, I am representing weight in a TChart as stones and pounds.
Before I decide on whether to change the data type I am currently using (Double) as the comments from above suggest, I want to see how I can display my chart in Stones and Pounds as I originally had in mind.
See this sample image I manipulated for demo purposes:
The problem is the left Axis of the chart, as the notes in the image state - the chart increments up to .99 (Pounds) before reaching the next whole number (Stones in this case). For example:
03.00
02.99 < .99 = max number before reaching 3.00
02.98
02.97
I need the Left axis to be setup like so:
03.00
02.13 < .13 = max number before reaching 3.00
02.12
02.11
02.10
And also display all the labels for the pounds part.
Is there a setting somewhere that I can use to set the max value for the .00 (lbs) before reaching the next whole number (stones)?
At the moment nothing seems to be making a lot of sense, From what I understand from the other question is I should be using Integers and representing as Pounds only.
I want to see how it could look before making any changes though, ideally I want the chart to stay near the same as the image if possible.
Hope this makes sense.
Thanks.
UPDATE
Just thought I would update the changes I eventually got working.
All credit has to go to David Heffernan for his persistence in explaining where I was going wrong, and writing detailed information and advice.
There is still some work I need to do, but for now here is the updated chart I now have:
I have not done the values in labels, but from the sample image above this is the values I used:
15.2
15.3
15.11
15.13
16.0
16.4
You can't use your current representation to plot a reasonable chart. Suppose you have a bar chart with the following values:
10st 12lb
10st 13lb
11st 0lb
11st 1lb
The chart will look like this:
Forget about the axis labelling for a moment. Look at the difference between the bars. The difference between each adjacent value is 1lb. But the graph tells a completely different story. I've used a bar chart here, but the principle applies for all chart types.
The bottom line is that you need to represent your weight values with a true decimal representation of the weight. Your representation does not obey basic laws of arithmetic. So, half a stone must be 0.5. Trying to represent a half with the number 0.07 is simply asking for a world of pain.
Use this formula to convert from stones and pounds to a true floating point representation of the weight:
FloatingPointWeightValue := Stones + Pounds/14.0;
Or if you store only the pounds then it is simply
FloatingPointWeightValue := Pounds/14.0;
I would suggest that you make sure that the Increment of the axis is at least 1. If you need to go smaller than that then you'll have to get into custom axis label titles. And when you add your values, give them a label. This will allow the chart to use sensible labels to identify values. For example:
Series1.Add(10 + 12/14, '10st, 12lb');
Series1.Add(10 + 13/14, '10st, 13lb');
Series1.Add(11 + 00/14, '11st, 0lb');
Series1.Add(11 + 01/14, '11st, 1lb');
And the result looks like this:
You'd obviously write a bunch of helper functions to handle this. I'd suggest storing the raw data as pounds. So, 11st 1lb would be stored as 11*14 + 1 = 155. Then you'd have these helpers:
function StonesFromPounds(Pounds: Integer): Double;
begin
Result := Pounds / 14.0;
end;
function StonesPoundsLabel(Pounds: Integer): string;
begin
Result := Format('%dst %dlb', [Pounds div 14, Pounds mod 14]);
end;
And then the data population would look like this:
Pounds := 152;
Series1.Add(StonesFromPounds(Pounds), StonesPoundsLabel(Pounds));
You have complete freedom with how you create text labels for your weights. If you want something less verbose than 10st 13lb then you can adjust the helper functions to your needs.
Now, this has been quite a long answer, so I will summarise my advice:
When you acquire the data, from what ever source, convert from whichever format they arrive in to a well-defined storage format, the raw data format.
Store this raw data as integer values, in units of pounds.
When you plot the weights, convert to floating point values in units of stones by Stones := Pounds/14.0.
Associate text labels to each value that you plot so that you can present the weights in human readable form.
Be prepared to supply custom label axes if you need to label weights in between whole values of stones.

TChart - Dont plot values that are less than 0?

Introduction
I am using the TChart component and am finding the options rather confusing and hard to find what I need.
The Left Axis of the chart has a minimum of 0 and a maximum of 5000, the Bottom Axis has a minimum of 0 and a maximum of 52 (weeks in a year).
In my chart I have 2 series that are populated based on values from a record I have created which can be edited at runtime, everything is working good so far.
Problem
Take a look at the below image of part of the chart filled with some random values:
I am not sure if such an option exists or not, but notice from week 4 onwards where no values have been added there is a solid red line.
I don't want the chart to plot values that are less than 0, so in this example from week 4 onwards there should be no more lines (I can confirm that from week 4 onwards I have the values set at -1)
Week 1 to 4 does not show this bottom red line, obviously because the values are greater than 0 and are therefore plotted above the line, but this should make my problem a bit more clearer.
So, how do I prevent the chart from plotting / drawing values that are less than 0, importantly for the Bottom Axis of the chart?
I am sure there must be a simple option somewhere, I just cannot find it if there is one as I am not too familiar with the TChart Component.
You have the possibility when adding values to a series to add them as null.
This will prevent them from showing.
Ken is correct saying that a tricky situation is to handle a single value surrounded by null values.
Picking another series type than FastLine and show dots as well as lines might work better.
For a FastLine series to show gaps, set:
Series1.IgnoreNulls := False;
And to discriminate values below zero:
if (y < 0) then
Series1.AddNullXY(x, y, '')
else
Series1.AddXY(x, y, '');
if y < 0 then
LineSeries1.AddXY(x, y, '', clNone)
else
LineSeries1.AddXY(x, y, '', clRed);

Resources