Filling a TGraph with strings on axis label

Hi Everyone,

I am having an issue with creating a TGraph. What I have is a vector (not a TVector) of doubles and a vector of strings. I would like to fill a TGraph and have the y-axis values be the values from the vector of doubles and have the x-axis values be the values from the vector of strings. Is there a way to do this? Thanks in advance.

Using ROOT 5.34/09

Alpha numeric labels are available on binned data only. See for instance:
root.cern.ch/doc/master/labels1_8C.html

Since ROOT version 6.08 ChangeLabel can help.

Although as couet said this is not intended by root it is still possible because the TGraph class uses an internal TH1 for drawing so all possibilities of a TH1 are more or less available for TGraphs. Assuming your vecors are of the std::vector type I’ve written you a short macro that does what you want. I names the vecors simply y_vals and x_labels. The problem is that you still have to set a numeric x-value, because otherwise root does not know where on the x-axis a specific string has to be drawn. In my example I just enumerate the points from 1 to Number of Points, which I assume is what you intended:

std::vector<Double_t> y_vals;
std::vector<std::string> x_labels;

// Fill the vectors here

TGraph* tg = new TGraph(TMath::Min(y_vals.size(), x_labels.size())); // Create the TGraph object

for (Int_t i = 0; i < TMath::Min(y_vals.size(), x_labels.size()); i++) { // Loop over all entries
    tg->SetPoint(i, i + 1., y_vals[i]); // Set The point itself
    tg->GetXaxis()->SetBinLabel(tg->GetXaxis()->FindBin(i + 1.), x_labels[i].c_str()); // Find out which bin on the x-axis the point corresponds to and set the bin label
}

tg->Draw("AP"); // Draw the TGraph

Hope this helps you. I tested it and it worked like I expected it to.

1 Like

data40Ktest.dat.txt (701 Bytes)
Hi, thank you for this solution, it works for me- but along the x axis, all values aren’t displayed. It just shows one of them at the end. Any idea how to solve this?

void plot(){
std::vector<Double_t> y_vals;
std::vector<std::string> x_labels;

// Fill the vectors here
std::ifstream file ("data40Ktest.dat");
if(!file){
cout << "File doesn't exist" << endl;
    }
std::string x;
double y;
int i = 0;
while(!file.eof()){
file >> x >> y;
x_labels.push_back(x);
y_vals.push_back(y);
                }


TGraph* tg = new TGraph(TMath::Min(y_vals.size(), x_labels.size())); // Create the TGraph object

for (Int_t i = 0; i < TMath::Min(y_vals.size(), x_labels.size()); i++) { // Loop over all entries
    tg->SetPoint(i, i + 1., y_vals[i]); // Set The point itself
    tg->GetXaxis()->SetBinLabel(tg->GetXaxis()->FindBin(i + 1.), x_labels[i].c_str()); // Find out which bin on the x-axis the point corresponds to and set t
}

tg->Draw("ALP"); // Draw the TGraph

}

As @couet already stated alphanumeric labels are not intended on Graphs. You have to see my solution as a dirty hack. I think the most probable reason why it does not work for you is that the bin labels are not transferred when the internal helper histogram is recreated.

One could solve this by creating an explicit helper histogram by hand:

TGraph* tg = new TGraph(TMath::Min(y_vals.size(), x_labels.size()));
for (Int_t i = 0; i < tg->GetN(); i++)
    tg->SetPoint(i, i + 1., y_vals[i]);

TH1F* h = (TH1F*) tg->GetHistogram()->Clone();
for (Int_t i = 0; i < tg->GetN(); i++)
    h->GetXaxis()->SetBinLabel(i + 1, x_labels[i].c_str());

h->Draw("AXIS");
tg->Draw("LP");

I think you made a double posting. See my answer here:

@Triple_S Thanks for the trick, but it doesn’t work for me, when I try to make a graph with double Y axis. It either doesn’t draw it at all, or draws it wrong.

