Java 如何在子地块上共享DomainAxis/RangeAxis,而不在每个地块上绘制它们?

Java 如何在子地块上共享DomainAxis/RangeAxis,而不在每个地块上绘制它们?,java,plot,jfreechart,Java,Plot,Jfreechart,好吧,我几乎整天都在做这个,但没有成功。我试图使用JFreeChart创建一个由XYPlots组成的网格,其中域轴和范围轴分别链接到绘图的每一列和每一行。也就是说,同一行中的图具有相同的范围轴范围,而一列中的图具有相同的域轴范围 我能够通过使用CombinedDomainXYPlot的CombinedRangeXYPlots的XYPlots来实现该功能。基本上,我制作了一些XYPlot对象并将它们添加到CombinedRangeXYPlot对象中,然后将那些CombinedRangeXYPlot

好吧,我几乎整天都在做这个,但没有成功。我试图使用JFreeChart创建一个由
XYPlot
s组成的网格,其中域轴和范围轴分别链接到绘图的每一列和每一行。也就是说,同一行中的图具有相同的范围轴范围,而一列中的图具有相同的域轴范围

我能够通过使用
CombinedDomainXYPlot
CombinedRangeXYPlot
s的
XYPlot
s来实现该功能。基本上,我制作了一些
XYPlot
对象并将它们添加到
CombinedRangeXYPlot
对象中,然后将那些
CombinedRangeXYPlot
对象添加到一个不绘制域轴的
CombinedDomainXYPlot
实例中。(可能有另一种方法来堆叠绘图,而不是
CombinedDomainXYPlot
,因为我没有使用合并域轴功能。)

正如预期的那样,每行的范围都会一起缩放。通过将相同的域轴添加到列中的每个子图中,我能够为每个列将域缩放到一起。结果如下所示

我现在有两个问题-首先,我想去掉每行下面的轴标签,只把它们放在底部,但保持比例链接

第二,范围轴的标签位于窗口边缘-如何将其取回

通常,我想了解
CombinedRangeXYPlot
CombinedRangeXYPlot
如何在多个图中使用相同的轴范围,而不在每个图下方绘制轴

编辑:以下是工作演示的代码:

主类

public class GridBlockPlotFrameExample {

  private final JFrame frame;
  private final XYPlot[][] phiPhiPlots;
  private final XYPlot[] phiDPlots;

  public GridBlockPlotFrameExample() {
    frame = new JFrame("Density Plot");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    phiDPlots = new XYPlot[4];
    phiPhiPlots = new XYPlot[4][4];

    createSubPlots();
    CombinedRangeXYPlot[] rowPlots = new CombinedRangeXYPlot[phiDPlots.length + 1];
    for (int i = 0; i < phiPhiPlots.length; i++) {
      rowPlots[i + 1] = new CombinedRangeXYPlot();
      for (int j = 0; j < phiPhiPlots[i].length; j++) {
        if (phiPhiPlots[i][j] != null) {
          rowPlots[i + 1].add(phiPhiPlots[i][j]);
        } else {
          rowPlots[i + 1].add(new XYPlot());
        }
      }
    }
    rowPlots[0] = new CombinedRangeXYPlot();
    for (XYPlot phiDPlot : phiDPlots) {
      rowPlots[0].add(phiDPlot);
    }

    StackedXYPlot gridPlot = new StackedXYPlot();

    for (int i = rowPlots.length - 1; i >= 1; i--) {
      XYPlot rowPlot = rowPlots[i];
      gridPlot.add(rowPlot, 2);
    }
    gridPlot.add(rowPlots[0], 1);

    JFreeChart chart = new JFreeChart("gridplot", JFreeChart.DEFAULT_TITLE_FONT, gridPlot, false);
    chart.setBackgroundPaint(Color.WHITE);

    ChartPanel panel = new ChartPanel(chart);
    panel.setPreferredSize(new Dimension(300, 300));
    panel.setMouseWheelEnabled(false);
    panel.setRangeZoomable(true);
    panel.setDomainZoomable(true);

    frame.setContentPane(panel);
    frame.pack();

    RefineryUtilities.centerFrameOnScreen(frame);
  }

