C++ and Root, passing 2D array to function and use it in TGraph

2.8k views Asked by At

How can I pass a 2D array into a function and use it like myArray[i][j] but without knowing the size of that array inside that function?

I can know the size inside the main.

I want to use it like this:

TGraph *myGraph = new TGraph(nValues, myArray[0][j], myArray[1][j]);
// I'll not use a loop for j, since TGraph receives all the values in the array,
   like "x values" and "y values"  

If I do it like this it works, but I would have to pass to the function Col1 and Col2 that are two 1D arrays:

main() {
     ...
     graphWaveTransmittance("a", nValues, Col1, Col2,
                           " Au ", "Evaporated", "thickness 5nm", kGreen+1);
     ...
}



void graphWaveTransmittance(char *n, int nValues, float Param1[], float Param2[],
                      char *title, char *header, char *entry, Color_t color) {

     TGraph *myGraph = new TGraph(nValues, Param1, Param2);
     ...
}

The Array:

float valuesArray[nCol][nValues];

for(int y=0; y<nValues; y++){
    for (int i=0; i<nCol; i++) {
        valuesArray[i][y] = values[i][y];
    }
    i=0;
}

Note: I've made it like this because values[ ][ ] is an array with values that are read from a text file. Before read the file I don't know how many lines are going to be necessary. With this second array (valuesArray[ ][ ]) I can make it to have just the size of the number of values that are read.

Firstly, I've put all the values in values[ ][ ] with "-1" and it's size very large. Then I've counted the number of lines and just used that value for valuesArray[ ][ ]. This is the first array with values (the large one):

const int nCol = countCols;
float values[nCol][nLin];

    // reads file to end of *file*, not line 
while(!inFile.eof()) {
    for(int y=0; y<nLin; y++){
        for (int i=0; i<nCol; i++) {
            inFile >> values[i][y];
        }
    i=0;    
    }
}

One other question, I've seen that "while(!inFile.eof())" shouldn't be used. What can I use instead? (I don't know the total number of lines from the .txt file at this point)

Importing values in columns in a .txt, till now I have:

    vector<vector<float> > vecValues;  // your entire data-set of values

vector<float> line(nCol, -1.0);  // create one line of nCol size and fill with -1

bool done = false;
while (!done) 
{
    for (int i = 0; !done && i < nCol; i++) 
    {
        done = !(inFile2 >> line[i]);
    }
    vecValues.push_back(line);  
}

The problem of this is that the values are like vecValues[value][column number from .txt] I want to have vecValues[column number from .txt][value].

How can I change it?


I'm reading from the file like this:

main() {
    ...

    vector < vector <float> > vecValues; // 2d array as a vector of vectors
    vector <float> rowVector(nCol); // vector to add into 'array' (represents a row)
    int row = 0; // Row counter


    // Dynamically store data into array
    while (!inFile2.eof()) { // ... and while there are no errors,
        vecValues.push_back(rowVector); // add a new row,
        for (int col=0; col<nCol; col++) {
            inFile2 >> vecValues[row][col]; // fill the row with col elements
        }
        row++; // Keep track of actual row 
    }


    graphWaveTransmittance("a", nValues, vecValues, " Au ",
                   "Evaporated", "thickness 5nm", kGreen+1); 
       // nValues is the number of lines of .txt file
    ...
}


//****** Function *******//

 void graphWaveTransmittance(char *n, int nValues,
           const vector<vector <float> > & Param, char *title, char *header,
           char *entry, Color_t color) {

       // like this the graph is not good
       TGraph *gr_WTransm = new TGraph(nValues, &Param[0][0], &Param[1][0]);

       // or like this
     TGraph *gr_WTransm = new TGraph(Param[0].size(), &Param[0][0], &Param[1][0]);

Note: TGraph can accept floats, my previous arrays were floats

Do you know why the graph is not appearing correctly?

Thank you

2

There are 2 answers

2
Michael Parker On

I ran into a similar problem recently. I ended up using two dimensional vectors, which don't need to know the inner dimension when passed to a function.

Declare vectors like this

vector< vector<int> > vec(xRange, vector<int>(yRange, initialValue));

While replacing xRange with your size in the x dimension, yRange with your size in the y direction, and initialValue with what you want to initialize your 2d vector with.

At this point, you can access or update vector contents using

vec[x][y]

To pass this to a function, use this

void myFunc(std::vector< std::vector<int> >& vec) {

Be sure to

#include <vector>
4
Doms On

You can use vectors to sove this problem as Michael Parker already mentioned. To make it work in root with graphs, note that TGraph expects two arrays of double or float as parameters. Therefore you have to use

std::vector<std::vector<double> > or std::vector<std::vector<float> >

in your case. Then your function looks like:

void drawGraph(const std::vector<std::vector<double> > & data)
{
    TGraph* graph = new TGraph(data[0].size(), &data[0][0], &data[1][0]);
    //...

}

The &data[0][0] "converts" the vectors to arrays as needed by TGraph.

Concerning your second question, instead of using !inFile.eof(), I typically directly ask whether the reading process was succesful, i.e. in your case:

if(!(inFile >> values[i][y]))
{
//at end of file 
}

I prefer to use this in a while loop but thats a matter of taste. By the way, by using vectors you no longer need to run though the whole file in advance to count the number of lines, just use push_back(...).

If you do not know the number of lines nor the number of columns, you can use getline to read out the file and to determine the number of columns:

std::vector<std::vector<float> > data;
std::string buffer;
getline(infile,buffer)//I do not check that the file has at least one line here
istringstream firstLine(buffer);
float value;
while(firstline >> value)
{
    data.push_back(std::vector<float>(1,value));
}

while(getline(infile,buffer))
{
    istringstream line(buffer);
    float value;
    unsigned int counter = 0;
    while(line >> value)
    {
        data[counter].push_back(value));
        counter++;
    }
}

Note that this requires:

 #include<sstream>

and that this assumes that the number of columns does not change over the file size.