UPDATE
SciChart v3.0 now supports a VerticalSliceModifier, which provides a draggable Vertical line which shows series values as Rollover style tooltips as you drag the line. You can see an example of it in action here:
- Andrew Burnett-Thompson answered 10 years ago
(I’m fairly new with SciChart myself, so I’m not sure if this is the best way to do it…)
You can look at what I’m building for a start. (Functional, but no comments yet. Hopefully the names are obvious enough)
I’m sure there will be a few extensions missing, but hopefully it’ll be obvious what they do.
When you add an annotation, it will show the textbox and tail pointers at an offset from the referenced data point.
When you zoom in and out and pan around, the annotation components will retain their relative size and offset to the point.
In edit mode, you can drag the text and reference points to new locations.
Here are two of the main extensions I know of:
public static void AddHandler(this DependencyProperty prop, object component, EventHandler handler)
{
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(prop, component.GetType());
if (dpd != null)
dpd.AddValueChanged(component, handler);
}
public static void AddHandler(this object component, DependencyProperty prop, EventHandler handler)
{
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(prop, component.GetType());
if (dpd != null)
dpd.AddValueChanged(component, handler);
}
- dwoerner answered 10 years ago
Hello Joerg,
we created an example for you. You only need to add reference on scichart.dll to run this code.
Best regards,
Yuriy
- Yuriy Zadereckiy answered 12 years ago
Hi there, and thanks for your enquiry!
It just so happens we have a sample for this already in our internal test-suite. Please see the attached.
What it does is append LabelAnnotations for the values on a Histogram plot. The solution is quite simple, it just uses this code to ensure label annotations are placed centred and above columns:
private void HistogramExampleView_Loaded(object sender, System.Windows.RoutedEventArgs e) { var series = new XyDataSeries<double, double>(); series.SeriesName = "Histogram"; var yValues = new double[] { 0.0, 0.1, 0.2, 0.4, 0.8, 1.1, 1.5, 2.4, 4.6, 8.1, 11.7, 14.4, 16.0, 13.7, 10.1, 6.4, 3.5, 2.5, 1.4, 0.4, 0.1, 0.0, 0.0 }; for (int i = 0; i < yValues.Length; i++ ) { // DataSeries for appending data series.Append(i, yValues[i]); // Annotations for text labels var labelAnnotation = new TextAnnotation() { FontSize = 10, X1 = i, Y1 = yValues[i], Text = yValues[i].ToString(), Foreground = new SolidColorBrush(Color.FromArgb(0xFF,0x33,0x33,0x33)), FontWeight = FontWeights.Bold, VerticalAnchorPoint = VerticalAnchorPoint.Bottom, HorizontalAnchorPoint = HorizontalAnchorPoint.Center }; this.sciChart.Annotations.Add(labelAnnotation); } columnSeries.DataSeries = series; }
If you wanted to do something more complex, maybe dynamically place annotations based on changing data, then you could look at this post, which describes an architecture for managing and keeping track of annotations using custom chartmodifiers.
Andrew
- Andrew Burnett-Thompson answered 11 years ago
Hi there,
Please see our KB article on How to Add Mouse Interaction to SciChart, the section on ChartModifier Precedence and Handled mouse events.
ChartModifier Precedence (Handled Events)
ChartModifiers obey a precedence, rather like WPF RoutedEvents. If you have a number of modifiers in a SciChartSurface, then the first modifier that handles an event marks it as e.Handled. Subsequent modifiers will not receive the event.
For instance, consider the following code:
If you drag the chart, then the series will not be selected too, because the RubberBandXyZoomModiifer marks MouseUp as Handled. The SeriesSelectionModifier relies on MouseUp to select. If the event is handled then it will not select.
So far this is all intuitive and good. But what about this case?
Working around event handling with ReceiveHandledEvents
The solution to the above problem is to set ReceiveHandledEvents=True on a modifier. This way the modifier will receive all events, even those marked as handled. Try the following code for instance:
Be careful with this flag though as it could enable event handling where it should not occur.
- Andrew Burnett-Thompson answered 11 years ago
SciChart v3.0 now allows detection of whether VisibleRangeChanged was fired during animation or not. Try this code below:
public void Foo() { var axis = new NumericAxis(); axis.VisibleRangeChanged += (s, e) => { if (e.IsAnimating) { // VisibleRangeChanged occurred during animation } else { // VisibleRangeChanged did not occur during animation } }; }
- Andrew Burnett-Thompson answered 10 years ago
Hi Manish,
I’ve just investigated this now – you’re absolutely right! The above code doesn’t work on the axes. Here. Try this – its a custom modifier I’ve developed which demonstrates hit testing of the YAxis and XAxis.
This code lets you detect click on axis.
public class HitTestingModifier : ChartModifierBase { public override void OnModifierMouseDown(ModifierMouseArgs e) { bool isOnChart = IsPointWithinBounds(e.MousePoint, ModifierSurface); bool isOnYAxis = IsPointWithinBounds(e.MousePoint, YAxis); bool isOnXAxis = IsPointWithinBounds(e.MousePoint, XAxis); MessageBox.Show(string.Format("Clicked YAxis? {0}\nClicked XAxis? {1}\nClicked Chart? {2}", isOnYAxis, isOnXAxis, isOnChart)); base.OnModifierMouseDown(e); } public bool IsPointWithinBounds(Point point, IHitTestable element) { var tPoint = ParentSurface.RootGrid.TranslatePoint(point, element); bool withinBounds = (tPoint.X <= (element as FrameworkElement).ActualWidth && tPoint.X >= 0) && (tPoint.Y <= (element as FrameworkElement).ActualHeight && tPoint.Y >= 0); return withinBounds; } }
If you click in the XAxis, YAxis or chart region you will get a message box showing what element has been clicked.
Example attached
Thanks!
- Andrew Burnett-Thompson answered 12 years ago
- last active 6 years ago
Thanks to Andrew, setting the ResamplingMode to Auto seems to have fixed the problem
- kewur answered 10 years ago
Hello there,
I’m investigating this now.
I can confirm if I run the application on my pc, while it doesn’t lock up by 16,000 points, it is certainly slower. What hardware do you have out of interest? It shouldn’t make much difference (unless its really slow). Mine is quad-core i7. 2.4GHz, so nothing stellar, but no sluggard either.
(BTW I’m really impressed with the SciChart application you’ve written in such a short period of time as in the trial. Nice application & really impressive job!)
Now, I ran your test application through DotTrace. The results are attached.
They make interesting reading! Basically the SciChartOverview is responsible for 40% of the time spent on the main thread. Particularly where the overview control is zooming itself to extents on each point added (on each redraw). We haven’t really optimized the overview for performance as it never raised itself as a bottleneck – it has now!
So, my first piece of advice is, remove the overview
The next interesting thing is that the axis drawing takes 10% of the time. In particular, Axis tick-drawing takes 6.4%. Remember if we remove overview all these figures double, so the tick drawing alone is quite significant.
My second recommendation is to Set AxisBase.DrawMinorTicks = false on all XAxes and YAxes
This will reduce the number of lines these are adding to the screen per frame. Axis ticks and labels are drawn using WPF canvases which are far slower than bitmap renderered series, so we want to minimise these if at all possible. If you can handle it setting AxisBase.DrawMinorGridLines = false will further improve performance since it will reduce the number of elements on the screen, however, there is only one set of gridlines for N axes and there are N sets of minor ticks, so minor ticks are the low hanging fruit here.
My third recommendation is to set SciChartSurface.RenderPriority = RenderPriority.Low
What does this do? It puts the priority of the render thread below the priority of mouse and keyboard input. This is really important as once the UI thread approaches saturation you will lose keyboard and mouse interactivity. This will really annoy your users and give you the impression that the application is ‘locked up’. By using priority low for rendering you give control back to the message loop to process mouse and key events and make your application a lot happier. The trade off is the chart rendering may appear more stuttery but it is because redraws are postponed slightly while the WPF message loop is flushed, resulting in a more fluid application experience.
If you want you can go one further and set RenderPriority.Manual. Then you are responsible for calling SciChartSurface.InvalidateElement() after appending points. For instance, you could set a timer and call InvalidateElement() every 1/10th of a second, rather than for each point appended.
My final recommendation is to throttle data appended to the chart, using the DataSeries.Append(IEnumerable<TX> xValues, IEnumerable<TY> yValues) API
The chart dataseries already do a good job of throttling data. For instance, there is not necessarily 1 redraw for each point appended. However, on each point appended some calculations are performed, such as Min Max calculations of the DataSeries, and checking internal state of the chart before pushing a redraw message onto a stack for the renderer thread to pick up. This is a small overhead but if you are calling DataSeries.Append in a tight loop it will soon add up. You can buffer or throttle appends but using the DataSeries.Append(IEnumerable<TX> xValues, IEnumerable<TY> yValues) method. Passing in arrays here of even size 10 or 100 points at a time can significantly improve throughput.
I’ve just tried the above (except for buffering Appends since that would require bigger changes to the code than I can do here) and I’m seeing task manager report a more healthy 7% CPU at ~16k points rather than the 29% I was seeing before. Can you try these and see if you get the same?
Regarding the overview, we’ll work on that. I suggest leaving it out for now and replacing with a scrollbar, calculating the offset based on XAxis.VisibleRange vs. the known DataSeries.XValues
Best regards,
Andrew
- Andrew Burnett-Thompson answered 11 years ago
Update June 2014: The Short Answer
We’ve now integrated the X and Y Values to the Rollovermodifier natively, and this is demonstrated in our examples. Please see the Realtime Cursors Example which demonstrates a Rollover with X and Y Values in the Legend area.
The Long Answer
The way it works is like this. The RolloverModifier and LegendModifier are simply data-sources, which give you an ObservableCollection<SeriesInfo> to bind to in XAML.
The Series Info classes are defined in the API documentation here:
- SeriesInfo Members
- XySeriesInfo Members
- XyzSeriesInfo Members
- OhlcSeriesInfo Members
- BoxPlotSeriesInfo Members
- BandSeriesInfo Members
Each Series has its own SeriesInfo type. All of them inherit from SeriesInfo, which is the base type. So given you are binding to a collection of SeriesInfo when you use the RolloverModifier or LegendModifier, it becomes possible to expose almost any info about the underlying RenderableSeries or DataSeries.
As a starting point please see our RolloverModifier demo, in particular the source code where we create the ItemsControl to consume SeriesInfo objects:
<!-- Binds to SeriesInfo, outputs Y-Values only -->
<!-- By modifying this and using knowledge of SeriesInfo class definition above, -->
<!-- you can theoretically do anything! -->
<Border Grid.Row="1" Margin="23,23" HorizontalAlignment="Left" VerticalAlignment="Top" Background="#77FFFFFF" BorderBrush="#55000000" BorderThickness="2" Padding="5">
<ItemsControl DataContext="{Binding ElementName=rolloverModifier}" ItemsSource="{Binding RolloverData.SeriesInfo}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Margin="3,3,20,3"
FontSize="13"
FontWeight="Bold"
Foreground="{Binding SeriesColor,
Converter={StaticResource ColorToBrushConverter}}"
Text="{Binding SeriesName}" />
<TextBlock Grid.Column="1"
Margin="3,3,3,3"
FontSize="13"
FontWeight="Bold"
Foreground="{Binding SeriesColor,
Converter={StaticResource ColorToBrushConverter}}"
Text="{Binding Value}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
Note that when you bind to XValue / YValue which are of type IComparable, you will need a converter or a StringFormat to convert from IComparable to the display value. Yes believe it or not, in XAML if you bind an IComparable which is actually a double to a TextBlock it won’t display! Please use an IComparable converter if you get blank values when binding to these properties.
In the RealTimeCursors example we see this code to convert the XValue, YValue to doubles:
<!-- When binding to XValue, YValue of type IComparable, StringFormat is mandatory due to a -->
<!-- XAML bug that cannot convert IComparable to text, even though underlying type is double -->
<StackPanel Orientation="Horizontal" Grid.Column="2">
<TextBlock Text="X: " Style="{StaticResource tbStyle}"/>
<TextBlock Text="{Binding XValue, StringFormat=\{0:0.00\}}" Style="{StaticResource tbStyle}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="3">
<TextBlock Text="Y: " Margin="3" Style="{StaticResource tbStyle}"/>
<TextBlock Text="{Binding YValue, StringFormat=\{0:0.00\}}" Style="{StaticResource tbStyle}"/>
</StackPanel>
Advanced SeriesInfo Binding
Finally, many people ask us how to bind to a specific property on the RenderableSeries or DataSeries. Well, the SeriesInfo exposes the RenderableSeries too so its possible to expose any property from the RenderableSeries. Don’t forget RenderableSeries.DataSeries also allows access from SeriesInfo right back to the original DataSeries.
- Andrew
- Andrew Burnett-Thompson answered 10 years ago
- last active 10 years ago
Hello Catalin,
Yes there is. All of our documentation is now online. Please see this related question: Where is the Documentation.
We also have a demo on Xaml styling in the examples suite, Please see our WPF Chart Xaml Styling Example
- Andrew Burnett-Thompson answered 12 years ago
- last active 9 years ago
I am considering applying server-side licensing for my javerScript application.
In the document below, there is a phrase “Our server-side licensing component is written in C++.”
(https://support.scichart.com/index.php?/Knowledgebase/Article/View/17256/42/)
However, there is only asp.net sample code on the provided github.
(https://github.com/ABTSoftware/SciChart.JS.Examples/tree/master/Sandbox/demo-dotnet-server-licensing)
I wonder if there is a sample code implemented in C++ for server-side licensing.
Can you provide c++ sample code?
Also, are there any examples to run on Ubuntu?
- Andrew Burnett-Thompson answered 12 years ago
Hello Joerg,
Axis Label styling was introduced in SciChart v3.0. You can now set a Style for a label including margins, LayoutTransforms etc…
Please see the answer on Styling Axis Labels for more information.
Best regards,
Yuriy
- Yuriy Zadereckiy answered 12 years ago
Sure, you can either use a TextAnnotation for an axis label on top of the axis. Just give the position for the Y axis, 0, yaxisMax + font height. You can also use regular Labels on top of the graph if you want to do that. I think you can also make your own custom NumericAxis to be able to do this.
The second part is easier, just make two textboxes and bind them to a property called YAxisMin YAxisMax, XAxisMin, XAxisMax. You can also bind them to your axis like this.
xAxis.SetBinding(NumericAxis.MinRange, new Binding(“XAxisMin”));
good luck.
- kewur answered 10 years ago
Hello Joerg,
As part of SciChart v3.0 all axis types now show labels at VisibleRange.Max and Min, so long as VisibleRange.Max, Min fall at ‘nice’ values, e.g. 1.0, 1.5, 2.0, 2.5 etc… By default the chart will choose these nice values when first showing or autoranging.
When you scroll however, the labels scroll too – you lose the labels at the edges of the axis. In this case you might want to use our new StaticAxis Feature, which fixes axis labels at fixed intervals and updates the label value instead.
Best regards,
Yuriy
- Yuriy Zadereckiy answered 12 years ago
- last active 8 years ago
Hi Simon,
As Nazar mentioned, it just works.
Please see the Video showing SciChart.iOS in UITableView that he created.
Best regards,
Andrew
- Andrew Burnett-Thompson answered 5 years ago
SciChart Expects Sorted X-Data
One of the underlying principles of SciChart is that data should be sorted in ascending order on the X-Axis. The reason for this is many of our users are rendering millions of points, and by far the most time is spent transforming data-points prior to render. Sorting in the X-Direction helps with this, as we can then use efficient binary search algorithms to find indices to data-points and can make several assumptions when resampling.
-
Versions 1.x and 2.x of Scichart will render and behave incorrectly
(bad rendering, glitches) if data is unsorted. -
Version 3.x will render correctly, but performance is greatly
enhanced if data is sorted in X.
Must Data always be sorted?
Actually, no. As of SciChart 3.0 you can have unsorted data in an XyDataSeries. SciChart will automatically detect the distribution of your data (Sorted, Unsorted, Evenly Spaced, Unevely Spaced, Scatter, Line) and apply the correct algorithms, meaning it should render correctly in all circumstances.
However, you will still get massive performance improvements if your data is sorted in the X direction.
What should you do if data arrives out of order?
That doesn’t help you if your data is arriving out of order you can’t append it to the end of the data series. Then, we have the ability to Update, Remove, Insert data via the XyDataSeries class.
DataSeries API Methods include:
You can also directly manipulate the data if you wish to trigger a redraw yourself. Note this does not recalculate flags such as what is the distribution of your data so be careful what you do!
Hope this helps!
- Andrew Burnett-Thompson answered 12 years ago
- last active 10 years ago
Hello lovely SciChart people,
To add to the excellent answers above by Marcell and Matt, SciChart v3.0 now supports natively persistence of properties, including annotations.
Please see the article entitled Parts of chart serialization as well as the topic category XML Serialization for more details.
Best regards,
Andrew
- Andrew Burnett-Thompson answered 10 years ago
Hi Lisbeth,
AnnotationCreationModifier is really added as a guideline on how to user-add annotations. Since you have the source code (thanks for upgrading btw!) why not create your own custom modifier which instead of adding to the SciChartSurface.Annotations collection, it handles mouse events and adds new AnnotationViewModels?
E.g. your architecture becomes something like this (refer to attached image)
SciChartSurface
Draws charts, annotations as normal. Binds to ChartViewModel which contains series data
ChartViewModel
Has 1..N AnnotationViewModels which have properties such as Color, Text, Position or other custom properties. Maybe you have a number of annotation view models such as TextAnnotationViewModel, LineAnnotationviewModel if you are mixing types
CustomAnnotationRenderingModifier
Databinds to ChartViewModel.Annotations and consumes annotationViewModels. Adds or maintains the state of 1..N annotations on the parent SciChartSurface. Only concerned with the presentation / rendering. Use the modifier from our MVVM Annotations tutorial as a basis for this.
CustomAnnotationCreationModifier
This class listens to mouse events e.g. two clicks. As the user is placing the two clicks (use our code from AnnotationCreationModifier as a basis for this) it places the line annotation on the chart. Then on completion, it removes that and creates an AnnotationViewModel to represent it. Because of databinding magic and because of the rendering modifier this will get picked up and added to the chart surface.
And hey presto, you have user-creatable annotations plus state management, colours, custom properties in a viewmodel!
Hope this helps,
Andrew
- Andrew Burnett-Thompson answered 11 years ago
An update for you, in SciChart v3.0, the SeriesSelectionModifier has now been reconfigured to trigger on MouseUp. The RubberBandXyZoomModifier sets e.Handled on MouseUp when a successful zoom occurs.
So, putting RubberBandXyZoomModifier before the SeriesSelectionModifier in a ModifierGroup means handled zooms will not cause a series to be selected. his is now demonstrated in our Series Selection Example, which has both RubberBandXyZoomModifier and SeriesSelectionModifier.
<!-- Declare ChartModifiers --> <s:SciChartSurface.ChartModifier> <s:ModifierGroup> <!-- Provides Interactivity --> <!-- NOTE: Order of Modifiers Matters because of e.Handled! --> <s:RubberBandXyZoomModifier/> <!-- Provides selection of series and custom styling to the selected series --> <s:SeriesSelectionModifier> <s:SeriesSelectionModifier.SelectedSeriesStyle> <!-- When a series is selected (on click), apply this style --> <!-- Changes SeriesColor to white on click --> <!-- Applies a PointMarker on click --> <Style TargetType="s:BaseRenderableSeries"> <Setter Property="SeriesColor" Value="White"/> <Setter Property="PointMarkerTemplate"> <Setter.Value> <!-- This is how we do PointMarkerTemplates in Scichart v2.0. You can either declare an EllipsePointMarker inline, --> <!-- or, if temmplating (because you are sharing a style across many series), then use a ControlTemplate with a BasePointMarker, --> <!-- or UIElement to replicate across each data-point --> <ControlTemplate> <s:EllipsePointMarker Fill="#FF00DC" Stroke="White" Width="7" Height="7"/> </ControlTemplate> </Setter.Value> </Setter> </Style> </s:SeriesSelectionModifier.SelectedSeriesStyle> </s:SeriesSelectionModifier> </s:ModifierGroup> </s:SciChartSurface.ChartModifier>
The RubberBandXyZoomModifier also does not start a zoom unless the user drags a few pixels, to prevent spurious handling of mouse events.
For more information about ChartModifiers and Modifier Precendence, see How to Add Mouse Interaction to SciChart.
- Andrew Burnett-Thompson answered 10 years ago