  private void createSubPlots() {
    for (int i = 0; i < phiDPlots.length; i++) {
      phiDPlots[i] = createPlot(createDataset());
    }
    XYPlot tempPlot;
    for (int i = 0; i < phiPhiPlots.length; i++) {
      for (int j = 0; j < phiPhiPlots.length; j++) {
        tempPlot = createPlot(createDataset());
        phiPhiPlots[j][i] = tempPlot; // (sic) YES this inversion is intentional
        tempPlot.setDomainAxis((NumberAxis) phiDPlots[i].getDomainAxis());
      }
    }
  }

  private XYPlot createPlot(XYZDataset data) {
    NumberAxis xAxis = new NumberAxis("X");
    xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
    xAxis.setLowerMargin(0.0);
    xAxis.setUpperMargin(0.0);
    xAxis.setAxisLinePaint(Color.white);
    xAxis.setTickMarkPaint(Color.white);
    NumberAxis yAxis = new NumberAxis("Y");
    yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
    yAxis.setLowerMargin(0.0);
    yAxis.setUpperMargin(0.0);
    yAxis.setAxisLinePaint(Color.white);
    yAxis.setTickMarkPaint(Color.white);
    XYBlockRenderer renderer = new XYBlockRenderer();
    PaintScale scale = new GrayPaintScale(-2.0, 1.0);
    renderer.setPaintScale(scale);
    XYPlot plot = new XYPlot(data, xAxis, yAxis, renderer);
    plot.setBackgroundPaint(Color.lightGray);
    plot.setDomainGridlinesVisible(false);
    plot.setRangeGridlinePaint(Color.white);
    plot.setAxisOffset(new RectangleInsets(5, 5, 5, 5));
    plot.setOutlinePaint(Color.blue);
    return plot;
  }

  private XYZDataset createDataset() {
    return new XYZDataset() {

      @Override
      public int getSeriesCount() {
        return 1;
      }

      @Override
      public int getItemCount(int series) {
        return 10000;
      }

      @Override
      public Number getX(int series, int item) {
        return new Double(getXValue(series, item));
      }

      @Override
      public double getXValue(int series, int item) {
        return item / 100 - 50;
      }

      @Override
      public Number getY(int series, int item) {
        return new Double(getYValue(series, item));
      }

      @Override
      public double getYValue(int series, int item) {
        return item - (item / 100) * 100 - 50;
      }

      @Override
      public Number getZ(int series, int item) {
        return new Double(getZValue(series, item));
      }

      @Override
      public double getZValue(int series, int item) {
        double x = getXValue(series, item);
        double y = getYValue(series, item);
        return Math.sin(Math.sqrt(x * x + y * y) / 5.0);
      }

      @Override
      public void addChangeListener(DatasetChangeListener listener) {
        // ignore - this dataset never changes
      }

      @Override
      public void removeChangeListener(DatasetChangeListener listener) {
        // ignore
      }

      @Override
      public DatasetGroup getGroup() {
        return null;
      }

      @Override
      public void setGroup(DatasetGroup group) {
        // ignore
      }

      @Override
      public Comparable getSeriesKey(int series) {
        return "sin(sqrt(x + y))";
      }

      @Override
      public int indexOf(Comparable seriesKey) {
        return 0;
      }

      @Override
      public DomainOrder getDomainOrder() {
        return DomainOrder.ASCENDING;
      }
    };
  }


  public void show() {
    frame.setVisible(true);
  }

  public static void main(String[] args) {
    GridBlockPlotFrameExample example = new GridBlockPlotFrameExample();
    example.show();
  }
}

我相信,要使StackedXYPlot正常工作,我唯一要做的另一件事就是将
组合域XYPlot.subplotAreas
的可见性更改为
受保护的

我注意到在这个例子中,域轴的鼠标缩放是关闭的,但它确实会传播到列中的其他绘图

谢谢

伊戈尔

另一方面,我之所以要删除绘图下方的绘图,是因为最终我需要绘制至少6x7的绘图网格,因为有这么多,标签占据了大部分空间


编辑:我接受了Eric的回答,认为它是功能性的,但我正在研究一种不那么粗俗的方法-。如果我能让它完全正常运行,我会在那里进行更新。

这真是个难题

