简体   繁体   English

用户在Java中的时间序列数据中选择的标记

[英]User-selected marker in time series data in Java

My code plots 5000 points of time series data in a panel that is 581 pixels wide by default, but this width changes when the user resizes the window. 我的代码在默认为581像素宽的面板中绘制了5000点的时间序列数据,但是当用户调整窗口大小时,该宽度会改变。 My code also plots several rectangular markers that each identify a local maximum/peak in this same space. 我的代码还绘制了几个矩形标记,每个标记都标识了同一空间中的局部最大值/峰值。

I need to enable the user to right click on any of the rectangular-peak-markers so that the user can manually delete any false peak. 我需要使用户能够右键单击任何一个矩形峰标记,以便用户可以手动删除任何错误的峰。 The problem is that my code is reporting different x-coordinates than expected when the user right-clicks on a peak-marker. 问题是,当用户右键单击峰标记时,我的代码报告的x坐标与预期不同。 I suspect that the reason may have to do with rounding error in converting from 581 x-pixels back to 5000 data indices. 我怀疑原因可能与将581个x像素转换回5000个数据索引时的舍入误差有关。 But I am not certain of the reason. 但我不确定原因。

Can anyone suggest a solution that enables my users to manually select one of the above-described peak markers by right-clicking on it? 谁能建议一种解决方案,使我的用户通过右键单击它来手动选择上述峰标记之一?

I am enclosing relevant sections of the code below. 我附上下面代码的相关部分。 My actual code is very, very long, and too complicated to post. 我的实际代码非常非常长,发布起来太复杂。 But the relevant portions below should be enough for someone to see the logic of my approach, and to then suggest a more effective approach. 但是下面的相关部分应该足以使别人看到我的方法的逻辑,然后提出一种更有效的方法。

The code that declares the class in question is: 声明相关类的代码是:

class SineDraw extends JPanel implements MouseMotionListener, MouseListener {
// lots of code, including the two segments excerpted below
}

This segment of code overloads the paintComponent of the JPanel so that my data is plotted: 这部分代码使JPanel的paintComponent重载,以便绘制我的数据:

// declare some variables
ArrayList<Double> PeakList = new ArrayList<Double>()  // this ArrayList is populated by an extraneous process
visiblePoints = 5000
hstep = getWidth()/visiblePoints //=581/5000 by default, but will change when user resizes window
int numPeaks = PeakList.size();

// scale (y-coordinate) data relative to height of panel
pts = new double[visiblePoints]
for (int i = 0; i < pts.length-1; i++){pts[i]=//data vertical scaled to fill panel;}

// plot the 5000 time-series-data-points within the 581 pixels in x-axis
for (int i = 1; i < visiblePoints; i++) {
    int x1 = (int) ((i - 1) * hstep);
    int x2 = (int) (i * hstep);
    int y1 = (int)pts[i - 1];
    int y2 = (int)pts[i];
    g2.drawLine(x1, y1, x2, y2);
}

// plot a rectangle for each of the local peaks
for(int m=0;m<=(numPeaks-1);m++){
    if(i==(int)(PeakList.get(m)){
        int currentVal = (int)pts[(int)(PeakList.get(m)];
        g2.drawRect((int)(PeakList.get(m), currentVal, 6, 6);
    }
}

This section of code is for handling the right-clicking of the mouse: 此部分代码用于处理鼠标的右键单击:

public void mousePressed(MouseEvent e){
    // check to see if right mouse button was clicked
    boolean jones = (e.getModifiers()&InputEvent.BUTTON3_MASK)==InputEvent.BUTTON3_MASK;
    if(jones==true){
        // test the value returned as x-coordinate when user right-clicks (code always underestimates x-coordinate of local peaks by this test)
        double ReverseHstep = visiblePoints/getWidth();
        int getX_ConvertedTo_i = (int) (e.getX()*ReverseHstep);
        System.out.println("getX_ConvertedTo_i is:  "+getX_ConvertedTo_i );

        // check to see if peaklist contains a value within the x-coordinates of the user-selected-rectangle
        if(PeakList.contains((double)(e.getX()-3))
                ||PeakList.contains((double)(e.getX()-2))
                ||PeakList.contains((double)(e.getX()-1))
                ||PeakList.contains((double)(e.getX()))
                ||PeakList.contains((double)(e.getX()+1))
                ||PeakList.contains((double)(e.getX()+2))
                ||PeakList.contains((double)(e.getX()+3))
                ){
                // handling code will go here, but for now it is a print test that never succeeds because x-coordinate is always underestimated
                System.out.println("You just selected a peak!");
        }
        }
    repaint();
    }

I suggest you create objects (in this case Rectangles ) for each thing you want to be clickable. 我建议您为要单击的每件事创建对象(在本例中为Rectangles )。 Here is an over-simplified example of how you can make something you draw clickable. 这是一个简化的示例,说明如何使绘制的内容可点击。 The key thing to take away from this is the mouseClicked method which will display a dialog only if the mouse clicked within the rectangle. 要避免的关键是mouseClicked方法,该方法在鼠标在矩形内单击时才会显示对话框。

One tricky point is that I wasn't able to figure out how to make the rectangle filled in with color without drawing another rectangle over it. 棘手的一点是,如果不在其上绘制另一个矩形,就无法弄清楚如何用颜色填充矩形。 I'll leave that one for you ;-) 我会把那个留给你;-)

public class Canvas extends JPanel implements MouseListener{
    private Rectangle rect = new Rectangle(100,100);

    public Canvas(){
        this.addMouseListener(this);
        rect.setSize(100, 100);
    }

    @Override
    public void paintComponent(Graphics g){
        g.setClip(rect);
        g.setColor(Color.RED);
        g.fillRect(0, 0, 100, 100);
    }

    @Override
    public void mouseClicked(MouseEvent e){
        if(rect.contains(e.getPoint())){
            JOptionPane.showConfirmDialog(this, "Click!");
        }
    }

    // The rest of the MouseListener methods have been cut out

    public static void main(String[] a){
        JFrame frame = new JFrame("Canvas Thingy");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(0, 0, 300, 300);
        frame.add(new Canvas());
        frame.setVisible(true);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM