Plotting a second graph axis

Hello everyone,

I am quite new to ROOT, and I have some trouble getting the plot I want.
For my first code I have to create a macro taking a data file (.dat), and ploting the data inside of it. My data file contains 5 columns : time, voltage value, voltage error, current value and current error.

I managed to read the data file and store its values into variables that I use to plot with “TGraphErrors”.
My plot works, but I am confronted with a scale problem. As you can see on this image, it is impossible to see anything about the current given the different scales of the values, which are plotted on the same scale :

(see attachment)

What I would like to do, is to create a second Y-axis on the right side of my graph for the current values and their errors while the voltage values stay attached to the Y-axis on the left, just as we can see in this image from google :

I have looked into the ROOT documentation but unfortunately I haven’t found anything to help me plot this. Would you happen to have a solution to this problem ? Thanks for any help.

If this is of any help, here is my code :

// Reads the points from a data file and produces a graph.

// Here, the data file is composed of 5 different columns
// First is time, then voltage values, voltage errors,
// current values and finally current errors

// The macro gets the values from the data file and plots them
// Plots for voltage and current are displayed on the same canvas

#include <TGraph.h>
#include <TCanvas.h>
#include <TF1.h>
#include <TMath.h>
#include <TStyle.h>

#include <iostream>
#include <fstream>
#include <string>

#include "TROOT.h"
#include "TGraphErrors.h"
#include "TF1.h"
#include "TLegend.h"
#include "TArrow.h"
#include "TLatex.h"



void plotdatafile1(){

   // Here we provide the number of lines from the data file and we create
   // variables in which to store the data

    const Int_t n_lines = 445;

    double_t time_vals[n_lines];

    double_t volt_vals[n_lines];
    double_t volt_errs[n_lines];

    double_t curr_vals[n_lines];
    double_t curr_errs[n_lines];

    // A few lines to get the data from the .dat file and put it directly into
    // respectively volt_vals, volt_errs, curr_vals and curr_errs

   //TFile *h = new TFile("File.root","RECREATE");
   FILE *f = fopen("2016-06-06_09-12-40_LeakageTest-FoilID_57_Long.dat","r");
   Int_t i=0;

   while (!feof(f)){
      fscanf(f,"%lf %lf %lf %lf %lf\n",&time_vals[i],&volt_vals[i],&volt_errs[i],&curr_vals[i],&curr_errs[i]);
      i++;
   }

   // Now we have stored the data from our .dat file into variables and we need
   // to plot both of it (voltage values with their erros, and current values
   // with theirs) on the same graph


   // Instance of the first graph for voltage values
   TGraphErrors graph_volt(n_lines,time_vals,volt_vals,nullptr,volt_errs);
   graph_volt.SetTitle("2016-06-06_09-12-40_LeakageTest-FoilID_57_Long;Time [s];Volts[V]");

   // Aesthetics of graph_volt
   graph_volt.SetMarkerStyle(1);
   graph_volt.SetMarkerColor(kBlue);
   graph_volt.SetLineColor(kBlue);

   // The canvas on which we'll draw the graph
   TCanvas *mycanvas = new TCanvas();

   // Drawing the graph
   graph_volt.DrawClone("APE");


   // Instance of the second graph, for the current values
   TGraphErrors graph_curr(n_lines,time_vals,curr_vals,nullptr,curr_errs);

   // Aesthetics of graph_curr
   graph_curr.SetMarkerStyle(1);
   graph_curr.SetMarkerColor(kRed);
   graph_curr.SetLineColor(kRed);

   // Building and drawing a legend
   TLegend leg(.1,.7,.3,.9,nullptr);
   leg.SetFillColor(0);
   graph_volt.SetFillColor(0);
   graph_curr.SetFillColor(0);
   leg.AddEntry(&graph_volt,"Voltage Values");
   leg.AddEntry(&graph_curr,"Current Values");
   leg.DrawClone("Same");

   // Drawing the second graph on the same canvas
   graph_curr.Draw("P");

   mycanvas->Modified();
   mycanvas->Update();
   mycanvas->Print("data_graph1.jpg");

}



int main(){
   plotdatafile1();
}


Hi,

You could take a look at the $(ROOTSYS)/tutorials/hist/twoscales.C tutorial, I think it can help.

Cheers, Bertrand.

Hi,

Thank you for the quick answer. I tried to adapt the method but I get the following error when launching my macro : “error: no member named ‘Scale’ in 'TGraphErrors’
graph_curr.Scale(scale);”

Do I have to use histograms for this to work ? If so, are there options to plot errors in histograms ?

Hi,

I’ll check your specific case later, but in the meanwhile, you can also take a look at the gaxis.C and gaxis2.C tutorials in the $(ROOTSYS)/tutorials/graphics directory

Cheers, Bertrand.

[quote=“LKFD”]Thank you for the quick answer. I tried to adapt the method but I get the following error when launching my macro : “error: no member named ‘Scale’ in 'TGraphErrors’
graph_curr.Scale(scale);”[/quote]
BTW, you don’t need to call Scale(). The relevant part of the code is:

//draw an axis on the right side TGaxis *axis = new TGaxis(gPad->GetUxmax(),gPad->GetUymin(), gPad->GetUxmax(), gPad->GetUymax(),0, rightmax,510,"+L"); axis->Draw();
“rightmax” being the max value of the right scale

