Pre loader

1

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

4 votes

Hello Joerg,

we created an example for you. You only need to add reference on scichart.dll to run this code.

Best regards,
Yuriy

4 votes

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!

1 vote

I’m afraid this isn’t possible in v1.3 of SciChart but in v2.0 or greater we introduced Multiple X,Y Axis feature.

What you would have to do is register the series on a separate X,Y Axis and zoom that X,YAxis to extents by using our Axis Interactivity API.

For a demo of Multiple X and Y Axis, please see here:
http://http://www.scichart.com/Abt.Controls.SciChart.SL.ExampleTestPage.html#/Abt.Controls.SciChart.Example;component/Examples/IWantTo/ModifyAxisBehaviour/MultipleXAxes.xaml

You will notice the series can be scaled separately by dragging the Y and X Axes.

Next, you can look at our Axis Interactivity APIs and Axis Members to find methods to control that specific axis.

Here are functions throughout the API which can assist in getting axis ranges to perform zoom to fit. For instance:

AxisBase.GetMaximumRange

/// <summary>
/// Gets the Maximum Range of the axis, which is equal to the DataRange including any GrowBy factor applied
/// </summary>
/// <returns></returns>
public abstract IRange GetMaximumRange();

DataSeries.GetWindowedYRange(IRange visibleXRange)

/// <summary>
/// Gets the YRange of the data (min, max of the series) in the input visible range point range, where the input range is the <see cref="IAxis.VisibleRange"/>
/// </summary>
/// <param name="xRange">The X-Axis Range currently in view</param>
/// <returns>The YRange of the data in this window</returns>
/// <exception cref="System.ArgumentNullException">xRange</exception>
/// <exception cref="System.InvalidOperationException">Invalid Range Type. Please ensure you are using DateTimeAxis where the X-Data is DateTime, and NumericAxis where the X-Data is Double, Float, Int, Long</exception>
public IRange GetWindowedYRange(IRange xRange);

DataSeries.GetWindowedYRange(IndexRange indicesRange)

/// <summary>
/// Gets the YRange of the data (min, max of the series) in the input IndexRange, where indices are point-indices on the DataSeries columns
/// </summary>
/// <param name="xIndexRange">The X-Axis Indices currently in view</param>
/// <returns>
/// The YRange of the data in this window
/// </returns>
public IRange GetWindowedYRange(IndexRange xIndexRange);

Also if you’re interested in writing custom zoom to fit, I would suggest looking at the source code (which you have access to), SciChartSurface.ZoomExtents(), ZoomExtentsY() methods as these have custom logic in them to determine zoom to fit on a per-axis basis.

0 votes

Hi Sam,

I’m pretty sure that when a line is selected it goes to the top of the Z-order. Can you verify this? Changing Canvas.ZOrder will have no effect on the lines as they are rendered as bitmaps, and you are correct in saying that the order of series will change the order that they are rendered.

Let me know if you need further assistance with this.

0 votes
In reply to: Modifier Surface bug?

Hi Miles,

Are you aware of WPF Snoop? A tool for inspecting the visual tree and debugging WPF applications? I’ve attached a screenshot to show me snooping SciChart to determine the bounds of the parent surface.

As you can see the SciChartSurface extents to the bounds of the user control and there is a padding inside of 20,20,15,15. This means the mouse leave event won’t fire so long as the mouse is within that red highlighted area.

To work around this, you can do the following. In your Xaml declare a border and place the SciChartSurface inside it with a padding of zero, and margin of 20,20,15,15

<Border Background="#333">
   <s:SciChartSurface Padding="0" Margin="20,20,15,15">
       <!-- etc ... -->
   </s:SciChartSurface>
</Border>

This will have the effect of making the 20 pixel border outside of the parent surface so when the mouse moves into this region, OnParentSurfaceMouseLeave will correctly fire.

If on the other hand you want to know if the mouse is inside the chart grid area, or either axis, you can use some aspects of the hit-test API to do this.

Please see this forum post, specifically the “HitTestModifier” which demonstrates where a mouse click is.

http://http://www.scichart.com/questions/question/rubberbandxyzoommodifier-onmodifiermousedown/

Best regards,

4 votes

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?

1 vote

Hi Catalin,

Please see this answer on how to modify the Grid Line Tick Interval.

There are two methods there, a simple and complex one for precise control over the output of the Axis.

Hope this helps!

3 votes

Hi Miles,

SciChart is only configured to draw two gridlines, major and minor. There are three ways I can suggest you do this (or close enough)

a.) Simplest way, manually calculate Major, MinorDelta

Configure the chart by setting AutoTicks=False and set the MajorDelta, MinorDelta to weeks and months.

See this KB article on Axis Gridlines, Ticks, Label Formatting which shows how to set MajorDelta, MinorDelta and AutoTicks to get simple adjustment of the tick frequency.

In SciChart a TimeSpan of one month is defined as this:

private const double DaysInMonth = 365.2425 / 12.0;

