OxyPlot:如何在对数轴上将刻度/十进位设置为1

时间:2019-10-02 20:51:40

标签: wpf plot oxyplot

我有一个对数-对数图,两个轴的范围都在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,这使我每10跳一跳。不幸的是,随着我增加应用程序的窗口大小,主要报价的数量也增加了。因此,设置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 个答案:

答案 0 :(得分:1)

经过一番思考,我决定对coding子进行硬编码不是最好的主意。我决定创建一个对数轴,在其中可以锁定刻度线的位置,但也可以解锁,并让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
}