OxyPlot:如何根据轴范围添加背景

时间:2017-06-05 07:22:36

标签: oxyplot

在最近的c#wpf应用程序中,我使用了氧气图进行趋势分析。它是一个很好的工具,具有高性能的体积数据。我从LiveChart搬到了Oxyplot。如何根据轴范围实现截面背景? TargetEffect

我尝试过修改了ThreeColorLineSeries,现在我可以根据设置的上限和下限来渲染线条。但对于背景而言,它并不起作用。

using System.Collections.Generic;

/// <summary>
/// Represents a two-color line series.
/// </summary>
public class FourColorLineSeries : LineSeries
{
    /// <summary>
    /// The default low color.
    /// </summary>
    private OxyColor defaultColorLoPre;

    /// <summary>
    /// The default low color.
    /// </summary>
    private OxyColor defaultColorLo;

    /// <summary>
    /// The default hi color.
    /// </summary>
    private OxyColor defaultColorLoLo;

    /// <summary>
    /// The default low color.
    /// </summary>
    private OxyColor defaultColorHiPre;

    /// <summary>
    /// The default low color.
    /// </summary>
    private OxyColor defaultColorHi;

    /// <summary>
    /// The default hi color.
    /// </summary>
    private OxyColor defaultColorHiHi;

    /// <summary>
    /// Initializes a new instance of the <see cref = "FourColorLineSeries" /> class.
    /// </summary>
    public FourColorLineSeries()
    {
        this.LimitHiPre = 1.0;
        this.ColorHiPre = OxyColors.Green;
        this.LineStyleHiPre = LineStyle.Solid;

        this.LimitHi = 2.0;
        this.ColorHi = OxyColors.Yellow;
        this.LineStyleHi = LineStyle.Solid;

        this.LimitHiHi = 5.0;
        this.ColorHiHi = OxyColors.Red;
        this.LineStyleHiHi = LineStyle.Solid;

        this.LimitLoPre = -1.0;
        this.ColorLoPre = OxyColors.Green;
        this.LineStyleLoPre = LineStyle.Solid;

        this.LimitLo = -2.0;
        this.ColorLo = OxyColors.Yellow;
        this.LineStyleLo = LineStyle.Solid;

        this.LimitLoLo = -5.0;
        this.ColorLoLo = OxyColors.Red;
        this.LineStyleLoLo = LineStyle.Solid;
    }

