Reading multiple .dat files and save plots in .root

Hi everybody! I am new and this is my very first post. I hope i posted in the more appropriate category.
I am a physicist (like a lot in here i suppose) but i have to confess i seriously converted to ROOT since a couple of months. Of course i already had a lot of time to get introduced in ROOT and i already worked a lot with it but never by writing from blank a new script. Now it’s time to grow!

Here’s the deal: i am shooting beta particles through a diamond with graphite contacts and i am getting the numbers of collected electrons-holes. My software provide me essentially a file .dat, two columns of numbers: the bin (ADC channel) and the counts.

I want to plot the Energy Loss Distribution of the charged particles impinging in my diamond. Of course i change the voltage accross the diamond and i have several .dat files. It is one week i am dying in order to give as input not only one file name but to automatically read all the files present in the folder (i.e. run_1.dat, run_2.dat, etc.)

Here is a minimal working example of what i was able to write alone.


#include <iostream>   // std ::cout
#include <fstream>    // std::ifstream
#include "TFile.h"
#include <TCanvas.h>
#include "TLegend.h"
#include "TGraph.h"

using namespace std;

void Example()
{  
   string filename,infile,fileout,extin,extout;
   string input_dir;
   char DatDirectory [99];


// Reading .dat files (i want more than one!!!)
   extin=".dat";
   extout=".root";
   cout << "Please enter the directory containing\n"
           "the .dat files you wish to plot "<< endl;
   cin >> DatDirectory;
   cin.getline(DatDirectory, sizeof(DatDirectory));
   input_dir=(DatDirectory);   // Input Directory from user
   cout<<"File you wish to plot? (without .dat extension): ";
   // Asking filename
   getline(cin, filename);
   infile=input_dir+filename+extin;
   fileout=filename+extout;
   cout<<"Processing Data File: "<<infile<<endl;    //Just a check



// Graphic Section
   c1 = new TCanvas(infile.c_str(),"My Plot");
   TGraph *gr=new TGraph(infile.c_str(),"%lg %lg"); 
   gr->Draw("AL");                               
   

// Saving my Graph
   TFile *f0=new TFile(fileout.c_str(),"RECREATE");
   gr->Write();  
   f0->Close(); 
}

this is a working script, you can have fun with it.

Now the deal: is anybody able to tell me, for my mental health sake, how can i input from screen the two run_*.dat at once? And eventually how to save both graphs? I’ll be delighted and forever grateful!!

I would have attached some .dat file but i can’t find how to… :cry:

EDIT: .dat files seems not allowed… i attached them as .txt so to use them in the script just change extin=".dat"; into extin=".txt";
or rename the extensions to .dat again :slight_smile:
P.S.
I know for sure that the ‘99’ inside char DatDirectory [99]; is giving me a warning (warning: expression result unused [-Wunused-value]) but this is another minor thing i couldn’t figured out till now…run_2.txt (134.2 KB)
run_1.txt (134.0 KB)

I am not sure to understand if you want to plot two graph on the same “figure” (same axis and so on) or if you want to plot both graph beside each other.
In the first case, you have to use TMultiGraph.
In the second case, you have to use the Divide method of the TCanvas class.

Hi there!
thank you a lot for taking a look to my request. For the nature of my data they will have the same X dynamics (they are more or less truncated Landau distributions which grows a bit but at certain point saturates) so i’ll plot them right one on top of the other with “same” from TBrowser (this is what i know till now).

The main issue i have here is to be able to tell the program to read not just run_1.dat and go ahead, but to input all the run_*.dat present in the folder.

Issue number two is to save all the generated plots into the same .root

Eventually, minor issue number 3 to eliminate the warning (only to be picky).

Thank you a lot!

Well, something like that should work (I did not test it but it will give you the idea on how to do it).

TFile *f = new TFile("yourRootFile.root","RECREATE");
//std::vector <TGraph*> myGraph; //if youwant to do more thing with each TGraph, you can store them in a std::vector
TMultiGraph *mmg = new TMultiGraph();
for(int i=0 ; i<10 ; i++) {
std::stringstream filename;
filename << "myrun" << i << ".dat"
TGraph *g = new TGraph(filename.str().c_str(),"%lg %lg");

std::stringstream ss;
ss << "graph" << i;
g->SetName(ss.str().c_str());
mg->Add(g);
//myGraph.push_back(g);
g->Write();
}
mg->Draw("A");
f->Close();
1 Like

