ASE Home Page Products Download Purchase Support About ASE
ChartDirector General
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  Multiple XYCharts in one MultiChart
Posted by Philip on Oct-08-2020 03:00
Hello Peter,

I have been experimenting with the example RealTimeZoomScrollWindow. It shows an XYChart with three lines (Alpha, Beta and Gamma).

In the GUI I added a checkbox called "separate". My intention was to toggle between one XYChart showing 3 lines with 3 stacked XYCharts each showing 1 line. For stacked XYCharts I have to create a MultiChart and then add each XYChart to the MultiChart.

I renamed the existing drawChart() to drawMyChart(). Then I created a new drawChart():

private void drawChart(WPFChartViewer viewer)
{
    // dimensions of a XYChart
    int widthOfXyChart = 640;
    int heightOfXyChart = 350;
    if (separate.IsChecked == false)
    {
        // XYChart will contain 3 lines
        drawMyChart(viewer, widthOfXyChart, heightOfXyChart, -1, null);
    }
    else
    {
        int numberOfCharts = 3;
        // multi-chart will contain 3 XYCharts
        int widthOfMultiChart = widthOfXyChart;
        int heightOfMultiChart = heightOfXyChart * numberOfCharts;
        MultiChart mc = new MultiChart(widthOfMultiChart, heightOfMultiChart);
        viewer.Chart = mc;
        for (int i = 1; i <= numberOfCharts; i++)
        {
            drawMyChart(viewer, widthOfXyChart, heightOfXyChart, i, mc);
        }
    }
}


private void drawMyChart(WPFChartViewer viewer, int widthOfXyChart, int heightOfXyChart, int lineId, MultiChart mc)
{
    // Get the start date and end date that are visible on the chart.

    ...

    // Extract the part of the data arrays that are visible.

    ...

    //
    // At this stage, we have extracted the visible data. We can use those data to plot the chart.
    //

    //=======================
    // Configure overall chart appearance.
    //=======================

    // Create an XYChart object of size 640 x 350 pixels
    XYChart c = new XYChart(widthOfXyChart, heightOfXyChart);

    ...

    //===========
    // Add data to chart
    //===========

    //
    // In this example, we represent the data by lines. You may modify the code below to use other
    // representations (areas, scatter plot, etc).
    //

    // Add a line layer for the lines, using a line width of 2 pixels
    LineLayer layer = c.addLineLayer2();
    layer.setLineWidth(2);
    layer.setFastLineMode();

    // Now we add the 3 data series to a line layer, using the color red (ff0000), green (00cc00)
    // and blue (0000ff)
    if (separate.IsChecked == false)
    {
        // lines grouped in one XYChart
        layer.setXData(viewPortTimeStamps);
        // check to see if lines are displayed
        if (checkboxA.IsChecked == true)
            layer.addDataSet(viewPortDataSeriesA, 0xff0000, "Alpha");
        if (checkboxB.IsChecked == true)
            layer.addDataSet(viewPortDataSeriesB, 0x00cc00, "Beta");
        if (checkboxC.IsChecked == true)
            layer.addDataSet(viewPortDataSeriesC, 0x0000ff, "Gamma");
    }
    else
    {
        // one line per XYChart
        layer.setXData(viewPortTimeStamps);
        if (lineId == 1)
            layer.addDataSet(viewPortDataSeriesA, 0xff0000, "Alpha");
        else if (lineId == 2)
            layer.addDataSet(viewPortDataSeriesB, 0x00cc00, "Beta");
        else if (lineId == 3)
            layer.addDataSet(viewPortDataSeriesC, 0x0000ff, "Gamma");
    }

    //=====================
    // Configure axis scale and labelling
    //=====================

    ...

    //=====================
    // Output the chart
    //=====================

    // We need to update the track line too. If the mouse is moving on the chart (eg. if
    // the user drags the mouse on the chart to scroll it), the track line will be updated
    // in the MouseMovePlotArea event. Otherwise, we need to update the track line here.
    if (!viewer.IsInMouseMoveEvent)
    {
        trackLineLabel(c, (null == viewer.Chart) ? c.getPlotArea().getRightX() :
            viewer.PlotAreaMouseX);
    }
    if (separate.IsChecked == false)
    {
        // all lines in one XYChart
        viewer.Chart = c;
    }
    else
    {
        // one line per XYChart
        // calculate top-left x,y coordinates within multi-chart. XYCharts are stacked vertically
        int xCoordinate = 0;
        int yCoordinate = (lineId - 1) * heightOfXyChart;  // values will be 0 * 350, 1 * 350, 2 * 350
        // add XYChart to MultiChart
        mc.addChart(xCoordinate, yCoordinate, c);
    }
}

