SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, iOS Chart, Android Chart and JavaScript Chart Components
Hi All,
I have a situation where the chart needs to be switched between a log scale and a linear scale. To solve this I created 2 axis (one of each) and collapse one of them while the other is visible. The user can switch between them from a context menu.
I declare them in XAML as:
<s:SciChartSurface.YAxes>
<s:NumericAxis x:Name="LinearAxis" Id="LinearAxisID" AutoRange="Always" AxisAlignment="Left" AxisTitle="Linear" Style="{StaticResource LinearScaleStyle}" Visibility="Visible" GrowBy="0.0, 0.1"/>
<s:LogarithmicNumericAxis x:Name="LogAxis" Id="LogAxisID" AxisAlignment="Left" AxisTitle="Log" Style="{StaticResource LogScaleStyle}" GrowBy="0.0, 0.1" />
</s:SciChartSurface.YAxes>
THE ISSUE:
I’ve noticed that the Major and Minor gridlines are drawn based on the order the Axis are declared in <s:SciChartSurface.YAxes> which isn’t a problem. The problem comes when I collapse one axis and make the other visible (obviously re-assigning the series to the visible axis by ID) – The axis and data change as you might expect but the major and minor gridlines are not redrawn.
In summary, if you start with log gridlines, you always get log gridlines – even on a linear axis.
Is there a way to force the redrawing of the gridlines?
Hi Stuart,
If you want one axis to draw gridlines, and the other not, you need to set AxisBase.IsPrimaryAxis to true (to draw gridlines) or to false (to not draw gridlines). That will solve the problem.
However, I think what you’re looking for is a good way to switch between linear and logarithmic axis. So, here is one way you can do this, with attached behaviours:
SwitchYAxisTypeBehavior
Dynamically Switches an axis instance on a chart depending on a bound boolean property
// Note this could be extended to deal with XAxis quite easily
public class SwitchYAxisTypeBehavior
{
// Define the Default YAxis -- this can be done in XAML
public static readonly DependencyProperty DefaultYAxisProperty = DependencyProperty.RegisterAttached(
"DefaultYAxis", typeof(AxisBase), typeof(SwitchYAxisTypeBehavior), new PropertyMetadata(default(AxisBase), OnPropertyChanged));
public static void SetDefaultYAxis(DependencyObject element, AxisBase value)
{
element.SetValue(DefaultYAxisProperty, value);
}
public static AxisBase GetDefaultYAxis(DependencyObject element)
{
return (AxisBase)element.GetValue(DefaultYAxisProperty);
}
// Define the Alternative YAxis -- this can be done in XAML
public static readonly DependencyProperty AlternativeYAxisProperty = DependencyProperty.RegisterAttached(
"AlternativeYAxis", typeof(AxisBase), typeof(SwitchYAxisTypeBehavior), new PropertyMetadata(default(AxisBase), OnPropertyChanged));
public static void SetAlternativeYAxis(DependencyObject element, AxisBase value)
{
element.SetValue(AlternativeYAxisProperty, value);
}
public static AxisBase GetAlternativeYAxis(DependencyObject element)
{
return (AxisBase)element.GetValue(AlternativeYAxisProperty);
}
// Define a boolean attached property which switches between default and alternative YAxis
public static readonly DependencyProperty UseAlternateYAxisProperty = DependencyProperty.RegisterAttached(
"UseAlternateYAxis", typeof(bool), typeof(SwitchYAxisTypeBehavior), new PropertyMetadata(default(bool), OnPropertyChanged));
public static void SetUseAlternateYAxis(DependencyObject element, bool value)
{
element.SetValue(UseAlternateYAxisProperty, value);
}
public static bool GetUseAlternateYAxis(DependencyObject element)
{
return (bool)element.GetValue(UseAlternateYAxisProperty);
}
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// This is where we switch the axis type depending on boolean
var scs = d as SciChartSurface;
if (scs == null) return;
bool useAlternateYAxis = GetUseAlternateYAxis(scs);
scs.YAxis = useAlternateYAxis ? GetAlternativeYAxis(scs) : GetDefaultYAxis(scs);
}
}
Usage (XAML):
<s:SciChartSurface x:Name="sciChart" Grid.Row="1" m:SwitchYAxisTypeBehavior.UseAlternateYAxis="{Binding UseLogarithmicAxis}">
<m:SwitchYAxisTypeBehavior.DefaultYAxis>
<s:NumericAxis AxisTitle="Numeric Axis" DrawMajorBands="True" VisibleRange="0, 10" AutoRange="Never"/>
</m:SwitchYAxisTypeBehavior.DefaultYAxis>
<m:SwitchYAxisTypeBehavior.AlternativeYAxis>
<s:LogarithmicNumericAxis AxisTitle="Logarithmic Axis" LogarithmicBase="10" TextFormatting="0.0" CursorTextFormatting="0.0"
DrawMajorBands="True" VisibleRange="0.1, 10000"/>
</m:SwitchYAxisTypeBehavior.AlternativeYAxis>
...
</s:SciChartSurface>
Alternatively, if not using MVVM
Attached properties can be set in code as well. The C# equivalent for setting an attached property is:
var scs = new SciChartSurface();
// ...
SwitchYAxisTypeBehavior.SetDefaultYAxis(scs, new NumericAxis() { ... } );
SwitchYAxisTypeBehavior.SetAlternateYAxis(scs, new LogarithmicNumericAxis() { ... } );
SwitchYAxisTypeBehavior.SetUseAlternateYAxis(scs, true);
Best regards,
Andrew
I’ve created a better solution than behavior.
I used DataTriggers:
<Style TargetType="s:SciChartSurface">
<Setter Property="YAxis" Value="{StaticResource NumericAxisY}" />
<Style.Triggers>
<DataTrigger Binding="{Binding UseLogarithmicAxisY}" Value="True">
<Setter Property="YAxis" Value="{StaticResource LogarithmicAxisY}" />
</DataTrigger>
</Style.Triggers>
</Style>
In my opinion this solution should be in official Examples Suite.
It looks like that I can’t add XAML code to comments. So I have to post it here.
Alitec Developer’s solution is really a good solution. Just to make it a complete answer, you also need to:
remove YAxis from SciChartSurface
define resource like following:
<s:NumericAxis x:Key="NumericAxisY" AxisTitle="Counts" GrowBy="0.1, 0.15" VisibleRangeLimitMode="Min" VisibleRangeLimit="0,0" />
<s:LogarithmicNumericAxis x:Key="LogarithmicAxisY" AxisTitle="Counts (Log)" GrowBy="0.1, 0.15" VisibleRangeLimitMode="Min" VisibleRangeLimit="0,0" />
Hope this will save you a few minutes.
Please login first to submit.