Steps with LogarithmicAxis
This discussion was imported from CodePlex
WeirdNoise wrote at 2013-07-22 14:08:
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:
I would like to have more displayed Steps (frequency labels) on the frequency axis, like this:
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
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:
I would like to have more displayed Steps (frequency labels) on the frequency axis, like this:
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
everytimer wrote at 2013-07-23 12:28:
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.
willmoore88 wrote at 2013-08-07 09:15:
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()....
Inside LogarithmicAxis.cs, GetTickValues()....
if (d2 >= this.ActualMinimum && d2 <= this.ActualMaximum)
{
//minorTickValues.Add(d2);
majorTickValues.Add(d2);
}
WeirdNoise wrote at 2013-08-11 17:20:
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:
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:
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:
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
everytimer wrote at 2013-08-11 19:38:
Great stuff, and good looking graph =)
Customer support service by UserEcho