在JFreeChart中指定对数轴值(标签和刻度)

时间:2014-08-21 14:34:18

标签: scala jfreechart

我正在努力LogAxis以获得合理的频率标签,例如:使用A4 = 440 Hz的相等淬火比例,例如this table,我希望标签出现在例如

(30 to 120 by 2).map(midicps).foreach(println)

46.249302
51.91309
58.270466
65.406395
73.4162
82.40688
92.498604
103.82618
116.54095
130.81279
146.83238
164.81378
184.99721
207.65234
233.08188
261.62558
293.66476
329.62756
369.99442
415.3047
466.16376
523.25116
587.3295
...
4698.6367
5274.0405
5919.9106
6644.8755
7458.621
8372.019

赫兹,在哪里

def midicps(d: Double): Double = 440 * math.pow(2, (d - 69) / 12)

换句话说,我每个八度音程有12个分区(值加倍),固定频率为440.0。我碰巧有一个32.7的下限和16700.0的上限。

我的第一次尝试:

import org.jfree.chart._
val pl = new plot.XYPlot
val yaxis = new axis.LogAxis
yaxis.setLowerBound(32.7)
yaxis.setUpperBound(16.7e3)
yaxis.setBase(math.pow(2.0, 1.0/12))
yaxis.setMinorTickMarksVisible(true)
yaxis.setStandardTickUnits(axis.NumberAxis.createStandardTickUnits())
pl.setRangeAxis(yaxis)
val ch = new JFreeChart(pl)
val pn = new ChartPanel(ch)
new javax.swing.JFrame {
  getContentPane.add(pn)
  pack()
  setVisible(true)
}

这使我的标签不属于上述任何光栅点:

enter image description here

如何强制执行我的栅格?

1 个答案:

答案 0 :(得分:1)

一种可能性是在JFreeChart之外进行日志< - > lin转换,并使用自定义数字格式转换回来:

import java.text.{ParsePosition, FieldPosition, NumberFormat}
import scalax.chart.api._

object PDFLogAxis extends App {
  scala.swing.Swing.onEDT(run())

  def midicps(d: Double): Double = 440 * math.pow(2, (d - 69) / 12)
  def cpsmidi(d: Double): Double = math.log(d / 440) / math.log(2) * 12 + 69

  def run(): Unit = {
    val lo    = cpsmidi(32.7)    // log -> lin
    val hi    = cpsmidi(16.7e3)
    val data  = Vector((0.0, lo), (1.0, hi))
    val chart = XYLineChart(data, title = "", legend = false)
    val yAxis = chart.plot.range.axis.peer
      .asInstanceOf[org.jfree.chart.axis.NumberAxis]
    yAxis.setLowerBound(lo)
    yAxis.setUpperBound(hi)
    yAxis.setNumberFormatOverride(new NumberFormat {
      def format(d: Double, sb: StringBuffer, 
                 pos: FieldPosition): StringBuffer = {
        val freq = midicps(d)  // lin -> log
        sb.append(f"$freq%1.1f")
      }

      def parse(s: String, parsePosition: ParsePosition): Number = ???

      def format(d: Long, sb: StringBuffer, 
                 pos: FieldPosition): StringBuffer = ???
    })
    chart.show()
  }
}