OxyPlot: как установить тики / декады на 1 на логарифмической оси - PullRequest
0 голосов
/ 02 октября 2019

У меня есть логарифмический график с обеими осями в диапазоне от 0,1 до 1000. Я хочу только 1 главный тик за десятилетие. До сих пор я не нашел способа контролировать интервал между тиками, кроме как установить IntervalLength, как в этом коде.

        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"
        };

По умолчанию IntervalLength равно 60, что дало мне 2 тика / десятилетие. К сожалению, когда я увеличиваю размер окна моего приложения, количество основных тиков увеличивается. Поэтому установка IntervalLength не является идеальным решением. Я просмотрел источник OxyPlot и ничего не нашел. Есть ли что-то, чего мне не хватает, или, возможно, мне нужно получить свой собственный класс LogarithmicAxis?

Редактировать: Я решил вывести свою собственную логарифмическую ось и заменить функцию, сгенерированную тиками.

    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>();
    }

Это, по крайней мере, позволяет мне вывести мое заявление за дверь.

1 Ответ

1 голос
/ 03 октября 2019

Подумав, я решил, что жесткое кодирование тиков - не лучшая идея. Я решил создать логарифмическую ось, где я мог бы зафиксировать размещение тиков, но я также мог разблокировать и позволить работать встроенным алгоритмам OxyPlot. Вы поймете, что я повторно использовал некоторые внутренние методы OxyPlot, поэтому я просто скопировал код в свой класс и сделал их закрытыми. Эту проблему было намного проще решить с помощью доступа к коду. Я все еще готов услышать другие решения.

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
}
...