从你的代码开始,我已经接近了:

  • 将域轴设置为不可见:

    ValueAxis a = phiDPlots[i].getDomainAxis();
    a.setVisible(false);
    tempPlot.setDomainAxis((NumberAxis) phiDPlots[i].getDomainAxis());
    
  • 如果绘制最后一行,则将子批次的域轴设置为可见:

    // draw all the subplots
    for (int i = 0; i < this.getSubplots().size(); i++) {
        CombinedRangeXYPlot plot = (CombinedRangeXYPlot) this.getSubplots().get(i);
        PlotRenderingInfo subplotInfo = null;
        if (info != null) {
            subplotInfo = new PlotRenderingInfo(info.getOwner());
            info.addSubplotInfo(subplotInfo);
        }
    
        if(i==getSubplots().size()-1){  // If the last row
            for(int j=0; j < plot.getSubplots().size(); j++)
                ((XYPlot)plot.getSubplots().get(j)).getDomainAxis().setVisible(true);
        }
    
        plot.draw(g2, this.subplotAreas[i], anchor, parentState, subplotInfo);
    
        if(i==getSubplots().size()-1){  // If the last row
            for(int j=0; j < plot.getSubplots().size(); j++)
                ((XYPlot)plot.getSubplots().get(j)).getDomainAxis().setVisible(false);
        }
    }
    
    //绘制所有子图
    for(int i=0;i
  • 这是可行的,但不知何故,只有在刷新/调整窗口大小之后,因为最后一行图形的垂直压缩太大


    您能分享一个我们可以使用的最小运行示例吗?也许以下内容适合您:1)
    在域轴上设置可见(false)
    (因此,列中的绘图一起缩放,但没有标签。2)在
    组合域XYPLOT中绘制域轴,因此,在每列的底部都有一个轴。@EricLeibenguth-我已经为我的问题的一个运行示例添加了代码。@EricLeibenguth-如果我能想出如何实现它,那就好了。我不知道如何为每列绘制单独的域轴。另外,我认为如果我在两个绘图之间共享的轴上设置Visible(false)
    ,它将不会在
    CombinedDomainXYPlot
    中绘图。我想有办法强迫它画在那里,但我不知道怎么画。正如我在帖子中所说的,我真的不明白如何在
    组合域xyplot
    中绘制绘图,并且该信息与子绘图共享,没有它们也会绘制域轴。我无法编译
    堆栈域xyplot
    ,因为
    这个.subplotAreas
    是一个私有字段…谢谢Eric!我要试试这个!我可以修正导致最后一行太小的权重,这是一个小问题。这在很大程度上是有效的,但存在一个隐藏的性能缺陷-图表正在不断重新绘制,可能是因为
    setVisible
    通知它的侦听器。太糟糕了。。。也许,您还可以使用自定义的
    NumberAxis
    覆盖
    setVisible()
    ?Eric-是的,现在我这样做了:
    xAxis=newnumberaxis(“Phi”){@override public void setVisible(布尔标志){if(标志!=this.visible){this.visible=flag;}我需要将
    可见的
    变量更改为受保护的…我接受这个答案。我认为我已经提出了一个解决方案,该解决方案更符合此类功能的实现方式(请参阅:)
    
    // draw all the subplots
    for (int i = 0; i < this.getSubplots().size(); i++) {
        CombinedRangeXYPlot plot = (CombinedRangeXYPlot) this.getSubplots().get(i);
        PlotRenderingInfo subplotInfo = null;
        if (info != null) {
            subplotInfo = new PlotRenderingInfo(info.getOwner());
            info.addSubplotInfo(subplotInfo);
        }
    
        if(i==getSubplots().size()-1){  // If the last row
            for(int j=0; j < plot.getSubplots().size(); j++)
                ((XYPlot)plot.getSubplots().get(j)).getDomainAxis().setVisible(true);
        }
    
        plot.draw(g2, this.subplotAreas[i], anchor, parentState, subplotInfo);
    
        if(i==getSubplots().size()-1){  // If the last row
            for(int j=0; j < plot.getSubplots().size(); j++)
                ((XYPlot)plot.getSubplots().get(j)).getDomainAxis().setVisible(false);
        }
    }