Steps with LogarithmicAxis

Jul 22, 2013 at 1:08 PM
Hello,
I'm trying to put together a little tool for displaying audio measurements. Such plots do usually have two logarithmic axes, though the amplitude axis is scaled linear by using dB.

The frequency axis, however, should be scaled logarithmic and has to cover approximately the human range of audibility from 20 Hz to 20 kHz. If I set up a plot using a logarithmic oxyPlot, I get something like this:
Image

I would like to have more displayed Steps (frequency labels) on the frequency axis, like this:
Image

Obviously, I can't just adjust the Axis' Base, as I would get rather odd numbers. Is there any way to achieve such an axis labeling with oxyPlot?

Thanks in advance
Jul 23, 2013 at 11:28 AM
I don't think it's possible right now. You should modify the GetTickValues method inside the LogarithmicAxis.cs file (particularly majorTickValues list). Please post the solution if you find out how to do it. Good luck.
Aug 7, 2013 at 8:15 AM
If you're not bothered about the minor ticks being the same size as major ticks then this is a bit of a hacky way to do this. Just change the minor ticks to major ticks.

Inside LogarithmicAxis.cs, GetTickValues()....
                    if (d2 >= this.ActualMinimum && d2 <= this.ActualMaximum)
                    {
                        //minorTickValues.Add(d2);
                        majorTickValues.Add(d2);
                    }
Aug 11, 2013 at 4:20 PM
Edited Aug 14, 2013 at 9:00 AM
Hello there,
it's been a while... Finally got to work on this.
everytimer: Thanks for pointing me in the right direction!

Main differences between my implementation and original (assuming base=10, but works with any other base):
-You can zoom out and display many decades without messing up the labels
-A Decade is subdivided if there's enough space for the labels
-The IntervalLength property is actually used by the algorithm

Example:
Image

For several reasons, I did my fix in the form of a simple override.
In case anyone's interested and not bothered by a little VB:
Imports System.Math

Public Class MyLogAxis
    Inherits Axes.LogarithmicAxis

    Public Overrides Sub GetTickValues(ByRef majorLabelValues As IList(Of Double), ByRef majorTickValues As IList(Of Double), ByRef minorTickValues As IList(Of Double))

        majorTickValues = New List(Of Double)
        minorTickValues = New List(Of Double)

        Dim screensize As Integer
        If Me.IsHorizontal Then
            screensize = Me.ScreenMax.X - Me.ScreenMin.X
        Else
            screensize = Me.ScreenMax.Y - Me.ScreenMin.Y
        End If

        Dim totalBW As Double = Log(Me.ActualMaximum, Me.Base) - Log(Me.ActualMinimum, Me.Base)
        Dim BWratio As Double = width / totalBW

        If totalBW < 1 Then
            MyBase.GetTickValues(majorLabelValues, majorTickValues, minorTickValues)

        ElseIf BWratio < Me.IntervalLength Then
            Dim steps As Integer = Ceiling(Me.IntervalLength / BWratio)
            Dim c As Double = Ceiling(Log(Me.ActualMinimum, Me.Base))

            While c < Floor(Log(Me.ActualMaximum, Me.Base))
                minorTickValues.Add(Round(Pow(Me.Base, c), 10))
                If c Mod steps = 0 Then
                    majorTickValues.Add(Round(Pow(Me.Base, c), 10))
                End If
                c += 1
            End While

        Else
            Dim c As Double = Floor(Log(Me.ActualMinimum, Me.Base))
            Dim v As Double
            Dim c2 As Double
            Dim lower As Double
            While c < Ceiling(Log(Me.ActualMaximum, Me.Base)) + 1

                v = Pow(Me.Base, c)
                If v > Me.ActualMinimum And v < Me.ActualMaximum Then
                    majorTickValues.Add(Round(v, 10))
                End If

                Dim a As Integer = 1
                lower = c

                While a < Me.Base
                    c2 = c + Log(a, Me.Base)
                    v = Pow(Me.Base, c2)
                    If v + 0.00001 >= Me.ActualMinimum And v <= Me.ActualMaximum + 0.00001 Then
                        minorTickValues.Add(Round(Pow(Me.Base, c2), 10))
                        If BWratio * Min(c2 - lower, c + 1 - c2) > Me.IntervalLength Then
                            majorTickValues.Add(Round(v, 10))
                            lower = c2
                        End If
                    End If

                    a += 1
                End While
                c += 1
            End While
        End If
        majorLabelValues = majorTickValues
    End Sub
End Class
Aug 11, 2013 at 6:38 PM
Great stuff, and good looking graph =)