CERN ROOT: Is is possible to plot pairs of x-y data points?
Asked Answered
T

3

4

I would like to use CERN ROOT to draw a 2d graph of pairs of x-y datapoints possibly also with y-errorbars. However I only know how to draw histograms.

Is this possible with CERN ROOT? If so how?

Also I realize that there may be better libraries for doing this. I have been using GNUPlot, but unfortunately I can't seem to integrate it well with my C++ code, since I can't find a C/C++ GNUPlot interface which covers all the features and allows me to send data in a bidirectional manner - ie: both to and from GNUPlot.

If you have a better alternative suggestion then that would be most welcome.

Traverse answered 27/7, 2015 at 13:28 Comment(1)
Have you tried TGraphErrors? root.cern.ch/root/html/TGraphErrors.htmlVandusen
S
2

There is gnuplot iostream to send data from c++ to gnuplot. Within root, you can use (as suggested by the others) TGraph, TGraphErrors, TGraphAsymErrors.

EDIT:

the gnuplot iostream example from its homepage looks like this. Means once you have your data points either as one vector of tuples or as several vectors of floats, you can send them to gnuplot.

#include <vector>
#include <cmath>
#include <boost/tuple/tuple.hpp>

#include "gnuplot-iostream.h"

int main() {
    Gnuplot gp;
    // Create a script which can be manually fed into gnuplot later:
    //    Gnuplot gp(">script.gp");
    // Create script and also feed to gnuplot:
    //    Gnuplot gp("tee plot.gp | gnuplot -persist");
    // Or choose any of those options at runtime by setting the GNUPLOT_IOSTREAM_CMD
    // environment variable.

    // Gnuplot vectors (i.e. arrows) require four columns: (x,y,dx,dy)
    std::vector<boost::tuple<double, double, double, double> > pts_A;

    // You can also use a separate container for each column, like so:
    std::vector<double> pts_B_x;
    std::vector<double> pts_B_y;
    std::vector<double> pts_B_dx;
    std::vector<double> pts_B_dy;

    // You could also use:
    //   std::vector<std::vector<double> >
    //   boost::tuple of four std::vector's
    //   std::vector of std::tuple (if you have C++11)
    //   arma::mat (with the Armadillo library)
    //   blitz::Array<blitz::TinyVector<double, 4>, 1> (with the Blitz++ library)
    // ... or anything of that sort

    for(double alpha=0; alpha<1; alpha+=1.0/24.0) {
        double theta = alpha*2.0*3.14159;
        pts_A.push_back(boost::make_tuple(
             cos(theta),
             sin(theta),
            -cos(theta)*0.1,
            -sin(theta)*0.1
        ));

        pts_B_x .push_back( cos(theta)*0.8);
        pts_B_y .push_back( sin(theta)*0.8);
        pts_B_dx.push_back( sin(theta)*0.1);
        pts_B_dy.push_back(-cos(theta)*0.1);
    }

    // Don't forget to put "\n" at the end of each line!
    gp << "set xrange [-2:2]\nset yrange [-2:2]\n";
    // '-' means read from stdin.  The send1d() function sends data to gnuplot's stdin.
    gp << "plot '-' with vectors title 'pts_A', '-' with vectors title 'pts_B'\n";
    gp.send1d(pts_A);
    gp.send1d(boost::make_tuple(pts_B_x, pts_B_y, pts_B_dx, pts_B_dy));

    return 0;
}
Spin answered 31/3, 2016 at 18:51 Comment(1)
okay, added one of the examples from the gnuplot-iostream webpage.Spin
T
0

Yes it is possible, you can do it like this:

// At program start
TApplication tapp("app", 0, 0); // this is needed for some reason - not ideal

// Later in program
TGraph *tgraph = new TGraph(N, x, y); // data: x,y N points
TCanvas *tcanvas = new TCanvas("tcanvas","canvas title", 200, 10, 800, 600);
tgraph->SetMarkerColor(kBlue);
tgraph->SetMarkerStyle(21);
tgraph->Draw();
tcanvas->Update();

// Wait for user to check if graph is "okay"
std::cin.get();

delete tcanvas;
delete tgraph;

**BUT** This code will NOT work in a loop. The subsequent graphs will be blank. I do not know why.

Traverse answered 28/7, 2015 at 11:24 Comment(0)
M
0

Take a look at this link from the official ROOT page. There is a very nice tutorial on how to use 'TGraph's . Here they even explain how to make a x-y-graph with asymmetrical error-bars.

This is how it works:

   c1 = new TCanvas("c1","A Simple Graph with error bars",
                    200,10,700,500);
   c1->SetGrid();

   // create the arrays for the points
   Int_t n = 10;
   Double_t x[n]  = {-.22,.05,.25,.35,.5, .61,.7,.85,.89,.95};
   Double_t y[n]  = {1,2.9,5.6,7.4,9,9.6,8.7,6.3,4.5,1};

   // create the arrays with high and low errors
   Double_t exl[n] = {.05,.1,.07,.07,.04,.05,.06,.07,.08,.05};
   Double_t eyl[n] = {.8,.7,.6,.5,.4,.4,.5,.6,.7,.8};
   Double_t exh[n] = {.02,.08,.05,.05,.03,.03,.04,.05,.06,.03};
   Double_t eyh[n] = {.6,.5,.4,.3,.2,.2,.3,.4,.5,.6};

   // create TGraphAsymmErrors with the arrays
   gr = new TGraphAsymmErrors(n,x,y,exl,exh,eyl,eyh);
   gr->SetTitle("TGraphAsymmErrors Example");
   gr->SetMarkerColor(4);
   gr->SetMarkerStyle(21);
   gr->Draw("ALP"); 

The constructor has six arrays as parameters: X and Y as TGraph and low X-errors and high X-errors, low Y-errors and high Y-errors. The low value is the length of the error bar to the left and down, the high value is the length of the error bar to the right and up.

Meit answered 24/7, 2023 at 20:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.