// Usage, 3 month timespan defined by Timespan t = FromMonths(3)
public static TimeSpan FromMonths(int numberMonths)
{
    return TimeSpan.FromDays(numberMonths * DaysInMonth);
}

This would achieve you month, week gridlines but not day. As you zoom in you could however switch the Major,Minor delta of the chart to show weeks and days.

more b. Complex way, use the TickProvider API

In SciChart v3.0 and above, there is now a way to override the exact Tick Intervals.

See this KB article on Advanced Tick Frequency Overriding which introduces the TickProvider API. This allows exact calculation of ticks (Axis Major, Minor gridlines and labels) as the axis is drawn.

Hope this helps!

3 votes

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!

0 votes

Hi Egbert,

I’ve spent some time investigating this today. Ok – you highlight a genuine issue with SciChart, but there is a workaround.

I ran your sample (Thanks for that – very helpful) through a profiler. The results are posted below as a screenshot. As you can see there are 12,000 calls to ZoomExtentsY() internally within SciChart, one per Dataseries.Append call.

In your MainViewModel you have a method like this:

private void FillData(IDataSeries<DateTime, double> dataSeries)
{
    for (int i = 0; i < 3000; i++)
    {
         // Each DataSeries.Append call triggers a redraw. Although rendering is 
         // buffered off the UI thread, the ZoomExtents() calculation performed by SciChart
         // when a new axis has an uninitialized VisibleRange is costly. 
         dataSeries.Append(new DateTime(2011, 01, 01).AddDays(i), _random.NextDouble());
    }
}

I modified this slightly to append all 3000 points in one go, like this

private void FillData(IDataSeries<DateTime, double> dataSeries)
{
    var xValues = new DateTime[3000];
    var yValues = new double[3000];

    // Precalculate all x,y values into arrays
    for (int i = 0; i < 3000; i++)
    {
        xValues[i] = new DateTime(2011, 01, 01).AddDays(i);
        yValues[i] = _random.NextDouble();
    }
 
    // Append in one block - triggers a single redraw
    dataSeries.Append(xValues, yValues);
}

The result is the axis renders immediately.

Another way of resolving the problem is to set a VisibleRange on the axis before adding it to SciChart. In your example because the axis had AutoRange=False, but also a null VisibleRange, SciChart tries to compute the zoom-extents of the axis on every single data-point add. This occurs until the axis range has been calculated (after first render).

to test this, keep your original FillData code but set NumericAxis.VisibleRange = new DoubleRange(0, 1) on each axis. You will see the axes also render immediately with this optimisation.

I hope this has resolved the issue for you (and for your client)!! Thank you for bringing this to our attention, as performance is our highest priority.

Best regards,

0 votes

Hi Egbert,

Got it. Ok I suppose you are using MVVM similar to the exampl you posted over? If so then you can use the following properties to show/hide lines and their axes:

private void ToggleAxisVisibility()
{
    var rSeries = RenderableSeries.LastOrDefault();
    rSeries.IsVisible = !rSeries.IsVisible;

    var axis = YAxes.GetAxisById(rSeries.YAxisId);
    ((AxisBase) axis).Visibility = rSeries.IsVisible ? Visibility.Visible : Visibility.Collapsed;
}

I’ve also attached the MainViewModel / MainView to this post. Try this (its from your SpeedTest sample). The button “Hide an Axis” toggles the visibility of the last series and its associated axis.

Best regards,
Andrew

0 votes

Hi Marcel – as requested (on email) I’ve attached the example we used to create the screenshot above. This uses the following code to set the DefaultPointWidth. It requires SciChart v1.3.1.1107, which is available on our downloads page.

If you have any problems, or if it still doesn’t work – let me know.

Best regards,
Andrew

4 votes

Hi Miles,

This is because all mouse clicks are relative to the parent SciChartsurface. If you want to get the coordinates relative to the ModifierSurface itself, you have to perform a simple translation operation.

public override void OnModifierMouseMove(ModifierMouseArgs e)
{
   // gets the bounds of the ModifierSurface with respect to the RootGrid
   // which hosts the SciChartSurface
   var modifierRect = ModifierSurface.GetBoundsRelativeTo(RootGrid);

   // Translates the mouse point (from root grid coords) to ModifierSurface coords
   var mousePoint = base.GetPointRelativeTo(e.MousePoint, ModifierSurface);
}

Can you try the above translation and let me know if it works?

0 votes

Hi,

This seems to work fine.
I’m using the following code to hide and show all axis and labels, so there will be more space for the graph itself.

        private void ShowHideAllAxis()
        {
            this.AllAxisVisible = !this.AllAxisVisible;

            for (int seriesCnt = 0; seriesCnt &amp;lt; RenderableSeries.Count; seriesCnt++)
            {
                var rSeries = RenderableSeries.ElementAt(seriesCnt);
                var axis = YAxes.GetAxisById(rSeries.YAxisId);

                if (rSeries.IsVisible)
                {
                    Visibility visibility = ((AxisBase)axis).Visibility;
                    if (visibility == Visibility.Visible)
                    {
                        ((AxisBase)axis).Visibility = Visibility.Collapsed;
                    }
                    else
                    {
                        ((AxisBase)axis).Visibility = Visibility.Visible;
                    }
                }
            }
        }

