jFreeChart轮廓图渲染不正确

时间:2016-02-11 16:00:44

标签: scala jfreechart

代码:

package vu.co.kaiyin.sfreechart.plots

import java.awt.{Shape, Stroke, RenderingHints}
import javax.swing.JFrame

import org.jfree.chart.plot.{PlotOrientation, XYPlot}
import org.jfree.chart.{ChartFactory => cf}
import org.jfree.chart.renderer.GrayPaintScale
import org.jfree.chart.renderer.xy.XYBlockRenderer
import org.jfree.chart.title.PaintScaleLegend
import org.jfree.chart._
import org.jfree.chart.axis.{AxisLocation, NumberAxis}
import org.jfree.data.Range
import org.jfree.data.general.DatasetUtilities
import org.jfree.data.statistics.HistogramDataset
import org.jfree.data.xy.{IntervalXYDataset, XYZDataset}
import org.jfree.ui.{RectangleEdge, RectangleInsets}
import vu.co.kaiyin.sfreechart.{ColorPaintScale, ExtendedFastScatterPlot}
import vu.co.kaiyin.sfreechart.implicits._
import scala.util.Random.nextGaussian

/**
  * Created by kaiyin on 2/10/16.
  */
object Plots {


  def histogram(
                 dataset: IntervalXYDataset,
                 title: String = "Histogram",
                 xAxisLabel: String = "Intervals",
                 yAxisLabel: String = "Count",
                 orientation: PlotOrientation = PlotOrientation.VERTICAL,
                 legend: Boolean = true,
                 tooltips: Boolean = true,
                 urls: Boolean = true,
                 alpha: Float = 0.5F,
                 pannable: Boolean = false
               ): JFreeChart = {
    val hist = cf.createHistogram(
      title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls
    )
    val xyPlot = hist.getPlot.asInstanceOf[XYPlot]
    if (pannable) {
      xyPlot.setDomainPannable(true)
      xyPlot.setRangePannable(true)
    }
    xyPlot.setForegroundAlpha(alpha)
    hist
  }

  def controuPlot(dataset: XYZDataset, title: String = "Contour plot", scaleTitle: String = "Scale"): JFreeChart = {
    val xAxis = new NumberAxis("x")
    val yAxis = new NumberAxis("y")
    val blockRenderer = new XYBlockRenderer
    val zBounds: Range = DatasetUtilities.findZBounds(dataset)
    println(zBounds.getLowerBound, zBounds.getUpperBound)
    val paintScale = new ColorPaintScale(zBounds.getLowerBound, zBounds.getUpperBound)
    blockRenderer.setPaintScale(paintScale)
    val xyPlot = new XYPlot(dataset, xAxis, yAxis, blockRenderer)
    xyPlot.setAxisOffset(new RectangleInsets(1D, 1D, 1D, 1D))
    xyPlot.setDomainPannable(true)
    xyPlot.setRangePannable(true)
    val chart = new JFreeChart(title, xyPlot)
    chart.removeLegend()
    val scaleAxis = new NumberAxis(scaleTitle)
    val paintScaleLegend = new PaintScaleLegend(paintScale, scaleAxis)
    paintScaleLegend.setAxisLocation(AxisLocation.BOTTOM_OR_LEFT)
    paintScaleLegend.setPosition(RectangleEdge.BOTTOM)
    chart.addSubtitle(paintScaleLegend)
    chart
  }


  def fastScatter(data: Array[Array[Float]], title: String = "Scatter plot", pointSize: Int = 5, pointAlpha: Float = 0.3F): JFreeChart = {
    val xAxis = new NumberAxis("x")
    val yAxis = new NumberAxis("y")
    xAxis.setAutoRangeIncludesZero(false)
    yAxis.setAutoRangeIncludesZero(false)
    val fsPlot = new ExtendedFastScatterPlot(data, xAxis, yAxis, pointSize, pointAlpha)
    fsPlot.setDomainPannable(true)
    fsPlot.setRangePannable(true)
    val chart = new JFreeChart(title, fsPlot)
    chart.getRenderingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
    chart
  }

  def main(args: Array[String]) {
    //    fastScatter(Array(Array(1.0F, 2.0F, 3.0F), Array(1.0F, 2.0F, 3.0F))).vis()
    val x = (1 to 10000).map(_.toFloat).toArray
    val y = x.map(i => i * nextGaussian().toFloat * 3F).toArray
    fastScatter(Array(x, y)).vis()
    val x1 = (-13.0 to 13.0 by 0.2).toArray
    val y1 = (-13.0 to 13.0 by 0.2).toArray
    val xyzData = (for {
      i <- x1
      j <- y1
      if i > j
    } yield Array(i, j, math.sin(i) + math.cos(j))).transpose
    controuPlot(xyzData.toXYZDataset()).vis()
    histogram((1 to 10000).map(_ => nextGaussian()).toArray.toHistogramDataset()).vis()
  }
}

可在此处找到完整项目:https://github.com/kindlychung/sfreechart

运行上面的代码会给你:

enter image description here

如果你仔细观察,你会发现沿着对角线边缘的一个窄带像素不太合适(这是sin(x)+ cos(y)的等高线图),好像有一个撕裂转移。但如果我注释掉if i < j行,那么情节看起来很正常:

enter image description here

出了什么问题以及如何解决这个问题?

更新

实际上,如果仔细观察上面第二幅图的右边缘,还有一条不应该在那里的条带。

1 个答案:

答案 0 :(得分:0)

我设法用散点图伪造等高线图:

  val x = (-12.0 to 12.0 by 0.1).toArray
  val y = (-12.0 to 12.0 by 0.1).toArray
  val xyzData = (for {
    i <- x
    j <- y
  } yield {
    val s = math.sin(i)
    val c = math.cos(j)
    Array(i, j, s + c)
  }).transpose
  fastScatter(xyzData.toFloats, grid = (false, false), pointSize = 4, pointAlpha = 1F).vis()

fastScatter的实施可以在这里找到:https://github.com/kindlychung/sfreechart(披露:我是作者。)