Cheers, Bertrand.

Hi,

I have successfully created my second axis, but I can’t manage to attach my second graph to it.
That being, my two graphs stay on the first axis, which makes the second one impossible to read.

Hi,

Our graphics expert is away this week, but I’m sure you can find a solution if you search on this forum (for example with “TGAxis”)

Cheers, Bertrand.

Hi,
adding a second TGaxis does influence the coordinatesystem of the TPad
it just draws an extra axis. This was done when plotting the first Graph.
Therefore you must scale your second TGraphErrors according to your extra axis.
TGraphErrors does not provide a method Scale (as TH1 does)
This can be done easily:

TGraph *g ...
Double_t xx, yy;
Double_t scale = ..
for (Int_t i=0;  i<g->GetN();  i++) {
	g->GetPoint(i, xx, yy);
	g->SetPoint(i, xx, yy*scale);
}

Cheers
Otto

Hi Otto,

Thank you for the advice. I am however having a hard time implementing these lines into my code.

My understanding of your lines is that you “browse” the graph points and for each one reattribute coordinates with the Y-axis value scaled.

I tried to implement that, but my second graph still won’t get plotted. Here is my code, I suppose the mistake is located in between lines 76 and 92. I have set the ‘scale’ value arbitrary to 100 as an attempt to make the graph_curr apprear, after trying lower values.

//example of macro illustrating how to superimpose two histograms
#include "TGaxis.h"
#include "TRandom.h"

#include <TGraph.h>
#include <TCanvas.h>
#include <TF1.h>
#include <TMath.h>
#include <TStyle.h>

#include <iostream>
#include <fstream>
#include <string>

#include "TROOT.h"
#include "TGraphErrors.h"
#include "TLegend.h"
#include "TArrow.h"
#include "TLatex.h"

void plotfile()
{
   //example of macro illustrating how to superimpose two histograms
   //with different scales in the "same" pad.
   // To see the output of this macro, click begin_html <a href="gif/twoscales.gif" >here</a> end_html
   //Author: Rene Brun

   const Int_t n_lines = 445;

   double_t time_vals[n_lines];

   double_t volt_vals[n_lines];
   double_t volt_errs[n_lines];

   double_t curr_vals[n_lines];
   double_t curr_errs[n_lines];

   //TFile *h = new TFile("File.root","RECREATE");
   FILE *f = fopen("2016-06-06_09-12-40_LeakageTest-FoilID_57_Long.dat","r");
   Int_t i=0;

   while (!feof(f)){
      fscanf(f,"%lf %lf %lf %lf %lf\n",&time_vals[i],&volt_vals[i],&volt_errs[i],&curr_vals[i],&curr_errs[i]);
      i++;
   }

   TCanvas *c1 = new TCanvas("c1","hists with different scales",600,400);

   //create/fill draw h1
   gStyle->SetOptStat(kFALSE);
   TGraphErrors graph_volt(n_lines,time_vals,volt_vals,nullptr,volt_errs);
   graph_volt.SetTitle("2016-06-06_09-12-40_LeakageTest-FoilID_57_Long;Time [s];Volts[V]");

   // Aesthetics of graph_volt
   graph_volt.SetMarkerStyle(1);
   graph_volt.SetMarkerColor(kBlue);
   graph_volt.SetLineColor(kBlue);

   graph_volt.DrawClone("APE");
   c1->Update();


   // Instance of the second graph, for the current values
   TGraphErrors graph_curr(n_lines,time_vals,curr_vals,nullptr,curr_errs);

   // Aesthetics of graph_curr
   graph_curr.SetMarkerStyle(1);
   graph_curr.SetMarkerColor(kRed);
   graph_curr.SetLineColor(kRed);

   //scale hint1 to the pad coordinates
   Float_t rightmax = 1.20;
   Double_t xx, yy;
   Double_t scale = 100;

   for (Int_t i=0;  i<graph_curr.GetN();  i++) {
      graph_curr.GetPoint(i, xx, yy);
      graph_curr.SetPoint(i, xx, yy*scale);
   }

   graph_curr.Draw("same");

   //draw an axis on the right side
   TGaxis *axis = new TGaxis(gPad->GetUxmax(),gPad->GetUymin(),
         gPad->GetUxmax(), gPad->GetUymax(),0,rightmax,510,"+L");
   axis->SetLineColor(kRed);
   axis->SetLabelColor(kRed);
   axis->Draw();
}

Hi,
att. the modified macro:

  • the TGraphErrors are now on heap so they dont
    disappear when the macro exits (dont need DrawClone)

  • the maximum of the extra axis must correspond
    to the scale applied to the 2nd TGraph

  • set minimum of the first graph = 0

  • the y error bars must be scaled too

  • the macro runs as it is with the att example.dat

Cheers
Otto

PS:
In may previous post unfortunately the little word “not” was missing
It should read:
“adding a second TGaxis does n o t influence the coordinatesystem of the TPad”
example.dat (85 Bytes)
extra_axis.C (2.99 KB)

Hi otto,

Thank you so much for your help, I rearranged the scale for my .dat files and the plot is absolutely what I needed. I will make sure to read and understand the improved code you sent me.

Thanks again. Cheers !