void plot(){
std::vector<Double_t> y_vals;
std::vector<std::string> x_labels;
std::vector<Double_t> y2_vals;
auto c=new TCanvas();
c->SetGrid();
// Fill the vectors here
std::ifstream file ("data40Ktest.dat.txt");
if(!file){
cout << "File doesn't exist" << endl;
    }
std::string x;
double x2, y, y2;



while(!file.eof()){
file >> x >> y >> x2 >> y2;
x_labels.push_back(x);
y_vals.push_back(y);
y2_vals.push_back(y2);
                }
//fill the Graphs
c->cd();
/*TGraph* tg = new TGraph(TMath::Min(y_vals.size(), x_labels.size())); // Create the TGraph object

for (Int_t i = 0; i < TMath::Min(y_vals.size(), x_labels.size()); i++) { // Loop over all entries
    tg->SetPoint(i, i + 1., y_vals[i]); // Set The point itself
    tg->GetXaxis()->SetBinLabel(tg->GetXaxis()->FindBin(i + 1.), x_labels[i].c_str()); // Find out which bin on the x-axis the point corresponds to and set t
}*/

TGraph* tg2 = new TGraph(TMath::Min(y2_vals.size(), x_labels.size())); // Create the TGraph object

for (Int_t i = 0; i < TMath::Min(y2_vals.size(), x_labels.size()); i++) { // Loop over all entries
    tg2->SetPoint(i, i + 1., y2_vals[i]); // Set The point itself
    tg2->GetXaxis()->SetBinLabel(tg2->GetXaxis()->FindBin(i + 1.), x_labels[i].c_str()); // Find out which bin on the x-axis the point corresponds to and set
}


TGraph* tg = new TGraph(TMath::Min(y_vals.size(), x_labels.size()));
for (Int_t i = 0; i < tg->GetN(); i++)
    tg->SetPoint(i, i + 1., y_vals[i]);

TH1F* h = (TH1F*) tg->GetHistogram()->Clone();
for (Int_t i = 0; i < tg->GetN(); i++)
    h->GetXaxis()->SetBinLabel(i + 1, x_labels[i].c_str());

// Draw the plots
tg->SetMarkerStyle(7);
tg2->SetMarkerStyle(8);
tg2->SetMarkerColor(kBlue);
tg2->SetLineColor(kBlue);

tg2->GetYaxis()->SetLabelColor(kBlue);

tg2->GetYaxis()->SetTitleOffset(1.4);
tg2->GetYaxis()->SetTitle("y2-title");
tg->GetYaxis()->SetTitle("y1-title");
tg->GetXaxis()->SetTitle("x1-title");

TPad *pad1 = new TPad("pad1","",0,0,1,1);
TPad *pad2 = new TPad("pad2","",0,0,1,1);
TPad *pad3 = new TPad("pad3","",0,0,1,1);
pad2->SetFillStyle(4000); //will be transparent
pad2->SetFrameFillStyle(0);

pad1->Draw();
pad1->cd();
h->Draw("AXIS");
tg->Draw("ALP");

pad2->Draw();
pad2->cd();
tg2->Draw("ALPY+"); //sets the axis/labels on the opposite side


c->Update();
}


Your macro doesn’t work for me … It is stuck in some kind of infinite loop…
It does nothing

Did it write that “File doesn’t exist”?
Maybe there’s wrong name of the file in the macro

No, the file exists, I took it form your first post. It simply never open a graphics window and it stuck forever…

That’s weird. It runs for me… Could you please try it now?
newfile.txt (1.0 KB)