    /// <summary>
    /// Gets or sets the color for the part of the line that is below the limit.
    /// </summary>
    public OxyColor ColorLoPre { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is below the limit.
    /// </summary>
    public OxyColor ColorLo { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is above the limit.
    /// </summary>
    public OxyColor ColorLoLo { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is below the limit.
    /// </summary>
    public OxyColor ColorHiPre { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is below the limit.
    /// </summary>
    public OxyColor ColorHi { get; set; }

    /// <summary>
    /// Gets or sets the color for the part of the line that is above the limit.
    /// </summary>
    public OxyColor ColorHiHi { get; set; }

    /// <summary>
    /// Gets the actual low pre color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorLoPre
    {
        get { return this.ColorLoPre.GetActualColor(this.defaultColorLoPre); }
    }

    /// <summary>
    /// Gets the actual low color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorLo
    {
        get { return this.ColorLo.GetActualColor(this.defaultColorLo); }
    }

    /// <summary>
    /// Gets the actual low low color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorLoLo
    {
        get { return this.ColorLoLo.GetActualColor(this.defaultColorLoLo); }
    }

    /// <summary>
    /// Gets the actual hi pre color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorHiPre
    {
        get { return this.ColorHiPre.GetActualColor(this.defaultColorHiPre); }
    }

    /// <summary>
    /// Gets the actual hi color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorHi
    {
        get { return this.ColorHi.GetActualColor(this.defaultColorHi); }
    }

    /// <summary>
    /// Gets the actual low color.
    /// </summary>
    /// <value>The actual color.</value>
    public OxyColor ActualColorHiHi
    {
        get { return this.ColorHiHi.GetActualColor(this.defaultColorHiHi); }
    }

    /// <summary>
    /// Gets or sets the high limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorHi.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitLoPre { get; set; }

    /// <summary>
    /// Gets or sets the low limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorLo.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitLo { get; set; }

    /// <summary>
    /// Gets or sets the pre limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorPre.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitLoLo { get; set; }

    /// <summary>
    /// Gets or sets the high limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorHi.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitHiPre { get; set; }

    /// <summary>
    /// Gets or sets the low limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorLo.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitHi { get; set; }

    /// <summary>
    /// Gets or sets the pre limit.
    /// </summary>
    /// <remarks>The parts of the line that is below this limit will be rendered with ColorPre.
    /// The parts of the line that is above the limit will be rendered with Color.</remarks>
    public double LimitHiHi { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is above the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesHi { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesLo { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesLoPre { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is above the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesLoLo { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesHiPre { get; set; }

    /// <summary>
    /// Gets or sets the dash array for the rendered line that is below the limit (overrides <see cref="LineStyle" />).
    /// </summary>
    /// <value>The dash array.</value>
    /// <remarks>If this is not <c>null</c> it overrides the <see cref="LineStyle" /> property.</remarks>
    public double[] DashesHiHi { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleLoPre { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleLo { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleLoLo { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleHiPre { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleHi { get; set; }

    /// <summary>
    /// Gets or sets the line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle LineStyleHiHi { get; set; }

    /// <summary>
    /// Gets the actual line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleHi
    {
        get
        {
            return this.LineStyleHi != LineStyle.Automatic ? this.LineStyleHi : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleHiHi
    {
        get
        {
            return this.LineStyleHiHi != LineStyle.Automatic ? this.LineStyleHiHi : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleHiPre
    {
        get
        {
            return this.LineStyleHiPre != LineStyle.Automatic ? this.LineStyleHiPre : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is above the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleLoPre
    {
        get
        {
            return this.LineStyleLoPre != LineStyle.Automatic ? this.LineStyleLoPre : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleLo
    {
        get
        {
            return this.LineStyleLo != LineStyle.Automatic ? this.LineStyleLo : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual line style for the part of the line that is below the limit.
    /// </summary>
    /// <value>The line style.</value>
    public LineStyle ActualLineStyleLoLo
    {
        get
        {
            return this.LineStyleLoLo != LineStyle.Automatic ? this.LineStyleLoLo : LineStyle.Solid;
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is above the limit.
    /// </summary>
    protected double[] ActualDashArrayHi
    {
        get
        {
            return this.DashesHi ?? this.ActualLineStyleHi.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is below the limit.
    /// </summary>
    protected double[] ActualDashArrayLo
    {
        get
        {
            return this.DashesLo ?? this.ActualLineStyleLo.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is below the limit.
    /// </summary>
    protected double[] ActualDashArrayLoPre
    {
        get
        {
            return this.DashesLoPre ?? this.ActualLineStyleLoPre.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is above the limit.
    /// </summary>
    protected double[] ActualDashArrayHiHi
    {
        get
        {
            return this.DashesHiHi ?? this.ActualLineStyleHiHi.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is below the limit.
    /// </summary>
    protected double[] ActualDashArrayLoLo
    {
        get
        {
            return this.DashesLoLo ?? this.ActualLineStyleLoLo.GetDashArray();
        }
    }

    /// <summary>
    /// Gets the actual dash array for the line that is below the limit.
    /// </summary>
    protected double[] ActualDashArrayHiPre
    {
        get
        {
            return this.DashesHiPre ?? this.ActualLineStyleHiPre.GetDashArray();
        }
    }


    /// <summary>
    /// Sets the default values.
    /// </summary>
    protected internal override void SetDefaultValues()
    {
        base.SetDefaultValues();

        if (this.ColorLoPre.IsAutomatic())
        {
            this.defaultColorLoPre = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleLoPre == LineStyle.Automatic)
        {
            this.LineStyleLoPre = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorHiPre.IsAutomatic())
        {
            this.defaultColorHiPre = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleHiPre == LineStyle.Automatic)
        {
            this.LineStyleHiPre = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorLo.IsAutomatic())
        {
            this.defaultColorLo = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleLo == LineStyle.Automatic)
        {
            this.LineStyleLo = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorLoLo.IsAutomatic())
        {
            this.defaultColorLoLo = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleLoLo == LineStyle.Automatic)
        {
            this.LineStyleLoLo = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorHi.IsAutomatic())
        {
            this.defaultColorHi = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleHi == LineStyle.Automatic)
        {
            this.LineStyleHi = this.PlotModel.GetDefaultLineStyle();
        }

        if (this.ColorHiHi.IsAutomatic())
        {
            this.defaultColorHiHi = this.PlotModel.GetDefaultColor();
        }

        if (this.LineStyleHiHi == LineStyle.Automatic)
        {
            this.LineStyleHiHi = this.PlotModel.GetDefaultLineStyle();
        }
    }

    /// <summary>
    /// Renders the smoothed line.
    /// </summary>
    /// <param name="rc">The render context.</param>
    /// <param name="clippingRect">The clipping rectangle.</param>
    /// <param name="pointsToRender">The points.</param>
    protected override void RenderLine(IRenderContext rc, OxyRect clippingRect, IList<ScreenPoint> pointsToRender)
    {
        var bottom = clippingRect.Bottom;
        var top = clippingRect.Top;

        // todo: this does not work when y axis is reversed
        var yLoPre = this.YAxis.Transform(this.LimitLoPre);
        var yLo = this.YAxis.Transform(this.LimitLo);
        var yLoLo = this.YAxis.Transform(this.LimitLoLo);
        var yHiPre = this.YAxis.Transform(this.LimitHiPre);
        var yHi = this.YAxis.Transform(this.LimitHi);
        var yHiHi = this.YAxis.Transform(this.LimitHiHi);

        if (yLoPre< clippingRect.Top)
        {
            yLoPre = clippingRect.Top;
        }

        if (yLoPre > clippingRect.Bottom)
        {
            yLoPre = clippingRect.Bottom;
        }

        if (yHiPre < clippingRect.Top)
        {
            yHiPre = clippingRect.Top;
        }

        if (yHiPre > clippingRect.Bottom)
        {
            yHiPre = clippingRect.Bottom;
        }

        if (yLo < clippingRect.Top)
        {
            yLo = clippingRect.Top;
        }

        if (yLo > clippingRect.Bottom)
        {
            yLo = clippingRect.Bottom;
        }

        if (yLoLo < clippingRect.Top)
        {
            yLoLo = clippingRect.Top;
        }

        if (yLoLo > clippingRect.Bottom)
        {
            yLoLo = clippingRect.Bottom;
        }

        if (yHi < clippingRect.Top)
        {
            yHi = clippingRect.Top;
        }

        if (yHi > clippingRect.Bottom)
        {
            yHi = clippingRect.Bottom;
        }

        if (yHiHi < clippingRect.Top)
        {
            yHiHi = clippingRect.Top;
        }

        if (yHiHi > clippingRect.Bottom)
        {
            yHiHi = clippingRect.Bottom;
        }

        clippingRect = new OxyRect(clippingRect.Left, top, clippingRect.Width, yHiHi - top);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorHiHi),
            this.StrokeThickness,
            this.ActualDashArrayHiHi,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yHiHi, clippingRect.Width, yHi - yHiHi);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorHi),
            this.StrokeThickness,
            this.ActualDashArrayHi,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yHi, clippingRect.Width, yHiPre - yHi);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorHiPre),
            this.StrokeThickness,
            this.ActualDashArrayHiPre,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yHiPre, clippingRect.Width, yLoPre - yHiPre);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColor),
            this.StrokeThickness,
            this.ActualDashArray,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yLoPre, clippingRect.Width, yLo - yLoPre);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorLoPre),
            this.StrokeThickness,
            this.ActualDashArrayLoPre,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yLo, clippingRect.Width, yLoLo - yLo);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorLo),
            this.StrokeThickness,
            this.ActualDashArrayLo,
            this.LineJoin,
            false);

        clippingRect = new OxyRect(clippingRect.Left, yLoLo, clippingRect.Width, bottom - yLoLo);

        rc.DrawClippedLine(
            clippingRect,
            pointsToRender,
            this.MinimumSegmentLength * this.MinimumSegmentLength,
            this.GetSelectableColor(this.ActualColorLoLo),
            this.StrokeThickness,
            this.ActualDashArrayLoLo,
            this.LineJoin,
            false);
     }
}

}

1 个答案:

答案 0 :(得分:1)

在阅读并在两天内使用oxyplot源代码进行挣扎之后,我最终修改了现有的oxyplot RangeColorAxis.cs并制作了一个wpf包装器。完成这些操作后,我可以使用2个重建的dll(OxyPlot.dll和Oxyplot.Wpf.dll)文件获取以下图像。

LineSeries with axis value based range colors

修改了RangeColorAxis.cs

namespace OxyPlot.Axes
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// Represents a color axis that contains colors for specified ranges.
    /// </summary>
    public class RangeColorAxis : LinearAxis, IColorAxis
    {
        /// <summary>
        /// The ranges
        /// </summary>
        private readonly List<ColorRange> ranges = new List<ColorRange>();

        /// <summary>
        /// Initializes a new instance of the <see cref="RangeColorAxis" /> class.
        /// </summary>
        public RangeColorAxis()
        {
            this.Position = AxisPosition.None;
            this.AxisDistance = 20;

            this.LowColor = OxyColors.Undefined;
            this.HighColor = OxyColors.Undefined;
            this.InvalidNumberColor = OxyColors.Gray;

            this.IsPanEnabled = false;
            this.IsZoomEnabled = false;
        }

        /// <summary>
        /// Gets or sets the color used to represent NaN values.
        /// </summary>
        /// <value>A <see cref="OxyColor" /> that defines the color. The default value is <c>OxyColors.Gray</c>.</value>
        public OxyColor InvalidNumberColor { get; set; }

        /// <summary>
        /// Gets or sets the color of values above the maximum value.
        /// </summary>
        /// <value>The color of the high values.</value>
        public OxyColor HighColor { get; set; }

        /// <summary>
        /// Gets or sets the color of values below the minimum value.
        /// </summary>
        /// <value>The color of the low values.</value>
        public OxyColor LowColor { get; set; }

        /// <summary>
        /// Adds a range.
        /// </summary>
        /// <param name="lowerBound">The lower bound.</param>
        /// <param name="upperBound">The upper bound.</param>
        /// <param name="color">The color.</param>
        public void AddRange(double lowerBound, double upperBound, OxyColor color)
        {
            this.ranges.Add(new ColorRange { LowerBound = lowerBound, UpperBound = upperBound, Color = color });
        }

        /// <summary>
        /// Clears the ranges.
        /// </summary>
        public void ClearRanges()
        {
            this.ranges.Clear();
        }

        /// <summary>
        /// Gets the palette index of the specified value.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>The palette index.</returns>
        /// <remarks>If the value is less than minimum, 0 is returned. If the value is greater than maximum, Palette.Colors.Count+1 is returned.</remarks>
        public int GetPaletteIndex(double value)
        {
            if (!this.LowColor.IsUndefined() && value < this.ranges[0].LowerBound)
            {
                return -1;
            }

            if (!this.HighColor.IsUndefined() && value > this.ranges[this.ranges.Count - 1].UpperBound)
            {
                return this.ranges.Count;
            }

            // TODO: change to binary search?
            for (int i = 0; i < this.ranges.Count; i++)
            {
                var range = this.ranges[i];
                if (range.LowerBound <= value && range.UpperBound > value)
                {
                    return i;
                }
            }

            return int.MinValue;
        }

        /// <summary>
        /// Gets the color.
        /// </summary>
        /// <param name="paletteIndex">The color map index.</param>
        /// <returns>The color.</returns>
        public OxyColor GetColor(int paletteIndex)
        {
            if (paletteIndex == int.MinValue)
            {
                return this.InvalidNumberColor;
            }

            if (paletteIndex == -1)
            {
                return this.LowColor;
            }

            if (paletteIndex == this.ranges.Count)
            {
                return this.HighColor;
            }

            return this.ranges[paletteIndex].Color;
        }

        /// <summary>
        /// Renders the axis on the specified render context.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="pass">The render pass.</param>
        public override void Render(IRenderContext rc, int pass)
        {
            if (this.Position == AxisPosition.None)
            {
                return;
            }

            if (pass == 0)
            {
                double distance = this.AxisDistance;
                double left = this.PlotModel.PlotArea.Left;
                double top = this.PlotModel.PlotArea.Top;
                double width = this.MajorTickSize - 2;
                double height = this.MajorTickSize - 2;
                double plotwidth = this.PlotModel.PlotArea.Width;
                double plotheight = this.PlotModel.PlotArea.Height;

                const int TierShift = 0;

                switch (this.Position)
                {
                    case AxisPosition.Left:
                        left = this.PlotModel.PlotArea.Left - TierShift - width - distance;
                        top = this.PlotModel.PlotArea.Top;
                        break;
                    case AxisPosition.Right:
                        left = this.PlotModel.PlotArea.Right + TierShift + distance;
                        top = this.PlotModel.PlotArea.Top;
                        break;
                    case AxisPosition.Top:
                        left = this.PlotModel.PlotArea.Left;
                        top = this.PlotModel.PlotArea.Top - TierShift - height - distance;
                        break;
                    case AxisPosition.Bottom:
                        left = this.PlotModel.PlotArea.Left;
                        top = this.PlotModel.PlotArea.Bottom + TierShift + distance;
                        break;
                }

                Action<double, double, OxyColor> drawColorRect = (ylow, yhigh, color) =>
                {
                    double ymin = Math.Min(ylow, yhigh);
                    double ymax = Math.Max(ylow, yhigh);
                    rc.DrawRectangle(
                        this.IsHorizontal()
                            ? new OxyRect(ymin, top, ymax - ymin, plotheight)
                            : new OxyRect(left, ymin, plotwidth, ymax - ymin),
                        color,
                        OxyColors.Undefined);
                };

                // if the axis is reversed then the min and max values need to be swapped.
                double effectiveMaxY = this.Transform(this.IsReversed ? this.ActualMinimum : this.ActualMaximum);
                double effectiveMinY = this.Transform(this.IsReversed ? this.ActualMaximum : this.ActualMinimum);

                foreach (ColorRange range in this.ranges)
                {
                    double ylow = this.Transform(range.LowerBound);
                    double yhigh = this.Transform(range.UpperBound);

                    if (this.IsHorizontal())
                    {
                        if (ylow < effectiveMinY)
                        {
                            ylow = effectiveMinY;
                        }

                        if (yhigh > effectiveMaxY)
                        {
                            yhigh = effectiveMaxY;
                        }
                    }
                    else
                    {
                        if (ylow > effectiveMinY)
                        {
                            ylow = effectiveMinY;
                        }

                        if (yhigh < effectiveMaxY)
                        {
                            yhigh = effectiveMaxY;
                        }
                    }

                    drawColorRect(ylow, yhigh, range.Color);
                }

                double highLowLength = 10;
                if (this.IsHorizontal())
                {
                    highLowLength *= -1;
                }

                if (!this.LowColor.IsUndefined())
                {
                    double ylow = this.Transform(this.ActualMinimum);
                    drawColorRect(ylow, ylow + highLowLength, this.LowColor);
                }

                if (!this.HighColor.IsUndefined())
                {
                    double yhigh = this.Transform(this.ActualMaximum);
                    drawColorRect(yhigh, yhigh - highLowLength, this.HighColor);
                }
            }

            var r = new HorizontalAndVerticalAxisRenderer(rc, this.PlotModel);
            r.Render(this, pass);
        }

        /// <summary>
        /// Defines a range.
        /// </summary>
        private class ColorRange
        {
            /// <summary>
            /// Gets or sets the color.
            /// </summary>
            /// <value>The color.</value>
            public OxyColor Color { get; set; }

            /// <summary>
            /// Gets or sets the lower bound.
            /// </summary>
            /// <value>The lower bound.</value>
            public double LowerBound { get; set; }

            /// <summary>
            /// Gets or sets the upper bound.
            /// </summary>
            /// <value>The upper bound.</value>
            public double UpperBound { get; set; }
        }
    }
}

RangeColorAxis.cs的WPF包装

namespace OxyPlot.Wpf
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Windows;
    using System.Windows.Markup;
    using System.Windows.Media;

    /// <summary>
    /// This is a WPF wrapper for the <see cref="OxyPlot.Axes.RangeColorAxis"/>
    /// </summary>
    public class RangeColorAxis : Axis
    {
        /// <summary>
        /// Identifies the <see cref="InvalidNumberColor"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty InvalidNumberColorProperty =
            DependencyProperty.Register(
                "InvalidNumberColor",
                typeof(Color),
                typeof(RangeColorAxis),
                new PropertyMetadata(Colors.Orange, AppearanceChanged));

        /// <summary>
        /// Identifies the <see cref="HighColor"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty HighColorProperty = DependencyProperty.Register(
            "HighColor", typeof(Color), typeof(RangeColorAxis), new PropertyMetadata(Colors.White, AppearanceChanged));

        /// <summary>
        /// Identifies the <see cref="LowColor"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty LowColorProperty = DependencyProperty.Register(
            "LowColor", typeof(Color), typeof(RangeColorAxis), new PropertyMetadata(Colors.Black, AppearanceChanged));

        /// <summary>
        /// Identifies the <see cref="Ranges"/> dependency property. 
        /// </summary>
        public static readonly DependencyProperty RangesProperty = DependencyProperty.Register(
            "Ranges", typeof(IList<Tuple<double, double, Color>>), typeof(RangeColorAxis), new PropertyMetadata(new List<Tuple<double,double,Color>>(), DataChanged));

        /// <summary>
        /// Initializes a new instance of the <see cref="RangeColorAxis"/> class.
        /// </summary>
        public RangeColorAxis()
        {
            this.InternalAxis = new Axes.RangeColorAxis();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="InvalidNumberColor"/> class.
        /// </summary>
        public Color InvalidNumberColor
        {
            get
            {
                return (Color)this.GetValue(InvalidNumberColorProperty);
            }

            set
            {
                this.SetValue(InvalidNumberColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the high color.
        /// </summary>
        public Color HighColor
        {
            get
            {
                return (Color)this.GetValue(HighColorProperty);
            }

            set
            {
                this.SetValue(HighColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets the low color.
        /// </summary>
        public Color LowColor
        {
            get
            {
                return (Color)this.GetValue(LowColorProperty);
            }

            set
            {
                this.SetValue(LowColorProperty, value);
            }
        }

        /// <summary>
        /// Gets or sets Labels.
        /// </summary>
        public IList<Tuple<double, double, Color>> Ranges
        {
            get
            {
                return (IList<Tuple<double, double, Color>>)this.GetValue(RangesProperty);
            }

            set
            {
                this.SetValue(RangesProperty, value);
            }
        }

        /// <summary>
        /// Creates the model.
        /// </summary>
        /// <returns>
        /// An axis object.
        /// </returns>
        public override Axes.Axis CreateModel()
        {
            this.SynchronizeProperties();
            return this.InternalAxis;
        }

        /// <summary>
        /// Synchronizes the properties.
        /// </summary>
        protected override void SynchronizeProperties()
        {
            base.SynchronizeProperties();
            var axis = this.InternalAxis as Axes.RangeColorAxis;
            Trace.Assert(axis != null);
            //if (this.GradientStops != null)
            //{
            //    axis.Palette = this.GradientStops.Count > 2
            //                       ? Interpolate(this.GradientStops.ToList(), this.PaletteSize)
            //                       : new OxyPalette();
            //}

            axis.HighColor = this.HighColor.ToOxyColor();
            axis.LowColor = this.LowColor.ToOxyColor();
            axis.InvalidNumberColor = this.InvalidNumberColor.ToOxyColor();
            axis.Minimum = this.Minimum;
            axis.Maximum = this.Maximum;
            if (Ranges != null)
            {
                axis.ClearRanges();
                foreach (var range in Ranges)
                {
                    axis.AddRange(range.Item1, range.Item2, range.Item3.ToOxyColor());
                }
            }
        }

    }
}

XAML文件:

<oxyPlot:Plot.Axes>
    <oxyPlot:DateTimeAxis StringFormat="HH:mm:ss"></oxyPlot:DateTimeAxis>
    <oxyPlot:RangeColorAxis 
         Ranges="{Binding ColorRanges}" 
         Unit="{Binding Unit}" 
         AbsoluteMinimum="{Binding DisplayMin}" 
         AbsoluteMaximum="{Binding DisplayMax}" 
         MinimumRange="{Binding DisplayMax}"/>
</oxyPlot:Plot.Axes>

查看模型

...
/// <summary>
/// The <see cref="ColorRanges" /> property's name.
/// </summary>
public const string ColorRangesPropertyName = "ColorRanges";

private List<Tuple<double, double, System.Windows.Media.Color>> _colorRanges = new List<Tuple<double, double, System.Windows.Media.Color>>();

/// <summary>
/// Sets and gets the ColorRanges property.
/// Changes to that property's value raise the PropertyChanged event. 
/// </summary>
public List<Tuple<double, double, System.Windows.Media.Color>> ColorRanges
{
    get
    {
        return _colorRanges;
    }

    set
    {
        if (_colorRanges == value)
        {
            return;
        }

        _colorRanges = value;
        RaisePropertyChanged(ColorRangesPropertyName);
    }
}
...
//usage
ColorRanges.Clear();
if (DisplayMin < LevelThresholdLoLo)
{
    ColorRanges.Add(new Tuple<double, double, Color>(DisplayMin, LevelThresholdLoLo, Color.FromArgb(127,255,68,0)));
}
if (LevelThresholdLoLo < LevelThresholdLo)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdLoLo, LevelThresholdLo, Color.FromArgb(127, 255, 140, 0)));
}
if (LevelThresholdLo < LevelThresholdLoPre)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdLo, LevelThresholdLoPre, Color.FromArgb(127, 65,105,225)));
}
if (LevelThresholdLoPre < LevelThresholdHiPre)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdLoPre, LevelThresholdHiPre, Color.FromArgb(127, 50, 205, 50)));
}
if (LevelThresholdHiPre < LevelThresholdHi)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdHiPre, LevelThresholdHi, Color.FromArgb(127, 65, 105, 225)));
}
if (LevelThresholdHi < LevelThresholdHiHi)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdHi, LevelThresholdHiHi, Color.FromArgb(127,255,140,0)));
}
if (LevelThresholdHiHi < DisplayMax)
{
    ColorRanges.Add(new Tuple<double, double, Color>(LevelThresholdHiHi, DisplayMax, Color.FromArgb(127, 255, 68, 0)));
}