ASE Home Page Products Download Purchase Support About ASE
ChartDirector Support
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  Trendlines
Posted by Alden on Jun-13-2011 19:06
Hi Peter,

I am having some problems drawing trendlines on my charts in Java.

Am I implementing this correctly as the code below is not drawing any lines?:

Point startpt, endpt;

viewer.addMouseListener(new MouseAdapter(){
            @Override
                public void mousePressed(MouseEvent e) {
                    startpt = new Point(e.getX(), e.getY());
                    endpt = startpt;
                }
            });
viewer.addMouseMotionListener(new MouseAdapter(){
            @Override
                public void mouseMoved(MouseEvent e){

                        endpt = new Point(e.getX(), e.getY());
                        xyChart.addLine(startpt.x, startpt.y, endpt.x, endpt.y, RGBColor);

               }

No lines appear on the chart. Also, how would I get the line to follow the mouse
dynamically and draw a final line once I click the mouse again?

Regards,
Alden

  Re: Trendlines
Posted by Peter Kwan on Jun-14-2011 00:45
Hi Alden,

ChartDirector is designed to draw charts from data.

There is another kind of drawing called "interactive drawing". It is like drawing in Windows Paint or Photoshop. The user uses a mouse to drag a line or add other things on an image. For your case, you seem to want to perform interactive drawing.

For interactive drawing, it is suggested you draw on top of the chart, not modifying the chart. As an example, a mouse cursor is something that can be on top of the chart. (You can put the mouse cursor on top of the chart.) But the mouse cursor is not part of the chart. When the mouse cursor moves, the chart does not need to change. Interactive drawing should be handled in a similar way.

If you use ChartDirector addLine (it is possible to make it work), you cannot "undraw" the line after adding it without recreating a new XYChart object. So as the user is dragging the mouse, you will add multiple lines as the mouse is moving. But what you probably want is to undraw the previous line, and redraw a new line as the mouse is dragging.

So instead of using ChartDirector addLine, you should just use the standard Java drawing method and functions to draw the line. See:

http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/JComponent.html#paintComponent(java.awt.Graphics)

http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Graphics.html

Hope this can help.

Regards
Peter Kwan

  Re: Trendlines
Posted by Alden on Jun-14-2011 05:23
Hi Peter,

Thanks for the reply, I was heading in the direction you've suggested.

Would I need to add a glass pane to draw on top of the chart. Or could the viewport
window be used as a container to draw on?

Regards,
Alden

  Re: Trendlines
Posted by Alden on Jun-14-2011 21:53
.... also, the drawing will need to scroll/zoom as I update the chart in the viewport.

  Re: Trendlines
Posted by Peter Kwan on Jun-15-2011 00:22
Hi Alden,

You may draw on a glass pane or on the ChartViewer control (by overriding the Java paintComponent method). It is up to you.

When the chart zoom/scroll, ChartDirector will inform you the new viewport setting. Your code can then compute the updated positions of your lines and draw them accordingly.

Hope this can help.

Regards
Peter Kwan

  Re: Trendlines
Posted by Alden on Dec-27-2012 03:49
Hi Peter,

I've been trying to override the paintComponent method on the chart director control, but
the it doesn't seem to get called on repaint, or the lines are actually drawn UNDER the
chart viewer component:

Here are a few lines of my overridden method:

Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1));

for (Line2D.Double l : trendlines) {
     g2.setPaint(trendlineColor);
     g2.draw(l);
}

My Chartdirector control is added to the content pane of a JInternalFrame and displayed. If
I call the method directly passing in viewer.getGraphics() as argument, I do get lines
drawn, but it's not working as it should.

Please help!
Regards,
Alden

  Re: Trendlines
Posted by Peter Kwan on Dec-28-2012 01:59
Hi Alden,

I have just created a ChartViewer2 to override the paintComponent method of the ChartViewer, and use ChartViewer2 instead of ChartViewer in the same code, and it works normally in my case. The ChartViewer2 I use is:

class ChartViewer2 extends ChartViewer
{
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.setColor(Color.BLUE);
        g.drawRect(0, 0, 100, 100);
    }
}

To test it, use any sample code that comes with ChartDirector (such as the "Simple Bar Chart" sample code), replace "new ChartViewer()" with "new ChartViewer2()", and run the sample code. The chart should contain a blue square at the top-left corner in the foreground.

Hope this can help.

Regards
Peter Kwan

  Re: Trendlines
Posted by Alden on Jan-07-2013 20:57
Thanks Peter, that works fine.

