# Drawing arrows with an absolute size

Hi,

I’d like to draw a graph containing points which are upper limits, represented as a horizontal bar with an arrow pointing downwards. I know how to correctly position the arrow (and I achieve the bar using point x-errors), but my question is how to ensure that all arrows are always the same absolute length. The arrow doesn’t support NDC coordinates and there doesn’t seem to be a way of doing UserToNDC for example. In particular I might need to do this in the case of a logarithmic scale, so just subtracting a constant offset from the arrow’s root coordinates won’t work.

Hugh

Do you have a small macro showing what you are doing ?

This is the best I’ve been able to come up with so far:

[code]// Draw Arrows on UL points and ass x error bars
ulGraph->SetMarkerStyle(9);
TObjArray arrows;
for(Int_t j = 0; j<= ulGraph->GetN(); j++){
// calculate end point of arrow using transformations between user and pixel coordinates
ulGraph->GetPoint(j, x1, y1);
arrows.Add(new TArrow(x1, y1, x1, y2, 0.015, “|>”));
dynamic_cast<TArrow*>(arrows.Last())->Draw();
}

for(Int_t j = 0; j<= ulGraph->GetN(); j++){
// set x error bars
ulGraph->SetPointEXhigh(j, binWidths.at(j)/2.0);
ulGraph->SetPointEXlow(j, binWidths.at(j)/2.0);
}
[/code]

In this case, the arrows all have the same length, but I can’t make that length a consistent fraction of the pad height or a consistent number of pixels. Basically, I need to know how to transform between coordinate systems to produce arrows with consistent absolute size, independent of user coordinates.

Cheers

Hugh

In principle the arrow size and angle do not depend on the screen unit. so it should work as you wish.

It’s been a while but I still haven’t solved this problem (don’t worry, I have been working on other things in the interim!). I think there was some confusion as to what I meant by arrow size. I don’t mean the size of the arrowhead, but rather the length of the arrow.

Since I just want to make upper limit markers the arrow will be pointing vertically down. The coordinates of the start and end points of the arrow are specified in the user coordinate system. I need to be able to ensure that the arrow lengths are a constant fraction of the pad size. In particular, the case when the pad is logarithmic in y is giving me a headache!

Has anyone done this and if so, what are the required coordinate transformations to achieve it in both the log and linear case?

Cheers,

Hugh

The small pice of code you sent earlier can not be run directly. Can you sent one simple RUNNING example showing what you are doing ?

Alternatively, in future versions of ROOT, one of the standard marker types could be a downward pointing arrow. This would be very useful for making graphs of upper limits.

Ok,
meanwhile can you sent that littlle example I asked ?

[code]{
Double_t x[3] = {1, 2, 3};
Double_t y[3] = {1, 1.5, 3};
Double_t ex[3] = {0.5, 0.5, 0.5};

TGraphErrors * ulGraph = new TGraphErrors(3, (Double_t*)(&x[0]), &y[0], &ex[0], 0);

ulGraph->Draw(“APEZ”);
ulGraph->GetYaxis()->SetRangeUser(0.0, 4.0);

// Draw Arrows on UL points and ass x error bars
ulGraph->SetMarkerStyle(9);
TObjArray arrows;
for(Int_t j = 0; j<= ulGraph->GetN(); j++){
// calculate end point of arrow using transformations between user and pixel coordinates
ulGraph->GetPoint(j, x1, y1);
arrows.Add(new TArrow(x1, y1, x1, y2, 0.015, “|>”));
dynamic_cast<TArrow*>(arrows.Last())->Draw();
}
}[/code]

This produces something close for linear y, but the length of the arrows depends on the y axis limits and it doesn’t work at all for logarithmic y.

Cheers,

Hugh

I need some clarification:

The value “0.3” seems to be the error along Y you would like for you arrow. Is that in user coordinates, or is it in normalized coordinates ? I mean do you always want to have the same length whateever the Y coordinates are ? also in log scale do you want always the same length ?

Yes, ideally it should be the same size (relative to the pad) in all cases. It’s not really an error with a real magnitude, just a marker showing that the true y value can be anything less than the y value of the graph point. I need it to be the same size in all cases in case I need to show two graphs with upper limits side by side. It would look bad if the arrows were all different lengths.

Perhaps I need to add an offset in the pixel coordinate system?

Hope that clarifies things. Cheers.

Hugh

Yes. it is clear. Give me a bit of time to come with something.

in linear scale the right way is:

``````{
TCanvas *c1 = new TCanvas("c1", "c1",15,48,700,500);

Double_t x[3] = {1, 2, 3};
Double_t y[3] = {1, 1.5, 3};
Double_t ex[3] = {0.5, 0.5, 0.5};

TGraphErrors * ulGraph = new TGraphErrors(3, (Double_t*)(&x[0]), &y[0], &ex[0], 0);

ulGraph->Draw("APEZ");
ulGraph->GetYaxis()->SetRangeUser(0.0, 4.0);

// Draw Arrows on UL points and ass x error bars
ulGraph->SetMarkerStyle(9);
TObjArray arrows;

Double_t dy   = (0.075*(ymax-ymin))+ymin;

for(Int_t j = 0; j<= ulGraph->GetN(); j++){
ulGraph->GetPoint(j, x1, y1);
y2 = y1-dy;
arrows.Add(new TArrow(x1, y1, x1, y2, 0.015, "|>"));
dynamic_cast<TArrow*>(arrows.Last())->Draw();
}
}``````

give me time for log scale.

Note that there is a very simple way to do something close to what to want:

``````{
Double_t x[3]  = {1, 2, 3};
Double_t y[3]  = {1, 1.5, 3};
Double_t ex[3] = {0.5, 0.5, 0.5};
TGraphErrors * ulGraph = new TGraphErrors(3, x, y, ex, 0);
ulGraph->SetMarkerStyle(23);
ulGraph->Draw("AP");
}``````

Yes, it’s close but it’s not right and wouldn’t be implicitly understood by those who saw it. I’m guessing that getting this to work with log scales is very tricky. Thanks very much for the help with the linear scale though.

Cheers,

Hugh