When I start the application I see the XYChart with 3 lines. When I checkbox "Separate", drawChart() executes this code:

MultiChart mc = new MultiChart(widthOfMultiChart, heightOfMultiChart);
viewer.Chart = mc;

and I get the exception:

System.InvalidCastException
  HResult=0x80004002
  Message=Unable to cast object of type 'ChartDirector.MultiChart' to type 'ChartDirector.XYChart'.
  Source=CSharpWPFCharts
  StackTrace:
   at CSharpWPFCharts.RealTimeZoomScrollWindow.WPFChartViewer1_MouseMovePlotArea(Object sender, MouseEventArgs e) in C:Usersphilip.watkinsonsourcereposChartDirectorNetWPFChartsCSharpWPFChartsRealTimeZoomScrollWindow.xaml.cs:line 575

Here is the method:

private void WPFChartViewer1_MouseMovePlotArea(object sender, MouseEventArgs e)
{
    var viewer = sender as WPFChartViewer;
    trackLineLabel((XYChart)viewer.Chart, viewer.PlotAreaMouseX);
    viewer.updateDisplay();
}

In the method, viewer.Chart is cast to XYChart but in my code viewer.Chart is of type MultiChart in drawChart().


What should I do?

Philip

  Re: Multiple XYCharts in one MultiChart
Posted by Philip on Oct-08-2020 03:30
Peter,

I was able to fix the exception by modifying WPFChartViewer1_MouseMovePlotArea():


        private void WPFChartViewer1_MouseMovePlotArea(object sender, MouseEventArgs e)
        {
            var viewer = sender as WPFChartViewer;
            if (viewer.Chart.GetType() == typeof(MultiChart))
            {
                MultiChart mc = (MultiChart)viewer.Chart;
                int numCharts = mc.getChartCount();
                for (int i = 0; i < numCharts; i++)
                {
                    trackLineLabel((XYChart)mc.getChart(i), viewer.PlotAreaMouseX);
                }
            }
            else
            {
                trackLineLabel((XYChart)viewer.Chart, viewer.PlotAreaMouseX);
            }
            viewer.updateDisplay();
        }


Unfortunately I don't see the 3 stacked XYCharts. Any idea what the problem is?

Philip

  Re: Multiple XYCharts in one MultiChart
Posted by Peter Kwan on Oct-08-2020 13:03
Attachments:
Hi Philip,

For a MultiChart, when drawing the track cursor, it needs to be drawn on the dynamic layer of the MultiChart. That means we need to ask the XYChart to draw on the MultiChart dynamic layer.

There are some examples in this forum, but I cannot find one in WPF. So I just modified the WPF "Real Time Chart with Zooming and Scrolling" sample code to provide an example.

There are many styles of stacked chart. The style I use is to omit the x-axis for all charts except the bottom chart. (Sometimes people will put the x-axis at the top of the first chart as well, or to include x-axis for every chart.) I have attached the screen shot and the code for your reference.

Regards
Peter Kwan
WpfApp1_20201008125550.png
RealTimeZoomScrollWindow.xaml.cs
RealTimeZoomScrollWindow.xaml.cs

24.58 Kb
RealTimeZoomScrollWindow.xaml
RealTimeZoomScrollWindow.xaml

4.91 Kb