Jfreechart注释消失

2023-12-03

我用 JFreechart 绘制了一条曲线。然后用户可以通过拖动鼠标来绘制范围。我使用 AbstractChartAnnotation 绘制这些图来绘制填充的 Path2D。到目前为止一切都很好 - 一切都与曲线完美对齐。

当某个区域已被注释时,新注释将被删除。我用XYPlot.removeAnnotation与新的注释。

我的问题是,有时不仅“新”注释被删除,而且图中其他地方的第二个注释也被删除。这似乎不是随机的 - 我发现“右侧”的注释更容易发生这种情况。

我很困惑是什么导致了这种情况。绘制/删除新注释的对象每次都会恢复,并且只保存当前注释 - 那么如何删除其他注释呢?

非常感谢任何提示,谢谢。


按照建议,我准备了一个 sscce 示例。不幸的是它并不太短。

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 是在按下鼠标按钮时拍摄的。

  1. select a few non-overlapping lines - no problem as it should be select a few non-overlapping lines enter image description here enter image description here enter image description here enter image description here

我刚刚在调试器中查看它 - ArrayList.remove(Object o) 是否删除了错误的元素?对我来说似乎不太可能......


你可能会看看Layer正在向其添加注释。有一个例子here。自然地,一个sscce显示您所描述的问题将有助于澄清问题的根源。

附录:一个潜在的问题是您的实施Comparable is not是一致的equals(),因为后者(隐式)依赖于超类实现。与排序一起使用需要一致的实现Set例如TreeSet。你需要覆盖hashCode(), 也。班级Value就是一个例子。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jfreechart注释消失 的相关文章

随机推荐

  • 如何为 T-SQL 选择中的每一行生成随机数?

    我的表中的每一行都需要一个不同的随机数 以下看似显而易见的代码对每一行使用相同的随机值 SELECT table name RAND magic number FROM information schema tables 我想从中得到一个
  • Outlook 互操作异常

    尝试将 Outlook 自动化为 Microsoft Office Interop Outlook Application myApp new Microsoft Office Interop Outlook ApplicationClas
  • 寻找关键的最大价值

    我想找出面积最大的国家 我的数据集如下 Afghanistan 648 Albania 29 Algeria 2388 Andorra 0 Austria 84 Bahrain 1 Bangladesh 143 Belgium 31 Ben
  • 更改模型: 由 keras 在 model.summary() 输出中自动给出

    调用命令时 print model summary 我得到以下输出 如何重命名由 Keras 自动生成的突出显示字段 预先感谢您的帮助 有参数 名称 以函数格式 inp Input 10 out Dense 1 inp m Model in
  • 如何将多张图像合并为一张?

    我有几个图像 第三方 例如设置 mysql 设置通用 php 应用程序环境 设置第三方工具 我想制作一个 Dockerfile Docker Image 来组合这两个图像 然后运行更多命令 imageA imageV gt sharedIm
  • 封装在JavaScript中,存在吗?

    我有使用 C 编程语言的经验 但现在我还必须使用 JS 它对我来说相当新 我尝试用 JS 开发一个简单的类模拟 如下所示 http jsfiddle net T74Zm function A inputValue this Init inp
  • 如何让 rake 任务在 dev 以外的环境中运行?

    我有一台具有特殊 暂存 环境的暂存机 我总是忘记在该机器上运行 rake 任务 例如 rake jobs work RAILS ENV staging 所以我最终做了 rake jobs work 然后我很困惑为什么我的数据库中没有任何变化
  • pygame中.quit和.QUIT有什么区别

    我只是想知道之间的区别 quit and QUIT在 pygame 我已经测试了两者 但我仍然不明白它们是如何工作的 QUIT是事件类型的枚举常量 参见event模块 quit 事件在 pygame 窗口关闭时发生 for event in
  • Google App Engine python 入站邮件 LookupError:未知编码

    我按照示例使用 标准 入站邮件处理程序接收发送到我的 Google App Engine 应用程序的入站电子邮件在文档中 似乎发送到应用程序的某封电子邮件 不是由我发送 导致电子邮件 api 抛出 LookupError 未知编码异常 请参
  • 使用 jQuery 在浏览器调整大小时更改图像 src

    我有两张不同尺寸的图像 一张适用于小于 759px 的屏幕 另一张适用于大于 759px 的屏幕 我已经设法在文档加载时根据窗口宽度更改图像的来源 但我真的希望能够在调整浏览器大小时执行此操作 但在我的一生中 我无法让它执行此操作 它似乎只
  • 图像处理以去除线条

    我试图最终得到一张只有文本的图像 我的代码会将此图像视为灰度 并从中删除所有长线以及除文本 符号 测量值之外的所有内容 Is this something that can be accomplished using image proce
  • 如何从Oracle SQL中的字符开头删除定义的值?

    我在 Oracle SQL 中有如下表 col1 ABC 1234 ABC 55674 ABC 11 所以我在 col1 中有 总是 ABC 在每个值的开头 ABC 后不同长度的值 我需要如下结果 所以我需要删除 ABC 从每个值的开头 c
  • Pyparsing:获取结果名称中的标记位置

    我正在开发一个使用 pyparsing 解析命令行的程序 它使用 readline 库来提供命令编辑和完成 在应用程序的上下文中 有效的命令行是path 可选 然后是命令名称 可选 和一些参数 也是可选的 为了提供命令完成 应用程序解析命令
  • htmlspecialchars 和 mysql_real_escape_string 是否可以保护我的 PHP 代码免受注入?

    今天早些时候有人问了一个关于Web 应用程序中的输入验证策略 在撰写本文时 最佳答案建议PHP只是使用htmlspecialchars and mysql real escape string 我的问题是 这总是足够的吗 还有更多我们应该知
  • 如何从数组中删除所有数字?

    我正在尝试从数组中删除所有数字 该循环完全按照我想要的方式工作 但 splice 方法仍然由于某种原因跳过一些元素 let arr 1 2 3 4 5 notanumber 6 for let element of arr let inde
  • 使用 python os.rename 时出现错误 [183]

    这是我第一次使用 python 我一直遇到错误 183 我创建的脚本在网络中搜索所有 py 文件并将它们复制到我的备份驱动器 请不要嘲笑我的剧本 因为这是我的第一个剧本 我在脚本中做错了什么有什么线索吗 import os import s
  • 防止 ansible 在通过 with_items 传递时解析字符串

    我正在尝试使用with items指定要传递给自定义 ansible 模块的键 值对列表 当键或值字符串具有类似列表的格式时 就会出现问题 例如 a b c d 在这种情况下with items大概将字符串转换为列表并对我的配置造成严重破坏
  • 为什么不从 Enum> 扩展

    我偶然发现了以下问题 我无法从 Java 1 5 java lang 包 中定义的此类扩展和实现 public abstract class Enum
  • Pandas 到 timedelta 只有小时、分钟和秒

    在我的脚本中 我提取了一个 Excel 其中名为 Time 的列是 dtype 对象 该列中有一个像 14 00 00 这样的小时 我想将该列转换为 datetime 但是当我这样做时 df Time pandas to datetime
  • Jfreechart注释消失

    我用 JFreechart 绘制了一条曲线 然后用户可以通过拖动鼠标来绘制范围 我使用 AbstractChartAnnotation 绘制这些图来绘制填充的 Path2D 到目前为止一切都很好 一切都与曲线完美对齐 当某个区域已被注释时