Help about plotting two arrays as scatter plot

Dears, thank you for your time.

I have little knowledge about afl coding and programming in general, but In short I want to plot two arrays vs each other as scatter plot, but the gfx.... () functions return an error says that i have to use numbers not arrays, while when using plot () function I only can plot time series of the arrays only.
I appreciate any ideas or hints to go through the problem solving.
Thank you.

Yes, you have to access elements of array via loop iteration. Elements of an array are type number. Then you can use those elements within Gfx* functions asking for x, y values.

But instead of Gfx* functionality you may just as well use exploration XY Scatter feature saving you lots of coding time (if you don't want to add own bells and whistles).

/// Plotting scatter chart of two arrays in exploration
/// @link https://forum.amibroker.com/t/help-about-ploting-two-arrays-as-scatter-plot/6517/2
Filter = 1;

sym2 = "AAPL";

arr1 = C;
arr2 = Foreign(sym2, "C");

AddColumn( arr1, Name() );
AddColumn( arr2, sym2 );

bir = Status( "BarInRange" );

for ( i = 0; i < BarCount; i++ ) {
	if ( bir[i] ) 	XYChartAddPoint( Name() + " vs " + sym2, "", arr1[ i ], arr2[ i ] , ColorRed );
}	
XYChartSetAxis( Name() + " vs " + sym2, Name() + "[$]", sym2 + "[$]" ); 

205

9 Likes

Thank you fxshrat for your fast response that code was very helpful I made simple modification to allow it to plot my variables and it worked.

Filter = 1;
arr1 = F1;
arr2 = F2;
bir = Status( "BarInRange" );

for ( i = 0; i < BarCount; i++ ) {
	if ( bir[i] ) 	XYChartAddPoint( Name() + " F1 vs F2  ", "", arr1[ i ], arr2[ i ] , ColorRed );
}	
XYChartSetAxis( Name() + " F1 vs F2  ", "F1 ", "F2 " ); 

Unfortunately this will satisfy my objective only 50%, so I am currently working on how to use gfx functions to allow ploting from online sources with appropriate labeling of each point.

I will post the coding steps through my coding journey hoping to get your comments and assistance, Thank you

1 Like

It seems that I have to read more about gfx functions, what ever I have worked on the code supplied by fxshrat and refined it more to approximately satisfy my needs here is the final code till now

Filter = 1;
arr1 = -F1;
arr2 = -F2;
bir = Status( "BarInRange" );

for ( i = 0; i < BarCount; i++ ) {
	if ( bir[i] )/* to only take values between the range of exploration*/ XYChartAddPoint( Name() + " F1 vs F2 " + Interval(2), NumToStr(i,0, True), arr1[ i ], arr2[ i ] , ColorRed );
}	
XYChartSetAxis( Name() + " F1 vs F2 " + Interval(2), "F1 ", "F2 " ,styleLine | styleDots ); 

1111

may that help other non-professionals like me

2 Likes

Dears Can any one please help me find why i cant show any output response for this code
I have two arrays F1,F2 and I want to plot points of coordinates (F1[i], F2[i]) and connected by line to each other in simultaneous order similar to graph below.
sorry If you found the code I posted here silly as I am not familiar with programming and AFL coding.
Thank you

GfxSetOverlayMode( 1 ); 
GfxSetCoordsMode( 0 ); 
GfxSelectSolidBrush( colorRed ); 
GfxSelectPen( colorRed ); 
for ( i = 0; i <= BarCount; i++ ) 
{ 
     Color = IIf( F1[ i ] > F2[ i ], colorGreen, colorRed ); 
     GfxSelectPen( Color ); 
     GfxSelectSolidBrush( Color ); 
     GfxCircle( F1[ i ], F2[ i ], 0.2 ); 
     GfxMoveTo( F1[ i-1], F2[ i -1] ); 
     GfxLineTo( F1[ i ], F2[ i ] );  
} 

1111

Your loop is wrong.
You exceed 0 to barcount range (in addition rather iterate through visible area).
Secondly you can not use coords mode 1 if applying your x-coordinate F1. You have to use different coords mode setting (if plotting two price arrays of DB as scatter) and converting x value to pixel yourself. Also you have to create custom x axis.

Anyway below is sample output once "everything" is properly done (because out of experience people almost always want to see proof otherwise they don't believe what's been said).

9

3 Likes

@mohamed.gad some of the issues you have to face, as indicated in the @fxshrat post, are common tasks when you are working with the low-level graphics.

A careful study of this thread will provide a better understanding of the matter and some functions that probably you can reuse in your formula.

Then, the main issue that you still have to figure out is to accuratelye create the custom X axis (mapping the second price series to it).

1 Like

No, It is not main issue at all... it is just a few lines (four/five additional lines) but no rocket science. Compared to that the main issue is the rest of the code.

1 Like

Thank you @fxshrat and @beppe for your responses I will consider both of your helpfull comments and comeback again to present results if I got good ones.

Hello brothers, I have got some progress in coding of the required graph because of your valuable comments and guidance, it seems that I have have to work more on customization of x axis (but I am out of ideas or knowledge), proper labeling of the points, direction identification of successive points as time passes. In addition to imparting zooming property and easy way to control the number of points to be shown on the graph.
here is the code till now

// thanks to the gfx part code owner Beaver
function gfxPlotVLine( XPixels, Color )
{
    global pxheight;
    GfxSelectPen( Color ) ;
    GfxMoveTo( XPixels, 0 );
    GfxLineTo( XPixels, pxheight );
}

GfxSetOverlayMode( 1 ); 
GfxSetCoordsMode(0);
function GetVisualBarIndex( )
{
    lvb = Status( "lastvisiblebar" );
    fvb = Status( "firstvisiblebar" );
    bi = BarIndex();
    StaticVarSet( "NumberbarsVisible", Lvb - fvb + 1 );
    return bi - bi[ 0 ] - fvb;
}

BeginExecutionTime = GetPerformanceCounter( False );
FilePathName = GetFormulaPath();
SetChartOptions( 0, chartHideQuoteMarker );
RequestTimedRefresh( 1 );

pxwidth = Status( "pxwidth" );
pxheight = Status( "pxheight" );


Plot( F2, "", colorgreen, styleNoLabel | stylenoline ); // needed to give the min and max values
Miny = Status( "axisminy" );
Maxy = Status( "axismaxy" );
Plot( F1, "", colorgreen, styleNoLabel | stylenoline ); // needed to give the min and max values
Minx = -100; // here I know that I did something wrong but via trial and error that was the best I can as beginner  
Maxx = 100( "axismaxy" );// here I know that I did something wrong but via trial and error that was the best I can as beginner
YRange = MaxY - MinY;
VisBarIndex =  GetVisualBarIndex( );
NumBarsVisible = StaticVarGet( "NumberbarsVisible" );
// calculate conversion factors
PixelsPerBar     = pxwidth / NumBarsVisible;
PixelsPerPrice = pxHeight /    ( YRange + 10 ^ -20 );

// Plot pixel plot
GfxSelectPen( colorOrange );
FVB = Status( "firstvisiblebar" );
LVB = Status( "lastvisiblebar" );

PrevPixelY 	= ( MaxY - Ref(F2,-1) ) * PixelsPerPrice;
PixelY 		= ( MaxY - F2 ) * PixelsPerPrice;
PrevPixelX 	= (Maxx-Ref( F1,-1) )* PixelsPerBar;
PixelX 		= (Maxx-F1) * PixelsPerBar;

for( b = FVB + 1; b <= LVB AND b < BarCount; b++ )
{
    GfxCircle(PixelX[b], PixelY[b],3);
    GfxTextOut(NumToStr(F1[b],0),PixelX[b], PixelY[b]);
    GfxMoveTo( prevPixelX[b], prevPixelY[b] );
    GfxLineTo( PixelX[b], Pixely[b] );  

Thank you @fxshrat , @beppe and I am waiting for yous ideas and guidance to complete the code where I believe that the most important part is to custom x axis and impart zooming properties.

her is the output graph
1112

@mohamed.gad in addition to the .useful tips that you'll find studying the notes that @fxshrat put in his image, here are some additional hints.

For the MinX and MaxX you should ignore the number of bars: here you are dealing with a price range like you are doing in the Y-axis, and as such, they correspond to the LowestVisibleValue()/HighestVisibleValue() of the second series array.

Then, your "pixelPerBar" (the value that will be used to calculate the x coordinates of each data x/y point) is no longer based on the number of visible bars, but derived from pxWidth / (MaxX - MinX).

More in general, I suggest you to simplify your code deleting unneeded functions, like removing completely the lines drawing and text logic.

Initially, you should focus on plotting the small circles in the correct positions, and ensure that when you are zooming or panning the chart your scatter plot still works correctly.
(Then attempt to display the custom x-axis scale).

When all the x,y calculations are in place, you may want to work on additional bells and whistles, like plotting some text labels (to avoid too much data you can do it only for certain dates, like for instance the first trading date of each month), coloring some points differently, add a vertical and horizontal lines crossing at the last available value, connecting points with lines, etcetera, and finally calculate and plot a linear regression line based on all the visible data points.

For sure you have a lot to work on!

1 Like

@beppe Thank you for your time and helpful notes. Sure I will work more and comeback to present what I got. for now I got fixed x axis according to your instruction but I cant understand your sentence

is that differ from fixing the conversion of x-axis to pixels as it was not correct in the previous submitted code or you mean other thing.

Whatever, I have fixed all points you mentioned before and according to my best knowledge I think that every thing is alright regarding points positioning. Please review the next modified code and guide me through customizing x-axis scale as I have no idea about display x-axis on the graph or even control zooming through it.

function GetVisualBarIndex( )
{
    lvb = Status( "lastvisiblebar" );
    fvb = Status( "firstvisiblebar" );
    bi = BarIndex();
    StaticVarSet( "NumberbarsVisible", Lvb - fvb + 1 );
    return bi - bi[ 0 ] - fvb;
}
pxwidth = Status( "pxwidth" );
pxheight = Status( "pxheight" );
Plot( F2, "", colorgreen, styleNoLabel | stylenoline ); // needed to give the min and max values
Miny = Status( "axisminy" );
Maxy = Status( "axismaxy" );
Minx = LowestVisibleValue(F1);
Maxx = HighestVisibleValue(F1);
YRange = MaxY - MinY;
Xrange = MaxX - MinX;
VisBarIndex =  GetVisualBarIndex( );
NumBarsVisible = StaticVarGet( "NumberbarsVisible" );
// calculate conversion factors
PixelsPerBar= pxWidth /Xrange ;
PixelsPerPrice = pxHeight /( YRange + 10 ^ -20 );
// Plot pixel plot
GfxSelectPen( colorwhite );
FVB = Status( "firstvisiblebar" );
LVB = Status( "lastvisiblebar" );
PrevPixelY 	= ( MaxY - Ref(F2,-1) ) * PixelsPerPrice;
PixelY 		= ( MaxY - F2 ) * PixelsPerPrice;
PrevPixelX 	= (Maxx-Ref( F1,-1) )* PixelsPerBar;
PixelX 		= (Maxx-F1) * PixelsPerBar;
for( b = FVB + 1; b <= LVB AND b < BarCount; b++ )
{
    If(b>=(BarCount-13) or b==(BarCount-1) )
    {GfxSelectSolidBrush(ColorHSB(255,255,255)) AND GfxTextOut("xx",PixelX[b], PixelY[b]);}else GfxSelectSolidBrush(colorGreen);
    GfxCircle(PixelX[b], PixelY[b],5);
    GfxMoveTo( prevPixelX[b], prevPixelY[b] );
    GfxLineTo( PixelX[b], Pixely[b] );
} 

@mohamed.gad, some observations.

At first sight, something seemed wrong to me: if I plot recent data for SPY vs. QQQ I expect to see the scatter points in an uptrend from lower left corner to the upper right one. But maybe you actually prefer to see them as you have done in your code (a parameter to choose the way it is presented would be a nice touch).

Your plot also overlaps the Y-axis; to avoid it you should use:

// pxwidth = Status( "pxwidth" ); // pane width
pxWidth = Status( "pxchartwidth" ); // chart width excluding Y axis area

Additionally, one of the lines you removed from your original code is still needed to properly refresh the chart when the Y-scale changes (panning the chart), if you are working with GfxSetCoordsMode(0), that is the default mode.

Add to the end of the formula:

RequestTimedRefresh( 0.25 ); 

(to set it lower than a second you need to enable it in the registry).

As an alternative, as was suggested by @fxshrat, maybe you want to experiment a bit using GfxSetCoordsMode(2); as a side effect this mode will also automatically resize/scale your plot circles when zooming.

Re the custom X-axis, here are some hints for a possible approach.

As a first step, you have to figure out the appropriate scale price unit (personally I select it from 0.05, 0.25, 0.50, 1, 2.5, 5, 10, 25, 50, 100).
You can derive it evaluating how large is pxWidth versus the width of the largest single price text representation (add some extra space to ensure that numbers are sufficiently spaced apart). The GfxGetTextWidth() will be useful in this case (use it sparingly since it is slow).

For instance, here are 3 different stocks custom X-axes:

CECE
immagine
INTL:
immagine
AMZN:
immagine

Then, to actually plot the axis simply use a loop calculating the coordinates for the GfxTextOut( priceStr, x, y) function, starting with the x coordinate corresponding to the first price that is a multiple of the scale unit price, then increasing it by the such unit until you reach the maximum price in your range.
Obviously, the y coordinates in this loop are always the same.
(If you want to keep your plot as per your posted code, then apply the logic accordingly to the direction of your prices).

You can improve the X-axis appearance by adding the small vertical lines corresponding to each x point and centering the text around it. Skip also any text that will be clipped at left or may overwrite the Y-axis.

To begin experimenting you can simply start setting your X-axis price "unit" at 1.00 and try to do the loop from Floor(x min visible price) to Ceil(x max visible price).
In such a case you need to figure out how to avoid overlapping prices in the X-axis (skip them). When you have the basic loop working, try to do it properly using a pre-calculated price unit "correctly sized".

Work on it until you get it right. Happy coding!

4 Likes

@beppe @fxshrat Thank you for your guidance and support since you both pushed me up toward solving my coding shortage. As a beginner It was impossible objective :cold_sweat: to code such complex script using AFL so I googled for long time first until I got here and presented my problem. I thought any body will send me a code of similar functionality which I will only modify it to meet my own requirements. " I never learned programming before except for my own passion and depending on watch and learn then practice principal without essential mastering of even basic programming skills" Now after I have coded my AFL script I would like to thank both of you for your guidance and support. :loudspeaker: You pushed me to learn something new and to remember that impossible is nothing.:grin::grin:
Sure there some issues I did not completed but from effort and result point of view I did not spent a lot of time developing those issues since the current graph satisfies my minimum requirements, hopefully in future I will complete them.

Here is a the graph

3333

4 Likes

Hello dears @beppe , @fxshrat Sorry for interruption but the code you both helped me to develop provided a very interesting prospective toward my analytical vision :zap: and it was astonishing to me :astonished:, I have little question about execution time of the code I have developed " In a nut shell one of the graphs I constructed was RRG graph to plot about 30 ticker" I used two loops inside each other one for changing the ticker the other for plotting the scatter-plot " but the execution time is very high 2000-900 ms is that normal for such code or I can still have the possibility to reduce execution time via modifying the coding steps, if last case is write please guide me through the way as I ran out of ideas " remember I am just a beginner":relieved:
:tulip: :tulip: :tulip: :tulip: :tulip: :tulip::tulip: :tulip::tulip: :tulip:
:tulip::tulip::tulip:Thank you again :tulip::tulip::tulip:
:tulip: :tulip: :tulip: :tulip: :tulip: :tulip::tulip: :tulip::tulip: :tulip:

@mohamed.gad I never coded a Relative Rotation Graph (RRG)1, and AFAIK the exact formula to do it is not available since it uses two proprietary indicators by Julius de Kempenaer.

On the other hand, some time ago I saw some images in which @fxshrat did something visually similar, using other indicators, so he is a lot more qualified than me to provide any feedback on the matter.

In any case, I suspect that something is wrong in your logic since the time you reported seem excessive to plot 30 data points (also adding a right amount of "gfx" functions to draw the quadrants and some labels).
But for me, it is impossible to provide any help to fix your code without seeing it!

1) These are registered trademarks of RRG Research.

2 Likes

Hi @mohamed.gad
Could you please guide how you plotted the above chart

Hi @mohamed.gad
I am also working on RRG on Amibroker. It took me quite a while, but I haven't gotten any significant results yet. Can you share with me about your experiences and results?
Thanks advance!

1 Like

Can you share with me about your experiences and results?

@fxshrat if y-axis value is price and x-axis value is custom (or pixel), how to plot custom x value?

I use GfxSetCoordsMode( 2 );

please advise