void plot(){
std::vector<Double_t> y_vals;
std::vector<std::string> x_labels;
std::vector<Double_t> y2_vals;
auto c=new TCanvas();
c->SetGrid();
// Fill the vectors here
std::ifstream file ("newfile.txt");
if(!file){
cout << "File doesn't exist" << endl;
    }
std::string x;
double x2, y, y2;



while(!file.eof()){
file >> x >> y >> x2 >> y2;
x_labels.push_back(x);
y_vals.push_back(y);
y2_vals.push_back(y2);
                }
//fill the Graphs
c->cd();
TGraph* tg = new TGraph(TMath::Min(y_vals.size(), x_labels.size())); // Create the TGraph object

for (Int_t i = 0; i < TMath::Min(y_vals.size(), x_labels.size()); i++) { // Loop over all entries
    tg->SetPoint(i, i + 1., y_vals[i]); // Set The point itself
    tg->GetXaxis()->SetBinLabel(tg->GetXaxis()->FindBin(i + 1.), x_labels[i].c_str()); // Find out which bin on the x-axis the point corresponds to and set t
}

TGraph* tg2 = new TGraph(TMath::Min(y2_vals.size(), x_labels.size())); // Create the TGraph object

for (Int_t i = 0; i < TMath::Min(y2_vals.size(), x_labels.size()); i++) { // Loop over all entries
    tg2->SetPoint(i, i + 1., y2_vals[i]); // Set The point itself
    tg2->GetXaxis()->SetBinLabel(tg2->GetXaxis()->FindBin(i + 1.), x_labels[i].c_str()); // Find out which bin on the x-axis the point corresponds to and set
}
TH1F* h = (TH1F*) tg->GetHistogram()->Clone();
for (Int_t i = 0; i < tg->GetN(); i++)
    h->GetXaxis()->SetBinLabel(i + 1, x_labels[i].c_str());



// Draw the plots
tg->SetMarkerStyle(7);
tg2->SetMarkerStyle(8);
tg2->SetMarkerColor(kBlue);
tg2->SetLineColor(kBlue);

tg2->GetYaxis()->SetLabelColor(kBlue);

tg2->GetYaxis()->SetTitleOffset(1.4);
tg2->GetYaxis()->SetTitle("y2-title");
tg->GetYaxis()->SetTitle("y1-title");
tg->GetXaxis()->SetTitle("x1-title");

TPad *pad1 = new TPad("pad1","",0,0,1,1);
TPad *pad2 = new TPad("pad2","",0,0,1,1);
TPad *pad3 = new TPad("pad3","",0,0,1,1);
pad2->SetFillStyle(4000); //will be transparent
pad2->SetFrameFillStyle(0);

pad1->Draw();
pad1->cd();

tg->Draw("ALP");
h->Draw("AXIS");
pad2->Draw();
pad2->cd();
tg2->Draw("ALPY+"); //sets the axis/labels on the opposite side


c->Update();
}

We already discussed it in previous topic, but I just find it strange, that the helping histogram isn’t drawn properly.

It runs now and I see the messed up labels.
Let me try to understand.

1 Like
void plot(){
   std::vector<Double_t> y_vals;
   std::vector<std::string> x_labels;
   std::vector<Double_t> y2_vals;
   auto c=new TCanvas();
   c->SetGrid();
   // Fill the vectors here
   std::ifstream file ("newfile.txt");
   if(!file) cout << "File doesn't exist" << endl;

   std::string x;
   double x2, y, y2;

   while(!file.eof()){
      file >> x >> y >> x2 >> y2;
      x_labels.push_back(x);
      y_vals.push_back(y);
      y2_vals.push_back(y2);
   }

   //fill the Graphs
   c->cd();
   int n = TMath::Min(y_vals.size(), x_labels.size());

   TGraph* tg = new TGraph(n);

   for (Int_t i = 0; i <n; i++) tg->SetPoint(i, i + 1., y_vals[i]);

   auto h = new TH1F("h","h",n,0,n);
   tg->SetHistogram(h);

   for (Int_t i = 0; i < n; i++) {
      h->GetXaxis()->SetBinLabel(i + 1, x_labels[i].c_str());
   }

   // Draw the plots
   tg->SetMarkerStyle(20);
   tg->Draw("ALP");
}

1 Like

Thanks Olivier, I appreciate your help. I see that this “trick” with histogram works when I have one TGraph, but not when I add a second one.

Just draw the 2nd graph on top using option “LP”