Or something like this to loop over the “.dat” files in a given directory:

#include <iostream>   // std ::cout
#include <fstream>    // std::ifstream
#include <vector>
#include <string>
#include "TFile.h"
#include <TCanvas.h>
#include "TLegend.h"
#include "TGraph.h"
#include "TSystemDirectory.h"
#include "TList.h"

using namespace std;

void list_files(vector<string> &filenames, const char *dirname="C:/root/folder/",
                const char *ext=".dat")
{
   TSystemDirectory dir(dirname, dirname);
   TList *files = dir.GetListOfFiles();
   if (files) {
      TSystemFile *file;
      TString fname;
      TIter next(files);
      while ((file=(TSystemFile*)next())) {
         fname = file->GetName();
         if (!file->IsDirectory() && fname.EndsWith(ext)) {
            string filename = fname.ReplaceAll(ext, "");
            cout << filename << endl;
            filenames.push_back(filename);
         }
      }
   }
}

void Example()
{
   vector<string> filenames;
   string filename,infile,fileout,extin,extout,input_dir;

   extin=".dat";
   extout=".root";
   cout << "Please enter the directory containing the " <<
        extin << " files you wish to plot "<< endl;
   cin >> input_dir;
   cout<<"Reading files from "<<input_dir<<endl;    //Just a check
   list_files(filenames, input_dir.c_str(), extin.c_str());
   for (auto name : filenames) {
      infile=input_dir+name+extin;
      fileout=name+extout;
      cout<<"Processing Data File: "<<infile<<endl;    //Just a check

      new TCanvas(infile.c_str(), "My Plot");
      TGraph *gr = new TGraph(infile.c_str(), "%lg %lg"); 
      gr->Draw("AL");                               

      TFile *f0 = TFile::Open(fileout.c_str(), "RECREATE");
      gr->Write();  
      f0->Close(); 
      delete f0;
   }
}
2 Likes

Holy smokes!
when you see a solution it’s always so easy that it’s embarassing for who was wandering in the dark.

Lemme try both and soon i’ll post the whole script that performs also a fit with two landau+a gauss. I think it could be of help since this solution was nowere to be found and solves a problem for whoever deals with Strontium as source (which decay is 90Sr->90Y->Zr so that you always have a convolution between two landau plus a gauss of noise.

Thank you a lot, i’ll back to you asap with a script trying to solve the whole issue.

EDIT:
the script you proposed looks very very intriguing but i cannot compile and the errore i’m afraid is beyond my actual kung-fu:

root [0] .x Example.C
In file included from input_line_8:1:
/myMacOSfolder/Example.C:91:20: error: no viable conversion from 'TString' to 'string' (aka
      'basic_string<char, char_traits<char>, allocator<char> >')
            string filename = fname.ReplaceAll(ext, "");
                   ^          ~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1349:5: note: 
      candidate constructor not viable: no known conversion from 'TString' to 'const std::__1::basic_string<char> &' for 1st
      argument
    basic_string(const basic_string& __str);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1354:5: note: 
      candidate constructor not viable: no known conversion from 'TString' to 'std::__1::basic_string<char> &&' for 1st argument
    basic_string(basic_string&& __str)
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1364:31: note: 
      candidate constructor not viable: no known conversion from 'TString' to 'const value_type *' (aka 'const char *') for 1st
      argument
    _LIBCPP_INLINE_VISIBILITY basic_string(const value_type* __s);
                              ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:1385:5: note: 
      candidate constructor not viable: no known conversion from 'TString' to 'initializer_list<value_type>'
      (aka 'initializer_list<char>') for 1st argument
    basic_string(initializer_list<value_type> __il);
    ^
/usr/local/Cellar/root6/6.08.02/include/root/TString.h:289:4: note: candidate function
   operator const char*() const { return GetPointer(); }
   ^
/usr/local/Cellar/root6/6.08.02/include/root/TString.h:290:4: note: candidate function
   operator std::string_view() const { return std::string_view(GetPointer(),Length()); }
   ^

I hope it is not somehow because i have a MacOS (10.11.6)…

Try with:

string filename(fname.ReplaceAll(ext, "").Data());

That solved the issue. Now i read at once all the .dat files in a certain folder URRAH!

You (and the other gentle user pamputt of course) surely have a beer on me!!!

P.S. if i post the whole script complete with the fit part probably it will contain other kind of issues to solve not under the topic i titled, so i was thinking to open a new thread… I think this can be declared solved!!! WOW

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.