The original graph looks good (GridProblem01).
But when removing/hiding the axis and labels, the graph is growing but the grid not.
I'm missing some grid lines on the right site of the graph (GridProblem02)

Any idea?

0 votes

Hi Toshiyuki,

You may be interested in this answer on Fixing Data Values that Arrive in Non Sorted DateTime Order as this covers the DataSeries API, including ability to Add, Remove, Insert, Update points in detail.

Hope this helps!

0 votes

Hi Miles,

cool chart! Ok I think I know what’s going on here. The RolloverModifier internally performs a hit-test on all series, and aligns itself to the X-values of the series, before showing the Y-Values. Therefore, it assumes that data-points are located in the same position in the X-axis across all series. We’ve not tested it with series with varying or differing X-values.

It sounds to me like you may need a custom modifier to do this. Are you able to share any data we can use to test? Just a CSV file with X,Y values for the three top series and one of your main series. You can send me this on email if you want to keep it off the forum.

Best regards,
Andrew

0 votes

Hi Miles,

I have an idea for you! There is a property in the ModifierMouseArgs called IsMaster. When this is true, the modifier triggered the event, else it is getting it from another modifier.

To make use of this, try the following:

// Note: not compiled this, but it demonstrates the principle
public class IgnoresSlaveEventsRolloverModifier : RolloverModifier
{
   public override void OnModifierMouseMove(ModifierMouseArgs e)
   {
      if (e.IsMaster)
      {
          base.OnModifierMouseMove(e);
      }
   }
}

Now register the IgnoresSlaveEventsRolloverModifier on your first chart and use a normal RolloverModifier on the second chart. Mouse over the first chart and both should receive the event, but mouse over the second and only the second should receive the event.

1 vote

Hello Icube,

In Wpf the touch events are promoted to the mouse equivalent, if they are unhandled, so you could use existing modifiers instead of creating your own. But if you need, you could subscribe to manipulation events on Modifier surface and implement desired behavior:

        public override void OnParentSurfaceRendered(SciChartRenderedMessage e)
        {
            base.OnParentSurfaceRendered(e);

            if (!_isSubscribed)
            {
                SubscribeModifierSurface();
                _isSubscribed = true;
            }
        }

        private void SubscribeModifierSurface()
        {
            ((ChartModifierSurface)ModifierSurface).ManipulationStarted += OnManipulationStarted;
            ((ChartModifierSurface)ModifierSurface).ManipulationCompleted += OnManipulationCompleted;
        }

What about zoom, RubberBandXyZoomModifier allows to zoom in specific selected area on the chart (please, see this example: http://http://www.scichart.com/Abt.Controls.SciChart.SL.ExampleTestPage.html#/Abt.Controls.SciChart.Example;component/Examples/IWantTo/ZoomAndPanAChart/DragAreaToZoom.xaml ). If your desired functionality is different, please, tell us and we will be glad to help.

If you have any more questions, don’t hesitate to ask!
Best regards,
Yuriy

0 votes

Hi Sam,

You can try this technique: http://http://www.scichart.com/questions/question/sharing-mouse-events-one-way/

Someone asked only yesterday how to prevent mouse events going from one chart to another. The solution was to override OnModifierMouseMove on the modifier in question and selectively call the base method.

It would be verbose but if you created derived types of the modifiers you are using, then overrode the OnModifierMouseDown, OnModifierMouseMove, OnModifierMouseUp events you could detect mouse on specific modifiers.

Another method – a lot simpler – you can subscribe to ((Grid)SciChartSurface.RootGrid).PreviewMouseDown and in there, stop adjusting visible range. Then subscribe to MouseDoubleClick to restore visible range adjustment.

Can you try those and let me know how you get on?

0 votes

Hi Manish,

A really simple way to solve this is to set text formatting to condition decimal places, for instance, instaed of the default value of “0.###” use “0.#######”. This way you will get up to 6 decimal places if the precision exists.

Alternatively you can use engineering notation. Try a value of “#.###E+0” for text formatting to keep maximum 3 decimal places, but the exponent can be used to add precision.

SciChart also provides scientific notation. This can be seen on our Logarithmic Axis demo:
http://http://www.scichart.com/Abt.Controls.SciChart.SL.ExampleTestPage.html#/Abt.Controls.SciChart.Example;component/Examples/IWantTo/ModifyAxisBehaviour/LogarithmicAxisView.xaml

The text-formatting is engineering notation but also this property is set to get the exponent in superscript: ScientificNotation=”Normalized”

Finally if that’s not enough I would suggest listening to XAxis.VisibleRange changes and dynamically setting the TextFormatting as the chart zooms.

Best regards,

Showing 21 - 40 of 6k results

Try SciChart Today

Start a trial and discover why we are the choice
of demanding developers worldwide

Start TrialCase Studies