问题描述
好吧,我几乎整天都在破解它,但没有成功.我正在尝试使用JFreeChart创建XYPlot
的网格,其中图的每一列和每一行都分别链接了域轴和范围轴.也就是说,同一行中的图具有相同的范围轴范围,而一列中的图具有相同的域轴范围.
Ok, I've been hacking at this for almost all day with no success. I'm trying to use JFreeChart to create a grid of XYPlot
s where the domain and range axes are linked for each column and row of plots, respectively. That is to say, the plots in the same row have the same range axis range, and the plots in a column have the same domain axis range.
我能够通过使用XYPlot
的CombinedRangeXYPlot
的被入侵的CombinedDomainXYPlot
来实现此功能.基本上,我做了一些XYPlot
对象,并将它们添加到CombinedRangeXYPlot
对象,然后将那些CombinedRangeXYPlot
对象添加到了不绘制域轴的CombinedDomainXYPlot
实例中. (也许因为我没有使用合并的域轴功能,所以还有一种方法可以代替CombinedDomainXYPlot
来堆积图.)
I was able to achieve the functionality by using a hacked CombinedDomainXYPlot
of CombinedRangeXYPlot
s of XYPlot
s. Basically I made some XYPlot
objects and added them to CombinedRangeXYPlot
objects, then added those CombinedRangeXYPlot
objects to an instance of CombinedDomainXYPlot
that doesnt draw a domain axis. (Maybe there is another way to stack plots instead of CombinedDomainXYPlot
, since I'm not using the combined domain axis functionality.)
每个行的范围将按预期比例缩放.通过为列中的每个子图添加相同的域轴,我可以使域针对每个列一起缩放.结果如下所示.
The ranges scale together for each row, as expected. By adding the same domain axis to each subplot in a column, I was able to get the domains to scale together for each column. Result is shown below.
我现在有两个问题-首先,我想摆脱每一行下方的轴标签,而只将它们放在底部,但要保持比例尺链接.
I have two problems right now - first, I would like to get rid of the axis labels below each row and just have them on the bottom, but keep the scales linked.
第二,范围轴的标签位于窗口的边缘-如何找回标签?
Second, the labels for the range axes are of the edge of the window - how do I get them back?
而且,总的来说,我想了解CombinedRangeXYPlot
和CombinedRangeXYPlot
如何在多个图上使用相同的轴范围而不在每个图下方绘制轴.
And, in general, I would like to understand how CombinedRangeXYPlot
and CombinedRangeXYPlot
use the same axis range for multiple plots without drawing the axes below each plot.
这是工作示例的代码:
主班
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类
StackedXYPlot class
public class StackedXYPlot extends CombinedDomainXYPlot {
public StackedXYPlot() {
super(null);
}
@Override
public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, PlotState parentState,
PlotRenderingInfo info) {
// set up info collection...
if (info != null) {
info.setPlotArea(area);
}
// adjust the drawing area for plot insets (if any)...
RectangleInsets insets = getInsets();
insets.trim(area);
setFixedRangeAxisSpaceForSubplots(null);
AxisSpace space = calculateAxisSpace(g2, area);
Rectangle2D dataArea = space.shrink(area, null);
// set the width and height of non-shared axis of all sub-plots
setFixedRangeAxisSpaceForSubplots(space);
// draw all the subplots
for (int i = 0; i < getSubplots().size(); i++) {
XYPlot plot = (XYPlot) getSubplots().get(i);
PlotRenderingInfo subplotInfo = null;
if (info != null) {
subplotInfo = new PlotRenderingInfo(info.getOwner());
info.addSubplotInfo(subplotInfo);
}
plot.draw(g2, this.subplotAreas[i], anchor, parentState, subplotInfo);
}
if (info != null) {
info.setDataArea(dataArea);
}
}
public int findSubplotIndex(PlotRenderingInfo info, Point2D source) {
ParamChecks.nullNotPermitted(info, "info");
ParamChecks.nullNotPermitted(source, "source");
XYPlot result = null;
return info.getSubplotIndex(source);
}
/**
* Multiplies the range on the range axis/axes by the specified factor.
*
* @param factor the zoom factor.
* @param info the plot rendering info (<code>null</code> not permitted).
* @param source the source point (<code>null</code> not permitted).
*/
@Override
public void zoomDomainAxes(double factor, PlotRenderingInfo info, Point2D source) {
zoomDomainAxes(factor, info, source, false);
}
/**
* Multiplies the range on the range axis/axes by the specified factor.
*
* @param factor the zoom factor.
* @param state the plot state.
* @param source the source point (in Java2D coordinates).
* @param useAnchor use source point as zoom anchor?
*/
@Override
public void zoomDomainAxes(double factor, PlotRenderingInfo state, Point2D source,
boolean useAnchor) {
// delegate 'state' and 'source' argument checks...
int subplotIndex = findSubplotIndex(state, source);
XYPlot subplot = null;
if (subplotIndex >= 0) {
subplot = (XYPlot) getSubplots().get(subplotIndex);
}
if (subplot != null) {
subplot.zoomDomainAxes(factor, state.getSubplotInfo(subplotIndex), source, useAnchor);
} else {
// if the source point doesn't fall within a subplot, we do the
// zoom on all subplots...
Iterator iterator = getSubplots().iterator();
while (iterator.hasNext()) {
subplot = (XYPlot) iterator.next();
subplot.zoomDomainAxes(factor, state, source, useAnchor);
}
}
}
/**
* Zooms in on the range axes.
*
* @param lowerPercent the lower bound.
* @param upperPercent the upper bound.
* @param info the plot rendering info (<code>null</code> not permitted).
* @param source the source point (<code>null</code> not permitted).
*/
@Override
public void zoomDomainAxes(double lowerPercent, double upperPercent, PlotRenderingInfo info,
Point2D source) {
// delegate 'info' and 'source' argument checks...
int subplotIndex = findSubplotIndex(info, source);
XYPlot subplot = null;
if (subplotIndex >= 0) {
subplot = (XYPlot) getSubplots().get(subplotIndex);
}
if (subplot != null) {
subplot.zoomDomainAxes(lowerPercent, upperPercent, info.getSubplotInfo(subplotIndex), source);
} else {
// if the source point doesn't fall within a subplot, we do the
// zoom on all subplots...
Iterator iterator = getSubplots().iterator();
while (iterator.hasNext()) {
subplot = (XYPlot) iterator.next();
subplot.zoomDomainAxes(lowerPercent, upperPercent, info, source);
}
}
}
/**
* Multiplies the range on the range axis/axes by the specified factor.
*
* @param factor the zoom factor.
* @param info the plot rendering info (<code>null</code> not permitted).
* @param source the source point (<code>null</code> not permitted).
*/
@Override
public void zoomRangeAxes(double factor, PlotRenderingInfo info, Point2D source) {
zoomRangeAxes(factor, info, source, false);
}
/**
* Multiplies the range on the range axis/axes by the specified factor.
*
* @param factor the zoom factor.
* @param state the plot state.
* @param source the source point (in Java2D coordinates).
* @param useAnchor use source point as zoom anchor?
*/
@Override
public void zoomRangeAxes(double factor, PlotRenderingInfo state, Point2D source,
boolean useAnchor) {
// delegate 'state' and 'source' argument checks...
int subplotIndex = findSubplotIndex(state, source);
XYPlot subplot = null;
if (subplotIndex >= 0) {
subplot = (XYPlot) getSubplots().get(subplotIndex);
}
if (subplot != null) {
subplot.zoomRangeAxes(factor, state.getSubplotInfo(subplotIndex), source, useAnchor);
} else {
// if the source point doesn't fall within a subplot, we do the
// zoom on all subplots...
Iterator iterator = getSubplots().iterator();
while (iterator.hasNext()) {
subplot = (XYPlot) iterator.next();
subplot.zoomRangeAxes(factor, state, source, useAnchor);
}
}
}
/**
* Zooms in on the range axes.
*
* @param lowerPercent the lower bound.
* @param upperPercent the upper bound.
* @param info the plot rendering info (<code>null</code> not permitted).
* @param source the source point (<code>null</code> not permitted).
*/
@Override
public void zoomRangeAxes(double lowerPercent, double upperPercent, PlotRenderingInfo info,
Point2D source) {
// delegate 'info' and 'source' argument checks...
int subplotIndex = findSubplotIndex(info, source);
XYPlot subplot = null;
if (subplotIndex >= 0) {
subplot = (XYPlot) getSubplots().get(subplotIndex);
}
if (subplot != null) {
subplot.zoomRangeAxes(lowerPercent, upperPercent, info.getSubplotInfo(subplotIndex), source);
} else {
// if the source point doesn't fall within a subplot, we do the
// zoom on all subplots...
Iterator iterator = getSubplots().iterator();
while (iterator.hasNext()) {
subplot = (XYPlot) iterator.next();
subplot.zoomRangeAxes(lowerPercent, upperPercent, info, source);
}
}
}
}
我相信要使StackedXYPlot正常工作,我要做的唯一另一件事就是将CombinedDomainXYPlot.subplotAreas
的可见性更改为protected
.
I believe the only other thing I had to do to get the StackedXYPlot to work is change visibility of CombinedDomainXYPlot.subplotAreas
to protected
.
在此示例中,我注意到域轴的鼠标缩放功能已关闭-但确实会传播到列中的其他图.
I noticed with this example that the mouse zoom of the domain axis is off - but it does propagate to the other plots in the column.
谢谢
伊戈尔
P.S.之所以要删除该图下面的图,是因为最后我至少要绘制一个6x7的图网格,并且在这么多的网格中,标签占据了大部分空间.
P.S. the reason I want to eliminate the plots below the plot is because in the end I need to plot at least a 6x7 grid of plots and with that many, the labels take up most of the space.
编辑:我已经接受Eric的回答,认为它是功能性的,但我正在尝试一种不太hacky的方式-.如果我可以完全正常运行,我将在那里进行更新.
Edit: I have accepted Eric's answer as functional, but I am working on a less hackish way of doing it - How CombinedDomainXYPlot and CombinedRangeXYPlot share Axis information with subplots. I'll update there if I get it completely functional.
推荐答案
那真的很困难……
从您的代码开始,这就是我接近的程度:
This is how close I got, starting from your code:
-
将域轴设置为不可见:
Set the domain axes invisible:
ValueAxis a = phiDPlots[i].getDomainAxis();
a.setVisible(false);
tempPlot.setDomainAxis((NumberAxis) phiDPlots[i].getDomainAxis());
如果绘制最后一行,则设置子图的域轴可见:
Set the subplot's domain axes visible if drawing the last row:
// 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);
}
}
这有效,但是以某种方式仅在刷新/调整窗口大小之后,因为图形的最后一行在垂直方向上过于压缩...
This works, but somehow only after a refresh/resize of the window, because the last row of graphs is too compressed vertically...
这篇关于如何在不绘制每个图的情况下跨子图共享DomainAxis/RangeAxis?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!