Jfreechart 注释消失 [英] Jfreechart annotations disappearing
问题描述
我用 JFreechart 绘制了一条曲线.然后用户可以通过拖动鼠标来绘制范围.这些我使用 AbstractChartAnnotation 绘制填充的 Path2D.到目前为止一切顺利 - 一切都与曲线完美对齐.
I plot a curve with JFreechart. Then the user can draw ranges by dragging the mouse. These I plot using AbstractChartAnnotation to draw a filled Path2D. So far so nice - all aligns perfectly with the curve.
当一个区域已经被注释时,新的注释会被删除.我将 XYPlot.removeAnnotation
与新注释一起使用.
When an area was already annotated the new annotation gets deleted. I use XYPlot.removeAnnotation
with the new annotation.
我的问题是有时不仅新"注释被删除,而且情节中其他地方的第二个注释也会被删除.这似乎不是随机的 - 我有点发现右侧"的注释更容易发生这种情况.
My problem is that sometimes not only the "new" annotation gets removed, but also a second annotation elsewhere in the plot. It doesn't seem random - I kinda found annotations to the "right" side more prone to this happening.
我很困惑是什么导致了这种情况.绘制/删除新注释的对象每次都会恢复,并且只保存当前的注释——那么如何删除另一个注释?
I'm very confused what could cause this. The object that draws/deletes the new annotation is reinstated every time and only holds the current annotation - so how could the other annotation be deleted?
非常感谢您的任何提示,谢谢.
Would be very grateful for any hints, thanks.
按照建议,我准备了一个 sscce 示例.不幸的是,它并不太短.
As suggested I prepare a sscce example. Unfortunately it's not too short.
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.*;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.event.MouseInputListener;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.AbstractXYAnnotation;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.TimeSeriesDataItem;
import org.jfree.ui.RectangleEdge;
/**
*
* @author c.ager
*/
public class IntegrationSSCE {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setLayout(new BorderLayout());
jFrame.setSize(600, 400);
jFrame.setDefaultCloseOperation(jFrame.EXIT_ON_CLOSE);
TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection();
TimeSeries timeSeries = new TimeSeries("test");
for (long i = 0; i < 1000; i++) {
double val = Math.random() + 3 * Math.exp(-Math.pow(i - 300, 2) / 1000);
timeSeries.add(new Millisecond(new Date(i)), val);
}
timeSeriesCollection.addSeries(timeSeries);
JFreeChart chart = ChartFactory.createTimeSeriesChart(
null,
null, "data", timeSeriesCollection,
true, true, false);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.removeMouseListener(chartPanel);
Set<MyAnnot> annotSet = new TreeSet<MyAnnot>();
AnnotListener list = new AnnotListener(chartPanel, annotSet, timeSeries);
chartPanel.addMouseListener(list);
chartPanel.addMouseMotionListener(list);
jFrame.add(chartPanel, BorderLayout.CENTER);
jFrame.setVisible(true);
// TODO code application logic here
}
private static class AnnotListener implements MouseInputListener {
Point2D start, end;
MyAnnot currAnnot;
final Set<MyAnnot> annotSet;
final ChartPanel myChart;
final TimeSeries timeSeries;
public AnnotListener(ChartPanel myChart, Set<MyAnnot> annotSet, TimeSeries timeSeries) {
this.myChart = myChart;
this.annotSet = annotSet;
this.timeSeries = timeSeries;
}
@Override
public void mousePressed(MouseEvent e) {
start = convertScreePoint2DataPoint(e.getPoint());
currAnnot = new MyAnnot(start, timeSeries, myChart.getChart().getXYPlot());
myChart.getChart().getXYPlot().addAnnotation(currAnnot);
}
@Override
public void mouseDragged(MouseEvent e) {
end = convertScreePoint2DataPoint(e.getPoint());
currAnnot.updateEnd(end);
}
@Override
public void mouseReleased(MouseEvent e) {
boolean test = annotSet.add(currAnnot);
if (!test) {
myChart.getChart().getXYPlot().removeAnnotation(currAnnot);
}
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseMoved(MouseEvent e) {
}
protected Point2D convertScreePoint2DataPoint(Point in) {
Rectangle2D plotArea = myChart.getScreenDataArea();
XYPlot plot = (XYPlot) myChart.getChart().getPlot();
double x = plot.getDomainAxis().java2DToValue(in.getX(), plotArea, plot.getDomainAxisEdge());
double y = plot.getRangeAxis().java2DToValue(in.getY(), plotArea, plot.getRangeAxisEdge());
return new Point2D.Double(x, y);
}
}
private static class MyAnnot extends AbstractXYAnnotation implements Comparable<MyAnnot> {
Long max;
Line2D line;
final TimeSeries timeSeries;
final XYPlot plot;
final Stroke stroke = new BasicStroke(1.5f);
public MyAnnot(Point2D start, TimeSeries timeSeries, XYPlot plot) {
this.plot = plot;
this.timeSeries = timeSeries;
line = new Line2D.Double(start, start);
findMax();
}
public void updateEnd(Point2D end) {
line.setLine(line.getP1(), end);
findMax();
fireAnnotationChanged();
}
@Override
public void draw(Graphics2D gd, XYPlot xyplot, Rectangle2D rd, ValueAxis va, ValueAxis va1, int i, PlotRenderingInfo pri) {
PlotOrientation orientation = plot.getOrientation();
RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
plot.getDomainAxisLocation(), orientation);
RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
plot.getRangeAxisLocation(), orientation);
double m02 = va.valueToJava2D(0, rd, domainEdge);
// y-axis translation
double m12 = va1.valueToJava2D(0, rd, rangeEdge);
// x-axis scale
double m00 = va.valueToJava2D(1, rd, domainEdge) - m02;
// y-axis scale
double m11 = va1.valueToJava2D(1, rd, rangeEdge) - m12;
Shape s = null;
if (orientation == PlotOrientation.HORIZONTAL) {
AffineTransform t1 = new AffineTransform(
0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
AffineTransform t2 = new AffineTransform(
m11, 0.0f, 0.0f, m00, m12, m02);
s = t1.createTransformedShape(line);
s = t2.createTransformedShape(s);
} else if (orientation == PlotOrientation.VERTICAL) {
AffineTransform t = new AffineTransform(m00, 0, 0, m11, m02, m12);
s = t.createTransformedShape(line);
}
gd.setStroke(stroke);
gd.setPaint(Color.BLUE);
gd.draw(s);
addEntity(pri, s.getBounds2D(), i, getToolTipText(), getURL());
}
@Override
public int compareTo(MyAnnot o) {
return max.compareTo(o.max);
}
private void findMax() {
max = (long) line.getP1().getX();
Point2D left, right;
if (line.getP1().getX() < line.getP2().getX()) {
left = line.getP1();
right = line.getP2();
} else {
left = line.getP2();
right = line.getP1();
}
Double maxVal = left.getY();
List<TimeSeriesDataItem> items = timeSeries.getItems();
for (Iterator<TimeSeriesDataItem> it = items.iterator(); it.hasNext();) {
TimeSeriesDataItem dataItem = it.next();
if (dataItem.getPeriod().getFirstMillisecond() < left.getX()) {
continue;
}
if (dataItem.getPeriod().getFirstMillisecond() > right.getX()) {
break;
}
double curVal = dataItem.getValue().doubleValue();
if (curVal > maxVal) {
maxVal = curVal;
max = dataItem.getPeriod().getFirstMillisecond();
}
}
}
}
}
这是有问题的行为.请注意,图像 2 和 4 是在按下鼠标按钮时拍摄的.
Here is the problematic behaviour. Note that images 2 and 4 were taken while the mouse button was pressed.
- 选择几条不重叠的线 - 应该没问题
<小时>
我刚刚在调试器中查看它 - ArrayList.remove(Object o) 会删除 WRONG 元素吗?对我来说似乎不太可能...
I have just been looking at it in the debugger - could it be that ArrayList.remove(Object o) removes the WRONG element? Seems very unlikely to me...
推荐答案
您可以查看 Layer
注释被添加到其中.这里有一个示例.当然,展示您描述的问题的 sscce 将有助于澄清问题的根源.
You might look at the Layer
to which the annotation is being added. There's an example here. Naturally, an sscce that exhibits the problem you describe would help clarify the source of the problem.
附录:一个潜在的问题是您对 Comparable
与 equals()
不一致,因为后者(隐式)依赖于超类实现.与已排序的 Set
(例如 TreeSet
)一起使用需要一致的实现.您还需要覆盖 hashCode()
.Value
类就是一个例子.
Addendum: One potential problem is that your implementation of Comparable
is not consistent with equals()
, as the latter relies (implicitly) on the super-class implementation. A consistent implementation is required for use with a sorted Set
such as TreeSet
. You'll need to override hashCode()
, too. Class Value
is an example.
这篇关于Jfreechart 注释消失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!