Now I can get a point on the screen using getXCoor(value) and getYCoor(value) using
interpolation and I know how to use the ViewPortChangedEvent to listen for changes, but I
don't understand how to calculate the new point once coordinates change due to
zooming/scrolling.

For example, if the initial point is x=42 and y=175 or (42,175) on the screen,  how do I
calculate the new point for those chart values after zooming/scrolling the chart?

Any help appreciated!

Regards,
Alden.

  Re: Trendlines
Posted by Peter Kwan on Jan-08-2013 01:15
Hi Alden,

If my understanding is correct, your screen x-coordinate and y-coordinate comes from some x-value and y-value using getXCoor(xValue) and getYCoor(yValue).

If the coordinate changes due to zooming or scrolling, depending on the axis type you are using, you may just recompute the new screen x-coordinate and y-coordinate using the same method getXCoor(xValue) and getYCoor(yValue). This works as long as the axes are true date/time or numeric.

In case you are drawing a FinanceChart, note that in a financial chart, the x-coordinates are trading sessions, not "true date/time", so a slightly different method has to be used. (The date/time show on the x-axis are trading dates, which are a little bit random and unpredictable. They are treated as names for human reading only. They are not needed to plot the chart or to compute any standard financial indicators.)

Hope this can help.

Regards
Peter Kwan

  Re: Trendlines
Posted by Alden on Jan-08-2013 02:52
Hi Peter,

Thanks for the reply.

You are misunderstanding my question. What I want to know is the following: I have a
point drawn on the chart, and want to know how to calculate where the point would be on
the screen (ie where it has moved to) after zooming/scrolling the chart? This is so that I
can redraw the trend lines referred to previously.

It is a finance chart (XYChart) that I am using.

Cheers,
Alden

  Re: Trendlines
Posted by Peter Kwan on Jan-09-2013 02:49
Hi Alden,

I assume your code knows the pixel (x, y) coordinates of the point relative to the chart. In this case, you can use XYChart.getXValue and XYChart.getYValue to obtain the x and y data values of the point.

After zooming or scrolling, the x-axis and y-axis will have change. You can then use getXCoor and getYCoor to determine the new pixel coordinate based on the x and y data values.

For a FinanceChart, as mentioned in my previous message, the x-data value should be trading session number, which is equivalent to the array index 0, 1, 2, 3, ..... Suppose your data has 10000 trading sessions. So the full x-range is 0 to 9999.

//initialize the view port full range
viewer.setFullRange("x", 0, timeStamps.length - 1);

When the chart is to be drawn, first, obtain the required data:

//Get the start date and end date that are visible on the chart.
int startIndex = (int)Math.floor(viewer.getValueAtViewPort("x", viewer.getViewPortLeft()));
int endIndex = (int)Math.ceil(viewer.getValueAtViewPort("x", viewer.getViewPortLeft() +
            viewer.getViewPortWidth()));

//To compute moving averages starting from the first day, we need to get extra data points before the first day
int extraDays = Math.min(30, startIndex);
startIndex -= extraDays

int noOfPoints = endIndex - startIndex + 1;

//Extract the part of the data array that are visible and use them to draw charts
double[] viewPortTimeStamps = (double[])Chart.arraySlice(timeStamps, startIndex, noOfPoints);
double[] viewPortHighData = (double[])Chart.arraySlice(highData, startIndex, noOfPoints);
double[] viewPortLowData = (double[])Chart.arraySlice(lowData, startIndex, noOfPoints);
double[] viewPortOpenData = (double[])Chart.arraySlice(openData, startIndex, noOfPoints);
double[] viewPortCloseData = (double[])Chart.arraySlice(closeData, startIndex, noOfPoints);
double[] viewPortVolData = (double[])Chart.arraySlice(volData, startIndex, noOfPoints);


Now when your plot a point on the chart using the pixel coordinate, the value obtained using XYChart.getXValue is the array index of the viewPortTimeStamps. You need to add startIndex + extraDays to obtain the array index of your original timeStamps array. After zooming and scrolling, you may perform the reverse computation to obtain the new pixel coordinates.

Hope this can help.

Regards
Peter Kwan

  Re: Trendlines
Posted by Alden on Jan-11-2013 07:12
Hi Peter,

I'm almost there now ... i'm just still struggling to get the updated x value after
zooming/scrolling. Getting the updated y value is fairly straightforward.

I save the initial start x,y and end x,y for the line and then update them after
zooming/scrolling with the following:

int new_start_x_point = xy.getXCoor(initial_XValue - startIndex);
int new_start_y_point = xy.getYCoor(yvalue1);
int new_end_x_point = xy.getXCoor(initial_endXValue - startIndex);
int new_end_y_point = xy.getYCoor(yvalue2);

