KAHIBARO
Discord Login Register

7.2. Creating a TGraph

Creating graphs from arrays

A TGraph represents a set of points $(x_i, y_i)$ stored as C++ arrays (or similar containers) and drawn as a graph. In this section the focus is on how to build such a graph from numerical data that you already have in memory.

The most direct constructor for TGraph takes the number of points and two arrays of coordinates:

cpp
int n = 5;
double x[n] = {0, 1, 2, 3, 4};
double y[n] = {0, 1, 4, 9, 16};
TGraph *g = new TGraph(n, x, y);

After construction, you can draw the graph on a canvas:

cpp
g->Draw("ALP");

The exact meaning of drawing options such as "ALP" is covered in the dedicated graph styling chapter. Here it is enough to know that Draw makes your TGraph visible.

The arrays that you pass to the constructor must have at least n elements. The type is usually double, although float can also be used. Internally TGraph stores its own copy of the data, so the original arrays can go out of scope after the constructor returns.

You can also use C++ standard containers like std::vector<double> by passing the address of the first element:

cpp
std::vector<double> xvals = {0.1, 0.2, 0.3};
std::vector<double> yvals = {10.0, 20.0, 30.0};
int n = xvals.size();
TGraph *g2 = new TGraph(n, &xvals[0], &yvals[0]);

If the vector is empty this approach is invalid because there is no element zero to take the address of. In practice, always check that the vector is not empty before taking &vec[0].

It is also possible to build an “empty” graph with a given number of points and then set each coordinate explicitly:

cpp
int n = 3;
TGraph *g3 = new TGraph(n);
g3->SetPoint(0, 0.0, 0.0);
g3->SetPoint(1, 1.0, 1.0);
g3->SetPoint(2, 2.0, 4.0);

In this constructor the graph is created with space for n points, but the coordinates are uninitialized until you call SetPoint. This method is useful when you know in advance how many points you will have, but the numerical values are computed later in your code.

There is also a text based constructor, where TGraph reads data points from a file with two columns corresponding to $x$ and $y$. The details of reading external data are treated in other chapters, but the essential idea is:

cpp
TGraph *gfile = new TGraph("data.txt"); // data.txt contains x y pairs

In that case each line of the file is interpreted as a point. This is mainly useful when your data is already stored in a plain text file.

Whenever you rely on a constructor that takes arrays or pointers, it is good practice to be sure that the number of points n is correct and matches the logical size of your data. A mismatch between n and the physical array size is a common source of subtle bugs.

In a TGraph created from arrays, the integer n passed to the constructor must not exceed the actual number of elements in the x and y arrays. Passing a larger n than the storage really holds leads to undefined behavior.

Adding points manually

Sometimes you do not have all your data up front as arrays. Instead, you generate points one by one, for example in a loop or in response to some conditional logic. In such cases you can create an initially empty TGraph and then add points manually.

The simplest approach is:

cpp
TGraph *g = new TGraph();  // starts with zero points
g->SetPoint(0, 0.0, 0.0);
g->SetPoint(1, 1.0, 2.0);
g->SetPoint(2, 2.0, 3.0);

The first argument to SetPoint is the point index, starting from zero. You can call SetPoint in any order, but for a clean workflow it is typical to increase the index by one each time. If you overwrite an existing index, the old point at that index is replaced.

More often, the number of points is not known in advance. In that case, you can keep a simple counter and increment it as you add each new point:

cpp
TGraph *g = new TGraph();
int ipoint = 0;
for (int i = 0; i < 10; ++i) {
    double x = i * 0.5;
    double y = x * x;
    g->SetPoint(ipoint, x, y);
    ++ipoint;
}

After the loop the graph contains 10 points. The internal size of the graph grows as needed when you increase the maximum index you have used.

You can query the number of points in a TGraph at any time using:

cpp
int npoints = g->GetN();

This is helpful when you build the graph dynamically and need to know its current size for further processing.

If you prefer a more automatic style, you can use TGraph::SetPoint together with GetN to append to the end without manually tracking a counter:

cpp
TGraph *g = new TGraph();
for (int i = 0; i < 10; ++i) {
    double x = i * 0.1;
    double y = std::sin(x);
    int idx = g->GetN();     // current number of points
    g->SetPoint(idx, x, y);  // append new point at the end
}

This pattern guarantees that you always write the next free index, even if earlier code already inserted some points.

Since TGraph owns its data after you use SetPoint, you do not need to keep additional arrays around. The graph can be drawn, written to a ROOT file, or passed to other ROOT functions in later analysis stages.

Finally, be aware that a TGraph does not force any specific order on the $x$ values. If you add points with $x$ values that are not sorted, ROOT will still draw a polyline from the first point (index 0) to the last in index order. If you want a visually meaningful curve, it is usually better to fill points with monotonically increasing or decreasing $x$ so that the drawn line follows the natural order of the data.

When adding points manually with SetPoint, the order of indices determines how the graph is drawn. If the indices do not correspond to sorted $x$ values, the line between adjacent points in index space can cross back and forth, which may misrepresent the underlying function of interest.

Views: 12

Comments

Please login to add a comment.

Don't have an account? Register now!