0

I have a log-log plot with both axes in the range 0.1 to 1000. I want only 1 major tick per decade. So far I have found no way to control the tick spacing, except to set IntervalLength as in this code.

        var logxAxis = new LogarithmicAxis
        {
            Position = AxisPosition.Bottom,
            Title = "Resistivity of Approaching Bed (ohm-m)",
            IntervalLength = 100,
            MajorGridlineStyle = LineStyle.Solid,
            MinorGridlineStyle = LineStyle.None,
            MinorTickSize = 0.0,
            Key = "logx"
        };

The default IntervalLength is 60, which gave me 2 ticks/decade. Unfortunately, as I increase the window size of my application the number of major ticks increase. So setting IntervalLength is not an ideal solution. I have looked through the OxyPlot source and found nothing. Is there something I am missing, or perhaps I need to derive my own LogarithmicAxis class?

Edit: I decided to derive my own logarithmic axis and replace the function the generated the ticks.

    public override void GetTickValues(out IList<double> majorLabelValues, out IList<double> majorTickValues,
        out IList<double> minorTickValues)
    {
        majorLabelValues = new List<double> { 0.1, 1, 10, 100, 1000 };
        majorTickValues = new List<double> { 0.1, 1, 10, 100, 1000 };
        minorTickValues = new List<double>();
    }

This at least lets me get my application out the door.

spainchaud
  • 365
  • 3
  • 12

1 Answers1

1

After some thought, I decided that hard coding the ticks was not the best idea. I decided to create a logarithmic axis where I could lock in the tick placement, but I could also unlock, and let the built in algorithms of OxyPlot work. You will that I reused some OxyPlot methods that are internal, so I just copied the code into my class and made them private. This problem was a lot easier to solve with access to the code. I am stiil open to hearing other solutions.

public class LockableLogarithmicAxis : LogarithmicAxis
{
    #region Properties

    public bool IsLocked { get; set; }
    public double[] MajorTickPositions { get; set; }
    public double[] MinorTickPositions { get; set; }

    #endregion

    #region Constructor

    public LockableLogarithmicAxis()
    {
        IsLocked = true;
    }

    #endregion

    #region Methods

    public override void GetTickValues(out IList<double> majorLabelValues, out IList<double> majorTickValues,
        out IList<double> minorTickValues)
    {
        if (!IsLocked)
        {
            base.GetTickValues(out majorLabelValues, out majorTickValues, out minorTickValues);
            return;
        }

        if (MajorTickPositions != null && MajorTickPositions.Length > 0)
        {
            majorTickValues = MajorTickPositions.ToList();
        }
        else
        {
            majorTickValues = this.DecadeTicks();
        }

        if (MinorTickPositions != null && MinorTickPositions.Length > 0)
        {
            minorTickValues = MinorTickPositions.ToList();
        }
        else
        {
            minorTickValues = this.SubdividedDecadeTicks();
        }

        majorLabelValues = majorTickValues;
    }

    /// <summary>
    /// Calculates ticks of the decades in the axis range with a specified step size.
    /// </summary>
    /// <param name="step">The step size.</param>
    /// <returns>A new IList containing the decade ticks.</returns>
    private IList<double> DecadeTicks(double step = 1)
    {
        return this.PowList(this.LogDecadeTicks(step));
    }

    /// <summary>
    /// Calculates logarithmic ticks of the decades in the axis range with a specified step size.
    /// </summary>
    /// <param name="step">The step size.</param>
    /// <returns>A new IList containing the logarithmic decade ticks.</returns>
    private IList<double> LogDecadeTicks(double step = 1)
    {
        var ret = new List<double>();
        if (step > 0)
        {
            var last = double.NaN;
            for (var exponent = Math.Ceiling(this.LogActualMinimum); exponent <= this.LogActualMaximum; exponent += step)
            {
                if (exponent <= last)
                {
                    break;
                }

                last = exponent;
                if (exponent >= this.LogActualMinimum)
                {
                    ret.Add(exponent);
                }
            }
        }

        return ret;
    }

    /// <summary>
    /// Raises all elements of a List to the power of <c>this.Base</c>.
    /// </summary>
    /// <param name="logInput">The input values.</param>
    /// <param name="clip">If true, discards all values that are not in the axis range.</param>
    /// <returns>A new IList containing the resulting values.</returns>
    private IList<double> PowList(IList<double> logInput, bool clip = false)
    {
        return
            logInput.Where(item => !clip || !(item < this.LogActualMinimum))
                .TakeWhile(item => !clip || !(item > this.LogActualMaximum))
                .Select(item => Math.Pow(this.Base, item))
                .ToList();
    }

    /// <summary>
    /// Calculates ticks of all decades in the axis range and their subdivisions.
    /// </summary>
    /// <param name="clip">If true (default), the lowest and highest decade are clipped to the axis range.</param>
    /// <returns>A new IList containing the decade ticks.</returns>
    private IList<double> SubdividedDecadeTicks(bool clip = true)
    {
        var ret = new List<double>();
        for (var exponent = (int)Math.Floor(this.LogActualMinimum); ; exponent++)
        {
            if (exponent > this.LogActualMaximum)
            {
                break;
            }

            var currentDecade = Math.Pow(this.Base, exponent);
            for (var mantissa = 1; mantissa < this.Base; mantissa++)
            {
                var currentValue = currentDecade * mantissa;
                if (clip && currentValue < this.ActualMinimum)
                {
                    continue;
                }

                if (clip && currentValue > this.ActualMaximum)
                {
                    break;
                }

                ret.Add(currentDecade * mantissa);
            }
        }

        return ret;
    }

    #endregion
}
spainchaud
  • 365
  • 3
  • 12