It works OK until I move the end of the viewport ranges, and then weird things starts to
happen.

Where am I going wrong?

Alden

  Re: Trendlines
Posted by Peter Kwan on Jan-12-2013 03:06
Hi Alden,

Would you mind to clarify what you mean by "It works OK until I move the end of the viewport ranges"? In particular, what does "move the end of the viewport ranges" mean? This may be an important clue as to the cause of the problem.

Since your code does not have extraPoints, I assume you are always using 0 as the extraPoints.

Note that startIndex should be different after zooming and scrolling. You would need to use the startIndex computed after zooming and scrolling to get the new coordinates.

The code also assumes the original arrays (timeStamps, highData, lowData, ...) does not change, that is, timeStamp[aaa] is always the same value as long as aaa is the same value.

The idea of the code is as follows:

(a) From the screen coordinates, obtain something that does not change by scrolling or zooming. For the y dimension, the code changes the y screen coordinates to the y-axis value (the price). After scrolling or zooming, we can obtain the new screen coordinates based on the price.

(b) For the x-axis, the array index of the original arrays are used. It is assumed the original arrays will not change, so the same index is always pointing to the same date.

To diagnose the problem, you may set a break point to examine the initial_XValue and timeStamps[initial_XValue] and viewPortTimeStamps[new_start_x_point] to see if it is really the date of the point. Note that new_start_x_point can become negative or larger than the size of viewPortTimeStamps. This just means the point is outside the plot area.

Hope this can help.

Regards
Peter Kwan

  Re: Trendlines
Posted by Alden on Mar-04-2013 19:29
Hi Peter,

I'm having trouble redrawing lines which are drawn on the indicator window below the
main price chart, during zoom and/or scroll. My chart is set to autoscale the Y-Axis.
So when the main chart y-axis autoscrolls, it misplaces lines drawn on the indicator boxes
below. I'm clearly not calculating the new YValues correctly on the indicator boxes.

note: the original lines are drawn and values saved set using xy.getYValue on the entire
chart drawing.

How do I get the correct y-values for lines drawn on the INDICATOR box below the main
price chart, so they can be redrawn after zoom/scroll?

Cheers,
Alden

  Re: Trendlines
Posted by Peter Kwan on Mar-05-2013 00:04
Hi Alden,

Since you are referring to the indicator chart, in your xy.getYValue, I assume "xy" refers to the indicator chart (not to the main price chart). In this case, any change in the scale in the main price chart should not affect the indicator chart. Is the "xy" refers to the indicator chart or the main price chart?

Regards
Peter Kwan

  Re: Trendlines
Posted by Alden on Mar-05-2013 00:22
Hi Peter,

As I said above the y-values are calculated on the main price chart, which is obviously
incorrect. I use xy.getYValue(coords) to get the y-value on the price chart. How do I get
the y-value from the indicator drawing, NOT the price chart (ie the values we see on the
image map?)?

Regards,
Alden

  Re: Trendlines
Posted by Peter Kwan on Mar-05-2013 23:29
Hi Alden,

If "xy" refers to the indicator chart, then the y-value will be relative to the indicator chart.

XYChart aaa = c.addMainChart(240);

XYChart bbb = c.addRSI(75, 14, 0x800080, 20, 0xff0000, 0x0000ff);

If you use aaa.getYValue, then it is using the y-axis of the main price chart, and is appropriate if you are measuring things on the main price chart. If you use bbb.getYValue, then it is using the y-axis of the RSI indicator chart, and is appropriate if you are measuring things on the RSI indicator chart.

Note that no matter you are drawing the line on the main price chart or indicator chart, when using ChartDirector API, all pixel coordinates used should be relative to the XYChart you are drawing to.

If you are using mouse coordinates obtained from Java, they are relative to the combined FinanceChart. With the exception of the first chart in the FinanceChart (which I assume to be the main price chart in your case), all other charts are vertically offseted from the top of the FinanceChart. So to obtain the pixel coordinates relative to the indicator chart from the mouse pixel coordinates, you would need to subtract the offset. The offset can be obtained using BaseChart.getAbsOffsetY. For example:

double yValue = bbb.getYValue(myMouseYCoordinate - bbb.getAbsOffsetY());

Conversely, if you would like to obtain the Java pixel coordinate from the XYChart pixel coordinate, you need to add the offset, like:

int yCoor = bbb.getYCoor(yValue) + bbb.getAbsOffsetY();

Hope this can help.

Regards
Peter Kwan