Beispiel #1
0
Int_t Doinc1DToF(){

  for (int i = 1; i<11; i++)
    {
      findHisto(i);
    }
  return 0;
}
Beispiel #2
0
unsigned assignHistos2Multipad(canvasSet_t& cs) // returns total number of occupied pads
{
  wCanvas_t *wc0       = cs.canvases[0];
  unsigned npadspercan = wc0->npadsx*wc0->npadsy;
  unsigned npadsall    = cs.ncanvases*npadspercan;

  // Note: wci can't be wCanvas_t& because apparently filling the
  //       vector messes up the reference to the first element!
  //
  wCanvas_t wci(*wc0); // doesn't copy member "pads"
  wCanvas_t *wc = wc0;  // Divvy up the pads among multiple canvases if so specified

  unsigned ipad=0,ipad2start=0; // ipad=global pad index, not the Apple product!
  unsigned m=0;                 // m=multipad index

  // A multipad potentially references multiple sets of graphical
  // objects (histograms, graphs) to overlay. The objects within a set
  // are plotted in sequential pads, but another set of objects
  // assigned to the same multipad are overlaid sequentially on the
  // previous set. Ideally each set assigned to the same multipad
  // contains the same number of objects, but not necessarily.
  // Multiple multipads can exist; their collection of object sets are
  // assigned sequentially to ranges of available pads defined in the
  // layout section.
  //
  for (m=0; m<wc0->multipads.size(); m++) {
    wPad_t  *mp = wc0->multipads[m];

    // figure out how many pads this multipad spans, taking max of the referenced histo sets
    unsigned npads4mp=0;
    for (unsigned k=0; k<mp->histo_ids.size(); k++) {
      std::map<string,unsigned>::const_iterator it=glmap_mhid2size.find(mp->histo_ids[k]);
      if (it==glmap_mhid2size.end()) {
	if (findHisto(mp->histo_ids[k]),"")
	  npads4mp = std::max<unsigned>(npads4mp, 1);
      } else {
	npads4mp = std::max(npads4mp,it->second);
      }
    }

    npads4mp = std::min(npads4mp,npadsall-ipad2start);

    if (!npads4mp) continue;

    // Plot all objects for this multipad that can be plotted within
    // the span of assigned pads

    // Create the pads first
    for (ipad=ipad2start; ipad<ipad2start+npads4mp; ipad++) {

      unsigned   i  =  ipad % npadspercan;      // index to current pad in canvas
      unsigned cnum = (ipad / npadspercan) + 1; // current canvas number

      if (!i) { // first pad in new canvas
	if (cnum > cs.canvases.size()) {
	  if (gl_verbose)
	    cout << "making new canvas" << endl;
	  wc = new wCanvas_t(wci);
	  cs.canvases.push_back(wc);
	  wc->title = cs.title + "_" + int2str(cnum);
	  wc->pads.clear();
	  wc->latex_ids = wc0->latex_ids;
	}
      }

      wPad_t *wp = new wPad_t(*(mp));
      wp->histo_ids.clear(); 
      wp->altyh_ids.clear(); 
      wp->graph_ids.clear(); 
      if (i) wp->legid.clear(); // don't automatically propagate legend to all pads

      wc->pads.push_back(wp);
    }

    unsigned g,h,j,k,l,y;     /* g=graph index in current graph set
				 h=histo index in current histo set
				 j=graph id (set) index
				 k=histo_id (set) index
				 l=altyhisto index
				 y=histoindex in current altyhisto set */
    g=h=j=k=l=y=0;

    // Now assign
    for (ipad=ipad2start; ipad<ipad2start+npads4mp; ipad++) {

      unsigned   i  =  ipad % npadspercan;      // index to current pad in canvas
      unsigned cnum = (ipad / npadspercan) + 1; // current canvas number

      wc = cs.canvases[cnum-1];
      wPad_t *wp = wc->pads[i];

      bool foundhisto=false;
      if (k < mp->histo_ids.size()) {
	string hid=mp->histo_ids[k];

	if (!h && gl_verbose) {
	  cout<<"Assigning histo/histo set "<<hid<<" to pads ";
	  cout<<ipad2start<<"-"<<ipad2start+npads4mp-1<<endl;
	}

	if (!h && findHisto(hid, "switching to histo set"))
	  foundhisto=true;
	else {
	  hid = hid +"_"+int2str(h++);
	  if (findHisto(hid, "hit the end of histo set"))
	    foundhisto=true;
	}
	if (foundhisto) {
	  // now we associate histogram sets with the pad set
	  wp->histo_ids.push_back(hid);
	}
      }

      // altyhistos:
      if (l < mp->altyh_ids.size()) {
	string ahid=mp->altyh_ids[l];
	bool foundaltyh=false;
	if (!y && findHisto(ahid, "switching to set"))
	  foundaltyh=true;
	else {
	  ahid = ahid +"_"+int2str(y++);
	  if (findHisto(ahid, "hit the end of histo set"))
	    foundaltyh=true;
	}
	if (foundaltyh) {
	  // now we associate histogram sets with the pad set
	  wp->altyh_ids.push_back(ahid);
	}
      }

      // graphs:
      bool foundgraph=false;
      if (j < mp->graph_ids.size()) {
	string gid=mp->graph_ids[j];
	if (!g && findGraph(gid, "switching to set"))
	  foundhisto=true;
	else {
	  gid = gid +"_"+int2str(g++);
	  if (findGraph(gid, "hit the end of graph set"))
	    foundgraph=true;
	}
	if (foundgraph) {
	  // now we associate histogram sets with the pad set
	  wp->graph_ids.push_back(gid);
	}
      }

      if (!foundgraph && !foundhisto) { // reset to next graph/histo ids
	ipad=ipad2start;
	g=h=y=0;
	++j;  ++k; ++l;
	if (j == mp->graph_ids.size() &&
	    k == mp->histo_ids.size()   ) break;
      }
    } // pad loop

    ipad2start += npads4mp;

  } // multipads loop

  return std::min(npadsall,ipad);
}                                               // assignHistos2Multipad
Beispiel #3
0
bool                              // returns true if success
processGraphSection(FILE *fp,
		    string& theline,
		    bool& new_section)
{
  vector<string> v_tokens;
  TString  title;
  string   *gid  = NULL;
  TVectorD vx,vy,vz,exl,exh,eyl,eyh;
  float xoffset=0.0,yoffset=0.0, yscale=1.0;
  float xmin=0.,xmax=0.,ymin=0.,ymax=0.,zmin=0.,zmax=0.;
  bool asymerrors = false;
  bool printvecs  = false;
  wGraph_t wg;                                    // placeholder for read-in values
  vector<std::pair<string, wGraph_t *> > v_graphs;

  char xheader[80],yheader[80];
  xheader[0]=0;
  yheader[0]=0;

  if (gl_verbose) cout << "Processing graph section" << endl;

  new_section=false;

  while (getLine(fp,theline,"graph")) {
    if (!theline.size()) continue;
    if (theline[0] == '#') continue; // comments are welcome

    if (theline[0] == '[') {
      new_section=true;
      break;
    }

    string key, value;
    if (!getKeyValue(theline,key,value)) continue;

    //--------------------
    if (key == "id") {
    //--------------------
      if (gid != NULL) {
	cerr << "no more than one id per graph section allowed " << value << endl;
	break;
      }

      gid = new string(value);

    //------------------------------
    } else if (key == "vectorfile") {
    //------------------------------
      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      string path     = value;
      string scanspec = asymerrors ?  "%lf %lf %lf %lf" : "%lf %lf";

      Tokenize(value,v_tokens,",");
      if (v_tokens.size() > 1) {
	path     = v_tokens[0];
	scanspec = v_tokens[1];
      }

      if (v_graphs.size()) {
	cerr << "graph(s) already defined" << endl; continue;
      }
      if (inSet<string>(glset_graphFilesReadIn,path)) {
	cerr << "vector file " << path << " already read in" << endl; break;
      }

      wGraph_t *pwg = new wGraph_t();

      if (asymerrors)
	loadVectorsFromFile(path.c_str(),scanspec.c_str(),vx,vy,exl,exh,eyl,eyh);
      else
	loadVectorsFromFile(path.c_str(),scanspec.c_str(),vx,vy,xheader,yheader);

      if (strlen(xheader)) pwg->xax->SetTitle(xheader);
      if (strlen(yheader)) pwg->yax->SetTitle(yheader);

      v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));

      // pend filling the graph until all parameters are read in

    //------------------------------
    } else if (key == "vectorfile2d") {
    //------------------------------
      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph(s) already defined" << endl; continue;
      }

      Tokenize(value,v_tokens,",");

      string path=v_tokens[0];
      if (inSet<string>(glset_graphFilesReadIn,path)) {
	cerr << "vector file " << path << " already read in" << endl; break;
      }

      wGraph_t *pwg = new wGraph_t();

      switch(v_tokens.size()) {
      case 1:  pwg->gr2d = new TGraph2D(path.c_str()); break;
      case 2:  pwg->gr2d = new TGraph2D(path.c_str(),v_tokens[1].c_str()); break;
      case 3:  pwg->gr2d = new TGraph2D(path.c_str(),v_tokens[1].c_str(),v_tokens[2].c_str()); break;
      default:
	cerr << "malformed vectorfile2d spec path[,format[,option]] " << value << endl;
	break;
      }

      if (pwg->gr2d->IsZombie()) {
	cerr << "Unable to make Graph2D from file " << path << endl;
	exit(-1);
      }
      pwg->gr2d->SetName(gid->c_str());

      v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));

    //------------------------------
    } else if (key == "path") {
    //------------------------------

      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph already defined" << endl; continue;
      }
      wGraph_t *pwg = new wGraph_t();
      pwg->gr  = getGraphFromSpec(*gid,value);
      if (!pwg->gr) continue;

      v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));

    //------------------------------
    } else if (key == "clone") {
    //------------------------------

      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph already defined" << endl; continue;
      }
      map<string,wGraph_t *>::const_iterator it = glmap_id2graph.find(value);
      if( it == glmap_id2graph.end() ) {
	cerr << "Graph ID " << value << " not found,";
	cerr << "clone must be defined after the clonee" << endl;
	break;
      }
      wGraph_t *pwg  = new wGraph_t(*(it->second),*gid);

      v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));

    //------------------------------
    } else if( key == "fromhisto" ) { // converts TH1 to TGraph
    //------------------------------
      if( !gid ) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph(s) already defined" << endl; continue;
      }
      // look for multihist with this identifier
      std::map<string,unsigned>::const_iterator it=glmap_mhid2size.find(value);
      if (it!=glmap_mhid2size.end()) {
	for (size_t i=0; i<it->second; i++) {
	  string hidi=value+int2str(i);
	  TH1 *h = (TH1 *)findHisto(hidi,"");
	  assert(h);
	  wGraph_t *pwg = new wGraph_t();
	  pwg->gr = new TGraph(h);
	  v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));
	}
      } else {
	TH1 *h = (TH1 *)findHisto(value);
	assert(h);
	wGraph_t *pwg = new wGraph_t();
	pwg->gr = new TGraph(h);
	v_graphs.push_back(pair<string,wGraph_t *>(*gid,pwg));
      }

    //------------------------------
    } else if( key == "fillfromtree" ) { // converts tree array variables into a group of graphs
    //------------------------------
      if( !gid ) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (v_graphs.size()) {
	cerr << "graph(s) already defined" << endl; continue;
      }

      Tokenize(value,v_tokens,";");
      string treedrawspec=v_tokens[0];

      int ifirst=-1,ilast=-1;
      if (v_tokens.size() == 2) {
	string range=v_tokens[1];
	Tokenize(range,v_tokens,"-");
	if (v_tokens.size()==2) {
	  ifirst=str2int(v_tokens[0]);
	  ilast =str2int(v_tokens[1]);
	}
      }
      //cout << v_tokens.size() << " " << ifirst << " " << ilast << endl;
      if (ifirst>0 && 
	  ilast>=ifirst ) {
	for (int i=ifirst; i<=ilast; i++) {
	  wGraph_t *pwg = NULL;

	  // defined in spTree.C
	  void fillGraphFromTreeVar(std::string& drawspec,int index,wGraph_t *&pwg);
	  fillGraphFromTreeVar(treedrawspec,i,pwg);
	  assert(pwg);
	  string gidi= (*gid)+"_"+int2str(i-ifirst);
	  v_graphs.push_back(std::pair<string,wGraph_t *>(gidi,pwg));
	}

	glmap_mgid2size.insert(pair<string,unsigned>(*gid,v_graphs.size()));
      } else {
	wGraph_t *pwg = NULL;
	void fillGraphFromTreeVar(std::string& drawspec,int index,wGraph_t *&pwg);
	fillGraphFromTreeVar(treedrawspec,0,pwg);
	assert(pwg);
	v_graphs.push_back(std::pair<string,wGraph_t *>(*gid,pwg));
	glmap_mgid2size.insert(pair<string,unsigned>(*gid,v_graphs.size()));
      }

    //------------------------------
    } else if (key == "bayesdiv") {
    //------------------------------

      Tokenize(value,v_tokens,",/"); // either comma-separated or using '/'
      if (v_tokens.size() != 2) {
	cerr << "expect comma-separated list of exactly two histo specs to divide! ";
	cerr << theline << endl;
	continue;
      }

      TH1 *tmph1 = (TH1 *)findHisto(v_tokens[0]); if (!tmph1) exit(-1);
      TH1 *tmph2 = (TH1 *)findHisto(v_tokens[1]); if (!tmph2) exit(-1);

      cout << tmph1->GetNbinsX() << " " << tmph2->GetNbinsX() << endl;

      wGraph_t *pwg = new wGraph_t();

      if ( gl_verbose ) { 
	std::cout << "Dump of bin contents, errors" << std::endl ; 
	if ( tmph1->GetNbinsX() == tmph2->GetNbinsX() ) { 
	  for (int ib=1; ib<=tmph1->GetNbinsX(); ib++) {
	    std::cout << ib << ": " << tmph1->GetBinContent(ib) << "+/-" << tmph1->GetBinError(ib) 
		      << ", " << tmph2->GetBinContent(ib) << "+/-" << tmph2->GetBinError(ib) << std::endl ; 
	  }
	} else { 
	  cerr << "Histograms being divided do not have same number of bins!!!" << endl ; 
	}
      }

      // equivalent to BayesDivide
      //
      if (gl_verbose) pwg->gr = new TGraphAsymmErrors(tmph1,tmph2,"debug");
      else            pwg->gr = new TGraphAsymmErrors(tmph1,tmph2,"");
      //if (gl_verbose) pwg->gr = new TGraphAsymmErrors(tmph1,tmph2,"cl=0.683 b(1,1) mode v");
      //else            pwg->gr = new TGraphAsymmErrors(tmph1,tmph2,"cl=0.683 b(1,1) mode");
      if (!pwg->gr) {
	cerr << "BayesDivide didn't work! wonder why..." << endl;
	continue;
      } else if (gl_verbose) {
	cout << pwg->gr->GetN() << " points in the graph" << endl;
      }

      // Fix in case something broke

      for (int i=0; i<pwg->gr->GetN(); i++) {
          if ( pwg->gr->GetErrorYhigh(i) == 0. || pwg->gr->GetErrorYlow(i) == 0 ) { // Something bad happened
              if ( gl_verbose ) std::cout << "Problem with Bayes divide, checking..." << std::endl ;
              double pass  = tmph1->GetBinContent(i+1) ; 
              double total = tmph2->GetBinContent(i+1) ;
              if ( gl_verbose ) std::cout << pass << "/" << total << std::endl ;
              if ( pass == total ) {
                  if ( gl_verbose ) std::cout << "Everything OK" << std::endl ;
              } else { 
                  if ( gl_verbose ) std::cout << "Yep, something is broken" << std::endl ;
                  double xval, yval ;
                  pwg->gr->GetPoint(i,xval,yval) ;
                  yval = pass / total ;
                  // Use simplified efficiency assumption
                  // double u1 = tmph1->GetBinError(i+1) / tmph1->GetBinContent(i+1) ; 
                  // double u2 = tmph2->GetBinError(i+1) / tmph2->GetBinContent(i+1) ; 
                  // double unc = yval * sqrt( u1*u1 + u2*u2 ) ; 
                  double unc = sqrt( yval * (1.-yval)/tmph2->GetBinContent(i+1) ) ; 
                  double uhi = ( (yval + unc > 1.)?(1.-yval):(unc) ) ; 
                  double ulo = ( (yval - unc < 0.)?(yval):(unc) ) ;
                  pwg->gr->SetPoint(i,xval,yval) ;
                  ((TGraphAsymmErrors*)pwg->gr)->SetPointError(i,pwg->gr->GetErrorXlow(i),pwg->gr->GetErrorXhigh(i),ulo,uhi) ; 
//                   pwg->gr->SetPointEYhigh(i,uhi) ; 
//                   pwg->gr->SetPointEYlow(i,ulo) ; 
              }
          }   
          if (gl_verbose) std::cout << i << ": " << pwg->gr->GetErrorYhigh(i) << "/" << pwg->gr->GetErrorYlow(i) << std::endl ; 
      }

    } else if (!v_graphs.size()) {
      cerr<<"One of keys path,clone,vectorfile,vectorfile2d or bayesdiv must be defined before key..."<<key<<endl;
    } else {
      if     ( key == "xoffset" )      xoffset   = str2flt(value);
      else if( key == "yoffset" )      yoffset   = str2flt(value);
      else if( key == "yscale" )       yscale    = str2flt(value);
      else if( key == "title"  )       title     = TString(value);
      else if( key == "xtitle" )       wg.xax->SetTitle      (TString(value));
      else if( key == "ytitle" )       wg.yax->SetTitle      (TString(value));
      else if( key == "ztitle" )       wg.zax->SetTitle      (TString(value));
      else if( key == "xtitleoffset" ) wg.xax->SetTitleOffset(str2flt(value));
      else if( key == "ytitleoffset" ) wg.yax->SetTitleOffset(str2flt(value));
      else if( key == "ztitleoffset" ) wg.zax->SetTitleOffset(str2flt(value));
      else if( key == "xndiv" )        wg.xax->SetNdivisions (str2int(value));
      else if( key == "yndiv" )        wg.yax->SetNdivisions (str2int(value));
      else if( key == "zndiv" )        wg.zax->SetNdivisions (str2int(value));
      else if( key == "xmin" )         xmin         = str2flt(value);
      else if( key == "xmax" )         xmax         = str2flt(value);
      else if( key == "ymin" )         ymin         = str2flt(value);
      else if( key == "ymax" )         ymax         = str2flt(value);
      else if( key == "zmin" )         zmin         = str2flt(value);
      else if( key == "zmax" )         zmax         = str2flt(value);
      else if( key == "linecolor" )    wg.lcolor    = str2int(value);
      else if( key == "linestyle" )    wg.lstyle    = str2int(value);
      else if( key == "linewidth" )    wg.lwidth    = str2int(value);
      else if( key == "markercolor" )  wg.mcolor    = str2int(value);
      else if( key == "markerstyle" )  wg.mstyle    = str2int(value);
      else if( key == "markersize"  )  wg.msize     = str2int(value);
      else if( key == "fillcolor" )    wg.fcolor    = str2int(value);
      else if( key == "fillstyle" )    wg.fstyle    = str2int(value);
      else if( key == "asymerrors" )   asymerrors   = (bool)str2int(value);
      else if( key == "leglabel" )     wg.leglabel  = value;
      else if( key == "draw" )         wg.drawopt   = value;
      else if( key == "legdraw" )      wg.legdrawopt= value;
      else if( key == "setprecision" ) cout << setprecision(str2int(value));
      else if( key == "printvecs2file") printvecs = true;
      else if( key == "fittf1" ) {
	TF1 *tf1 = findTF1(value);
	if( !tf1 ) {
	  cerr << "TF1 " << value << " must be defined first" << endl;
	  continue;
	}
	string funcnewname = value+(*gid);
	wg.fitfn = new TF1(*tf1);
	wg.fitfn->SetName(funcnewname.c_str());
      }
      else if ( key == "contours" ) {
	Tokenize(value,v_tokens,",");
	wg.contours = new TVectorD(v_tokens.size());
	for (size_t i=0; i<v_tokens.size(); i++)
	  wg.contours[i] = str2flt(v_tokens[i]);
      }
      else {
	cerr << "unknown key " << key << endl;
      }
#if 0
      processCommonHistoParams(key,value,*wh);
#endif
    }
  } // getline loop

  //cout << title << endl;

  for (size_t i=0; i<v_graphs.size(); i++) {
    string gidi = v_graphs[i].first;
    wGraph_t *pwg = v_graphs[i].second;
    if (pwg->gr2d) {
      pwg->gr2d->SetTitle(title);
      pwg->gr2d->SetLineStyle   (wg.lstyle);
      pwg->gr2d->SetLineColor   (wg.lcolor);
      pwg->gr2d->SetLineWidth   (wg.lwidth);
      pwg->gr2d->SetMarkerColor (wg.mcolor);
      pwg->gr2d->SetMarkerStyle (wg.mstyle);
      pwg->gr2d->SetMarkerSize  (wg.msize);
      pwg->gr2d->SetFillStyle   (wg.fstyle);
      pwg->gr2d->SetFillColor   (wg.fcolor);
      if (zmax>zmin)  
	pwg->zax->SetLimits(zmin,zmax);
    } else {
      if (vx.GetNoElements()) { // load utility guarantees the same size for both
	if (yscale  != 1.0) vy *= yscale;
	if (xoffset != 0.0) vx += xoffset;
	if (yoffset != 0.0) vy += yoffset;
	if (asymerrors) 
	  pwg->gr = new TGraphAsymmErrors(vx,vy,exl,exh,eyl,eyh);
	else
	  pwg->gr = new TGraph(vx,vy);
      }
      pwg->gr->UseCurrentStyle();
      pwg->fitfn      =        wg.fitfn;
      pwg->contours   =        wg.contours;
      pwg->drawopt    =        wg.drawopt;
      pwg->legdrawopt =        wg.legdrawopt;
      pwg->gr->SetTitle       (title);
      pwg->xax->SetTitle      (wg.xax->GetTitle());
      pwg->yax->SetTitle      (wg.yax->GetTitle());
      pwg->zax->SetTitle      (wg.zax->GetTitle());
      pwg->xax->SetTitleOffset(wg.xax->GetTitleOffset());
      pwg->yax->SetTitleOffset(wg.yax->GetTitleOffset());
      pwg->zax->SetTitleOffset(wg.zax->GetTitleOffset());
      pwg->xax->SetNdivisions (wg.xax->GetNdivisions());
      pwg->yax->SetNdivisions (wg.yax->GetNdivisions());
      pwg->zax->SetNdivisions (wg.zax->GetNdivisions());
      pwg->gr->SetLineStyle   (wg.lstyle);
      pwg->gr->SetLineColor   (wg.lcolor);
      pwg->gr->SetLineWidth   (wg.lwidth);
      pwg->gr->SetMarkerColor (wg.mcolor);
      pwg->gr->SetMarkerStyle (wg.mstyle);
      pwg->gr->SetMarkerSize  (wg.msize);
      pwg->gr->SetFillStyle   (wg.fstyle);
      pwg->gr->SetFillColor   (wg.fcolor);

      if (xmax>xmin) pwg->xax->SetLimits(xmin,xmax);
      if (ymax>ymin) pwg->yax->SetLimits(ymin,ymax);

      glmap_id2graph.insert(pair<string,wGraph_t *>(gidi,pwg));

      if (printvecs) printVectorsToFile(pwg); // ,value);
    }
  }

  return (v_graphs.size());
}                                                 // processGraphSection
Beispiel #4
0
bool                              // returns true if success
processMultiGraphSection(FILE *fp,
			 string& theline,
			 bool& new_section)
{
  vector<string> v_tokens;
  TString  title;
  string   *gid  = NULL;
  TVectorD vx,vy,vz,exl,exh,eyl,eyh;
  float xoffset=0.0,yoffset=0.0, yscale=1.0;
  float xmin=0.,xmax=0.,ymin=0.,ymax=0.,zmin=0.,zmax=0.;
  bool asymerrors = false;
  wGraph_t *wg = NULL;

  char xheader[80],yheader[80];
  xheader[0]=0;
  yheader[0]=0;

  if (gl_verbose) cout << "Processing multigraph section" << endl;

  new_section=false;

  while (getLine(fp,theline,"multigraph")) {
    if (!theline.size()) continue;
    if (theline[0] == '#') continue; // comments are welcome

    if (theline[0] == '[') {
      new_section=true;
      break;
    }

    string key, value;
    if (!getKeyValue(theline,key,value)) continue;

    //--------------------
    if (key == "id") {
    //--------------------
      if (gid != NULL) {
	cerr << "no more than one id per section allowed " << value << endl;
	break;
      }

      gid = new string(value);

    //------------------------------
    } else if (key == "graphs") {
    //------------------------------
      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }

      Tokenize(value,v_tokens,","); 

      for (size_t i=0; i<v_tokens.size(); i++) {
	map<string,wGraph_t *>::const_iterator it = glmap_id2graph.find(v_tokens[i]);
	if( it == glmap_id2graph.end() ) {
	  cerr << "Graph ID " << v_tokens[i] << " not found,";
	  cerr << "graphs must be defined before multigraph section" << endl;
	  break;
	}
	wg  = new wGraph_t(*(it->second),*gid);
	
      }
      if (wg) {
	cerr << "graph already defined" << endl; continue;
      }
      if (inSet<string>(glset_graphFilesReadIn,path)) {
	cerr << "vector file " << path << " already read in" << endl; break;
      }

      wg = new wGraph_t();

      if (asymerrors)
	loadVectorsFromFile(path.c_str(),scanspec.c_str(),vx,vy,exl,exh,eyl,eyh);
      else
	loadVectorsFromFile(path.c_str(),scanspec.c_str(),vx,vy,xheader,yheader);

      if (strlen(xheader)) wg->xax->SetTitle(xheader);
      if (strlen(yheader)) wg->yax->SetTitle(yheader);

    //------------------------------
    } else if (key == "vectorfile2d") {
    //------------------------------
      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      string path = value;
      if (wg) {
	cerr << "graph already defined" << endl; continue;
      }
      if (inSet<string>(glset_graphFilesReadIn,path)) {
	cerr << "vector file " << path << " already read in" << endl; break;
      }

      wg = new wGraph_t();

      wg->gr2d = new TGraph2D(path.c_str());

      if (wg->gr2d->IsZombie()) {
	cerr << "Unable to make Graph2D from file " << path << endl;
	exit(-1);
      }
      wg->gr2d->SetName(gid->c_str());

    //------------------------------
    } else if (key == "path") {
    //------------------------------

      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (wg) {
	cerr << "graph already defined" << endl; continue;
      }
      wg = new wGraph_t();
      wg->gr  = getGraphFromSpec(*gid,value);
      if (!wg->gr) continue;

    //------------------------------
    } else if (key == "clone") {
    //------------------------------

      if (!gid) {
	cerr << "id key must be defined first in the section" << endl; continue;
      }
      if (wg) {
	cerr << "graph already defined" << endl; continue;
      }
      map<string,wGraph_t *>::const_iterator it = glmap_id2graph.find(value);
      if( it == glmap_id2graph.end() ) {
	cerr << "Graph ID " << value << " not found,";
	cerr << "clone must be defined after the clonee" << endl;
	break;
      }
      wg  = new wGraph_t(*(it->second),*gid);

    //------------------------------
    } else if (key == "bayesdiv") {
    //------------------------------

      Tokenize(value,v_tokens,",/"); // either comma-separated or using '/'
      if (v_tokens.size() != 2) {
	cerr << "expect comma-separated list of exactly two histo specs to divide! ";
	cerr << theline << endl;
	continue;
      }

      TH1 *tmph1 = (TH1 *)findHisto(v_tokens[0]); if (!tmph1) exit(-1);
      TH1 *tmph2 = (TH1 *)findHisto(v_tokens[1]); if (!tmph2) exit(-1);

      cout << tmph1->GetNbinsX() << " " << tmph2->GetNbinsX() << endl;

      wg = new wGraph_t();

      // equivalent to BayesDivide
      //
      if (gl_verbose) wg->gr = new TGraphAsymmErrors(tmph1,tmph2,"debug");
      else            wg->gr = new TGraphAsymmErrors(tmph1,tmph2,"");
      //if (gl_verbose) wg->gr = new TGraphAsymmErrors(tmph1,tmph2,"cl=0.683 b(1,1) mode v");
      //else            wg->gr = new TGraphAsymmErrors(tmph1,tmph2,"cl=0.683 b(1,1) mode");
      if (!wg->gr) {
	cerr << "BayesDivide didn't work! wonder why..." << endl;
	continue;
      } else if (gl_verbose) {
	cout << wg->gr->GetN() << " points in the graph" << endl;
      }

    } else if (!wg) {
      cerr<<"One of keys path,clone,vectorfile,vectorfile2d or bayesdiv must be defined before key..."<<key<<endl;
    } else {
      if     ( key == "xoffset" )      xoffset   = str2flt(value);
      else if( key == "yoffset" )      yoffset   = str2flt(value);
      else if( key == "yscale" )       yscale    = str2flt(value);
      else if( key == "title"  )       title     = TString(value);
      else if( key == "xtitle" )       wg->xax->SetTitle(value.c_str());
      else if( key == "ytitle" )       wg->yax->SetTitle(value.c_str());
      else if( key == "ztitle" )       wg->zax->SetTitle(value.c_str());
      else if( key == "xtitleoffset" ) wg->xax->SetTitleOffset(str2flt(value));
      else if( key == "ytitleoffset" ) wg->yax->SetTitleOffset(str2flt(value));
      else if( key == "ztitleoffset" ) wg->zax->SetTitleOffset(str2flt(value));
      else if( key == "xmin" )         xmin      = str2flt(value);
      else if( key == "xmax" )         xmax      = str2flt(value);
      else if( key == "ymin" )         ymin      = str2flt(value);
      else if( key == "ymax" )         ymax      = str2flt(value);
      else if( key == "zmin" )         zmin      = str2flt(value);
      else if( key == "zmax" )         zmax      = str2flt(value);
      else if( key == "linecolor" )    wg->lcolor  = str2int(value);
      else if( key == "linestyle" )    wg->lstyle  = str2int(value);
      else if( key == "linewidth" )    wg->lwidth  = str2int(value);
      else if( key == "markercolor" )  wg->mcolor  = str2int(value);
      else if( key == "markerstyle" )  wg->mstyle  = str2int(value);
      else if( key == "markersize"  )  wg->msize   = str2int(value);
      else if( key == "fillcolor" )    wg->fcolor  = str2int(value);
      else if( key == "fillstyle" )    wg->fstyle  = str2int(value);
      else if( key == "xndiv" )        wg->xax->SetNdivisions(str2int(value));
      else if( key == "yndiv" )        wg->yax->SetNdivisions(str2int(value));
      else if( key == "asymerrors" )   asymerrors  = (bool)str2int(value);
      else if( key == "leglabel" )     wg->leglabel   = value;
      else if( key == "draw" )         wg->drawopt    = value;
      else if( key == "legdraw" )      wg->legdrawopt = value;
      else if( key == "setprecision" ) cout << setprecision(str2int(value));
      else if( key == "printvecs2file") printVectorsToFile(wg); // ,value);
      else if( key == "fittf1" ) {
	TF1 *tf1 = findTF1(value);
	if( !tf1 ) {
	  cerr << "TF1 " << value << " must be defined first" << endl;
	  continue;
	}
	string funcnewname = value+(*gid);
	wg->fitfn = new TF1(*tf1);
	wg->fitfn->SetName(funcnewname.c_str());
      }
      else if ( key == "contours" ) {
	Tokenize(value,v_tokens,",");
	wg->contours = new TVectorD(v_tokens.size());
	for (size_t i=0; i<v_tokens.size(); i++)
	  wg->contours[i] = str2flt(v_tokens[i]);
      }
      else {
	cerr << "unknown key " << key << endl;
      }
#if 0
      processCommonHistoParams(key,value,*wh);
#endif
    }
  }

  //cout << title << endl;
  if (wg->gr2d) {
    wg->gr2d->SetTitle(title);
    wg->gr2d->SetLineStyle   (wg->lstyle);
    wg->gr2d->SetLineColor   (wg->lcolor);
    wg->gr2d->SetLineWidth   (wg->lwidth);
    wg->gr2d->SetMarkerColor (wg->mcolor);
    wg->gr2d->SetMarkerStyle (wg->mstyle);
    wg->gr2d->SetMarkerSize  (wg->msize);
    wg->gr2d->SetFillStyle   (wg->fstyle);
    wg->gr2d->SetFillColor   (wg->fcolor);
    if (zmax>zmin)  
      wg->zax->SetLimits(zmin,zmax);
  } else {
    if (vx.GetNoElements()) { // load utility guarantees the same size for both
      if (yscale  != 1.0) vy *= yscale;
      if (xoffset != 0.0) vx += xoffset;
      if (yoffset != 0.0) vy += yoffset;
      if (asymerrors) 
	wg->gr = new TGraphAsymmErrors(vx,vy,exl,exh,eyl,eyh);
      else
	wg->gr = new TGraph(vx,vy);
    }
    wg->gr->UseCurrentStyle();
    wg->gr->SetTitle(title);
    wg->gr->SetLineStyle   (wg->lstyle);
    wg->gr->SetLineColor   (wg->lcolor);
    wg->gr->SetLineWidth   (wg->lwidth);
    wg->gr->SetMarkerColor (wg->mcolor);
    wg->gr->SetMarkerStyle (wg->mstyle);
    wg->gr->SetMarkerSize  (wg->msize);
    wg->gr->SetFillStyle   (wg->fstyle);
    wg->gr->SetFillColor   (wg->fcolor);

    if (xmax>xmin) wg->xax->SetLimits(xmin,xmax);
    if (ymax>ymin) wg->yax->SetLimits(ymin,ymax);
  }

  glmap_id2graph.insert(pair<string,wGraph_t *>(*gid,wg));

  return (wg != NULL);
}                                                 // processGraphSection