2011-08-08 36 views
0

我的代码在面板中绘制了5000个时间序列数据点,默认宽度为581像素,但当用户调整窗口大小时,宽度会发生变化。我的代码还绘制了几个矩形标记,每个标记在相同的空间中标识一个局部最大值/峰值。Java中时间序列数据中用户选择的标记

我需要让用户右键单击任何矩形峰标记,以便用户可以手动删除任何假峰。问题在于,当用户右键单击峰标记时,我的代码报告的x坐标不同于预期值。我怀疑这个原因可能与将581个x像素转换回5000个数据索引时的舍入误差有关。但我不确定原因。

任何人都可以提出一个解决方案,使我的用户可以通过右键单击来手动选择上述峰值标记之一吗?

我附上下面的代码的相关部分。我的实际代码非常非常长,而且太复杂,无法发布。但是下面的相关部分应该足以让某人看到我的方法的逻辑,然后提出一个更有效的方法。

声明所涉及的类的代码是:

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

此代码段重载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); 
    } 
} 

这部分代码是用于处理鼠标右击:

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(); 
    } 
+0

我一直在测试这个,我通过右键单击获得的x坐标分别在相应的期望值的92.7%和93.8%之间PeakList ArrayList中的峰值。这说明问题可能是由于系统舍入误差。 – CodeMed

+1

你绘制了多少个矩形?如果不是太多,你可能会使每个矩形成为一个单独的对象,让他们监听点击事件。那么它在哪里绘制就没有关系了。 – Jeremy

+0

我有大约300万个数据点,其中可能有3500个本地峰值,每个峰值都需要自己的矩形。在任何给定时刻,JPanel中只绘制了5000个数据点,并且在该5000数据点窗口中可能有5到15个本地峰值,但面板底部有一个滚动条,允许用户滚动3个百万个数据点查看所有3500个峰值。 JPanel在用户使用滚动条时重新绘制。 – CodeMed

回答

1

我建议你创建对象(在这种情况下Rectangles)你想要点击每件事情。这里是一个过度简化的例子,说明如何让你绘制可点击的东西。关键是要采取的方法是mouseClicked方法,如果鼠标在矩形内单击,将显示对话框只有

一个棘手的问题是,我无法弄清楚如何用颜色填充矩形而不用在其上绘制另一个矩形。我会离开那一个给你;-)

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); 
    } 
} 
+0

谢谢。看起来我必须为我想要点击的时间序列数据上的每个标记创建一个单独的JPanel。 (5到15个小标记面板,每个放置在更大的数据面板上,我的5000个数据点也被绘制出来)。我这样说是因为,当我尝试更改代码以扩展Rectangle而不是扩展JPanel时,会收到错误消息告诉我Rectangle不支持相关的方法。 – CodeMed

+0

我暗示你的Canvas可能有一个矩形列表。 – Jeremy

+0

我现在正在处理这个问题,随着我进一步研究,可能会有更多的意见/问题。 – CodeMed

相关问题