Negative series based on positive source values?

Hi, I have two sets of source data, one for buy volume, and another for sell volume. Both sets are in positive values. I want to present the sets as two column series, a green column series for buy volume, which will lie above the zero line as normal, and a red column series for sell volume, which should lie BELOW the zero line, as if the source values were negative. See the attached image for what I want to achieve.

If I changed the sign of the source sell values from positive to negative, there would be no problem presenting this chart. But I don't want to change the source data. Is there a way to present the sell volume series in this fashion with the source values kept positive? Preferably both series should use the same secondary axis, as a requirement is that the secondary axis should zoom such that the top and bottom edges of the chart touches the max and min values of the columns (as can be seen on the image).

Thank you.



Attachment: SnapShot_253_6b1220ac.rar

7 Replies

SR Samuel Rajadurai Edwin Rajamanickam Syncfusion Team June 25, 2018 12:53 PM UTC

Hi Tom, 
  
Thank you for using Syncfusion Products. 
  
We can achieve your requirement with the help of chart row definition and inversed axis features. To plot the buy volume data in upward direction and sell volume data in downward direction, split the chart into two rows and inverse the Y axis of bottom chart(sell volume) to plot the data in downward direction. 
  
Please refer the following user guide document to split the chart using row definition. 
  
Code Snippet 
  
XAML 

        <chart:SfChart> 
 
            <chart:SfChart.Behaviors> 
                <chart:ChartZoomPanBehavior /> 
            </chart:SfChart.Behaviors> 
             
            <chart:SfChart.RowDefinitions> 
                <chart:ChartRowDefinition/> 
                <chart:ChartRowDefinition/> 
            </chart:SfChart.RowDefinitions> 
 
            <chart:SfChart.PrimaryAxis> 
                <chart:NumericalAxis/> 
            </chart:SfChart.PrimaryAxis> 
 
            <!--Constituting axis for the first half series.--> 
            <chart:SfChart.SecondaryAxis> 
                <chart:NumericalAxis IsInversed="True" Minimum="0"/> 
            </chart:SfChart.SecondaryAxis> 
 
            <chart:ColumnSeries XBindingPath="XValue"  
                                YBindingPath="SellVolume"  
                                ItemsSource="{Binding Data}"  
                                Label="Sell Volume">             
            </chart:ColumnSeries> 
 
            <!--Constituting axis for the second half series.--> 
            <chart:ColumnSeries XBindingPath="XValue"  
                                YBindingPath="BuyVolumne"  
                                ItemsSource="{Binding Data}"  
                                Label="Buy Volume"> 
                <chart:ColumnSeries.YAxis> 
                    <chart:NumericalAxis chart:ChartBase.Row="1" Minimum="0"/> 
                </chart:ColumnSeries.YAxis> 
            </chart:ColumnSeries> 
 
        </chart:SfChart> 


  
Regards,
Samuel 



TO Tom June 26, 2018 04:27 PM UTC

Hi Samuel, unfortunately what has happened in your sample is that the unit lengths for the upper and lower axis are different. In your sample the maximum of the upper axis is 140, and the maximum of the lower axis is 60, but they both appear the same size, because the zero line is exactly in the middle. This is wrong. The two series should be in correct proportion relative to each other, so the zero line must move either up or down to reflect that. It is why I mentioned in my opening post that it's perhaps best that both series use the same secondary axis so that they scale correctly. What method do you suggest to solve this issue?


MK Muneesh Kumar G Syncfusion Team June 27, 2018 05:43 AM UTC

Hi Tom,  
 
You can resolve this problem by setting Maximum property in axis as per the below code snippet.  
 
Code snippet [XAML]: 
<chart:SfChart.SecondaryAxis> 
                <chart:NumericalAxis Maximum="{Binding Maximum}" IsInversed="True" Minimum="0"/> 
            </chart:SfChart.SecondaryAxis> 
 
           .. 
                <chart:ColumnSeries.YAxis> 
                    <chart:NumericalAxis Maximum="{Binding Maximum}" chart:ChartBase.Row="1" Minimum="0"/> 
                </chart:ColumnSeries.YAxis> 
            </chart:ColumnSeries> 
 
Code snippet [C#]: 
public ViewModel() 
        { 
            Data = new ObservableCollection<Model>(); 
 
            Data.Add(new Model() { XValue = 0, BuyVolume = 110, SellVolume  = 40}); 
            Data.Add(new Model() { XValue = 1, BuyVolume = 140, SellVolume= 60 }); 
            Data.Add(new Model() { XValue = 2, BuyVolume = 130, SellVolume = 50 }); 
            Data.Add(new Model() { XValue = 3, BuyVolume = 110 , SellVolume = 30 }); 
            Data.Add(new Model() { XValue = 4, BuyVolume = 100 , SellVolume = 25}); 
 
            var buyMax = Data.Max(model => model.BuyVolume); 
            var sellMax = Data.Max(model => model.SellVolume); 
 
            Maximum = Math.Max(buyMax, sellMax); 
        } 
        public double Maximum { get; set; } 
 
Also, you can change the color for series using Interior property as per the below code snippet.  
 
Code snippet [XAML]: 
<chart:ColumnSeries XBindingPath="XValue"  
                                YBindingPath="SellVolume"  
                                Interior="Red" 
 
We have modified our sample based on above solutions, please find the sample from the following location.  
 
 
Please let us know if you have any queries.  
 
Thanks, 
Muneesh Kumar G. 
 



TO Tom July 1, 2018 11:24 AM UTC

Hi Muneesh, this solution is also wrong. There should be no gap between the max column and the chart edge. In your sample, the maximum sell column is 60, yet the maximum for the sell axis is 140, so there is a gap of 80. To solve this problem, the zero line needs to move down. In other words, the buy and sell chartrows need to have different heights. Please take another close look at the image I attached to my opening post. I tried to bind the buy chartrow height to the max buy volume, and the sell chartrow height to the max sell volume in xaml, but it didn't bind correctly.


MK Muneesh Kumar G Syncfusion Team July 2, 2018 07:15 AM UTC

Hi Tom,   
  
We have analyzed your query and we are able to reproduce the problem at our end. We will fix this issue and the fix will be available on our upcoming volume 2 SP1 release, which will be available on end of July 2018. However, you can resolve this by setting calculated Height for RowDefinition in code behind as per the below code snippet.  
  
Code snippet [XAML]:  
<chart:SfChart.RowDefinitions> 
                <chart:ChartRowDefinition x:Name="row1"  Unit="Star"/> 
                <chart:ChartRowDefinition x:Name="row2"  Unit="Star"/> 
            </chart:SfChart.RowDefinitions> 
  <chart:SfChart.DataContext> 
                <local:ViewModel x:Name="viewModel"/> 
            </chart:SfChart.DataContext> 
 
 
Code snippet [C#]: 
  public MainWindow() 
        { 
            InitializeComponent(); 
 
            row1.Height = viewModel.RowHeight1; 
            row2.Height = viewModel.RowHeight2; 
        } 
 
  public class ViewModel 
    { 
 
        public ViewModel() 
        { 
            Data = new ObservableCollection<Model>(); 
 
            Data.Add(new Model() { XValue = 0, BuyVolumne = 110, SellVolume  = 40}); 
            Data.Add(new Model() { XValue = 1, BuyVolumne = 140, SellVolume= 60 }); 
            Data.Add(new Model() { XValue = 2, BuyVolumne = 130, SellVolume = 50 }); 
            Data.Add(new Model() { XValue = 3, BuyVolumne = 110 , SellVolume = 30 }); 
            Data.Add(new Model() { XValue = 4, BuyVolumne = 100 , SellVolume = 25}); 
 
            double buyMax = Data.Max(data => data.BuyVolumne); 
            double sellMax = Data.Max(data => data.SellVolume); 
 
            double total = buyMax + sellMax; 
 
            RowHeight1 = (sellMax / total) * 100; 
 
            RowHeight2 = (buyMax / total) * 100; 
        } 
 
        public ObservableCollection<Model> Data { get; set; } 
 
        public double RowHeight1 { get; set; } 
 
        public double RowHeight2 { get; set; } 
    } 
 
 
We have modified our sample based on this, please find the sample from the following location.  
 
 
Output:  
 
Please let us know if you have any queries.  
 
Thanks, 
Muneesh Kumar G. 



TO Tom July 3, 2018 01:50 PM UTC

Great, thank you Muneesh.


MK Muneesh Kumar G Syncfusion Team July 5, 2018 04:01 AM UTC

Hi Tom, 

Thanks for the update.

We are glad to know that the given solution works. Please let us know if you need any further assistance.

Thanks,
Muneesh Kumar G.

Loader.
Up arrow icon