]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - PWG2/FORWARD/analysis2/DrawdNdeta.C
Added script to test the energy loss assumptions and
[u/mrichter/AliRoot.git] / PWG2 / FORWARD / analysis2 / DrawdNdeta.C
index ba9d8eace6fdb4fa3cf2918ba830ea8c070de0ed..7883d71739605ddd1dc30f5c0077ef1035323835 100644 (file)
@@ -1,4 +1,20 @@
+/**
+ * @file   DrawdNdeta.C
+ * @author Christian Holm Christensen <cholm@dalsgaard.hehi.nbi.dk>
+ * @date   Wed Mar 23 14:07:10 2011
+ * 
+ * @brief  Script to visualise the dN/deta for pp and PbPb
+ *
+ * This script is independent of any AliROOT code - and should stay
+ * that way.
+ * 
+ * The script is <emph>very</emph> long - sigh - the joy of drawing
+ * things nicely in ROOT
+ * 
+ * @ingroup pwg2_forward_dndeta
+ */
 #include <TH1.h>
+#include <TColor.h>
 #include <THStack.h>
 #include <TGraphErrors.h>
 #include <TGraphAsymmErrors.h>
 #include <TLegendEntry.h>
 #include <TLatex.h>
 #include <TImage.h>
+#include <TRandom.h>
+#include <fstream>
+#define SYSERR_COLOR kBlue-10
+#define SYSERR_STYLE 1001
+
+Double_t myFunc(Double_t* xp, Double_t* pp);
 
 /**
  * Class to draw dN/deta results 
  * 
+ * @ingroup pwg2_forward_tasks_dndeta
+ * @ingroup pwg2_forward_dndeta
  */
 struct dNdetaDrawer 
 {
@@ -41,29 +65,35 @@ struct dNdetaDrawer
    * 
    */
   dNdetaDrawer()
-    : fShowOthers(false),      // Bool_t 
-      fShowAlice(false),        // Bool_t
-      fShowRatios(false),      // Bool_t 
-      fShowLeftRight(false),   // Bool_t
-      fRebin(5),               // UShort_t
-      fCutEdges(false),                // Bool_t
-      fTitle(""),              // TString
-      fHHDFile(""),            // TString
-      fTrigString(0),          // TNamed*
-      fSNNString(0),           // TNamed*
-      fSysString(0),           // TNamed*
-      fVtxAxis(0),             // TAxis*
-      fForward(0),             // TH1*
-      fForwardMC(0),           // TH1*
-      fForwardHHD(0),          // TH1*
-      fTruth(0),               // TH1*
-      fCentral(0),             // TH1*
-      fForwardSym(0),          // TH1*
-      fForwardMCSym(0),                // TH1*
-      fForwardHHDSym(0),       // TH1*
-      fTriggers(0),            // TH1*
-      fRangeParam(0)
-
+    : // Options 
+    fShowRatios(false),    // Show ratios 
+    fShowLeftRight(false), // Show asymmetry 
+    fShowRings(false),     // Show rings too
+    fExport(false),        // Export data to script
+    fCutEdges(false),      // Whether to cut edges
+    fRemoveOuters(false),  // Whether to remove outers
+    fShowOthers(0),        // Show other data
+    // Settings 
+    fRebin(0),             // Rebinning factor 
+    fFwdSysErr(0.076),     // Systematic error in forward range
+    fCenSysErr(0),         // Systematic error in central range 
+    fTitle(""),            // Title on plot
+    fClusterScale(""),     // Scaling of clusters to tracklets      
+    // Read (or set) information 
+    fTrigString(0),        // Trigger string (read, or set)
+    fNormString(0),        // Normalisation string (read, or set)
+    fSNNString(0),         // Energy string (read, or set)
+    fSysString(0),         // Collision system string (read or set)
+    fVtxAxis(0),           // Vertex cuts (read or set)
+    fCentAxis(0),          // Centrality axis
+    // Resulting plots 
+    fResults(0),           // Stack of results 
+    fRatios(0),            // Stack of ratios 
+    fLeftRight(0),         // Left-right asymmetry
+    fOthers(0),            // Older data 
+    fTriggers(0),          // Number of triggers
+    fTruth(0),             // Pointer to truth 
+    fRangeParam(0)         // Parameter object for range zoom 
   {
     fRangeParam = new RangeParam;
     fRangeParam->fMasterAxis = 0;
@@ -72,6 +102,27 @@ struct dNdetaDrawer
     fRangeParam->fSlave2Axis = 0;
     fRangeParam->fSlave2Pad  = 0;
   }
+  dNdetaDrawer(const dNdetaDrawer&) {}
+  dNdetaDrawer& operator=(const dNdetaDrawer&) { return *this; }
+
+  //__________________________________________________________________
+  virtual ~dNdetaDrawer()
+  {
+    if (fRatios  && fRatios->GetHists())  fRatios->GetHists()->Delete();
+    if (fResults && fResults->GetHists()) fResults->GetHists()->Delete();
+
+    if (fTrigString) { delete fTrigString; fTrigString = 0; }
+    if (fSNNString)  { delete fSNNString;  fSNNString  = 0; }
+    if (fSysString)  { delete fSysString;  fSysString  = 0; }
+    if (fVtxAxis)    { delete fVtxAxis;    fVtxAxis    = 0; }
+    if (fCentAxis)   { delete fCentAxis;   fCentAxis   = 0; }
+    if (fResults)    { delete fResults;    fResults    = 0; }
+    if (fRatios)     { delete fRatios;     fRatios     = 0; }
+    if (fOthers)     { delete fOthers;     fOthers     = 0; }
+    if (fTriggers)   { delete fTriggers;   fTriggers   = 0; } 
+    fRangeParam = 0;
+  }
+
   //==================================================================
   /** 
    * @{ 
@@ -82,14 +133,7 @@ struct dNdetaDrawer
    * 
    * @param x Whether to show or not 
    */
-  void SetShowOthers(Bool_t x)    { fShowOthers = x; }
-  //__________________________________________________________________
-  /** 
-   * Show ALICE published data 
-   * 
-   * @param x Wheter to show or not 
-   */
-  void SetShowAlice(Bool_t x)     { fShowAlice = x; }
+  void SetShowOthers(UShort_t x)    { fShowOthers = x; }
   //__________________________________________________________________
   /** 
    * Whether to show ratios or not.  If there's nothing to compare to,
@@ -107,6 +151,20 @@ struct dNdetaDrawer
    */
   void SetShowLeftRight(Bool_t x) { fShowLeftRight = x; }
   //__________________________________________________________________
+  /** 
+   * Whether to show rings 
+   * 
+   * @param x To show or not 
+   */
+  void SetShowRings(Bool_t x) { fShowRings = x; }
+  //__________________________________________________________________
+  /** 
+   * Whether to export results to a script 
+   *
+   * @param x Wheter to export results to a script
+   */
+  void SetExport(Bool_t x)     { fExport = x; }
+  //__________________________________________________________________
   /** 
    * Set the rebinning factor 
    * 
@@ -129,11 +187,18 @@ struct dNdetaDrawer
   void SetTitle(TString x)        { fTitle = x; }
   //__________________________________________________________________
   /** 
-   * Set the file name of the file containing the HHD results
+   * Set the systematic error in the forward region
+   * 
+   * @param e Systematic error in the forward region 
+   */
+  void SetForwardSysError(Double_t e=0) { fFwdSysErr = e; }
+  //__________________________________________________________________
+  /** 
+   * Set the systematic error in the forward region
    * 
-   * @param fn File name 
+   * @param e Systematic error in the forward region 
    */
-  void SetHHDFile(const char* fn) { fHHDFile = fn; }
+  void SetCentralSysError(Double_t e=0) { fCenSysErr = e; }
   /* @} */
   //==================================================================  
   /** 
@@ -147,7 +212,7 @@ struct dNdetaDrawer
    */
   void SetSNN(UShort_t sNN) 
   {
-    fSNNSTring = new TNamed("sNN", Form("%04dGeV", sNN));
+    fSNNString = new TNamed("sNN", Form("%04dGeV", sNN));
     fSNNString->SetUniqueID(sNN);
   }
   //__________________________________________________________________
@@ -160,9 +225,9 @@ struct dNdetaDrawer
    */
   void SetSys(UShort_t sys)
   {
-    fSNNString = new TNamed("sys", (sys == 1 ? "pp" : 
+    fSysString = new TNamed("sys", (sys == 1 ? "pp" : 
                                    sys == 2 ? "PbPb" : "unknown"));
-    fSNNString->SetUniqueID(sys);
+    fSysString->SetUniqueID(sys);
   }
   //__________________________________________________________________
   /** 
@@ -198,67 +263,151 @@ struct dNdetaDrawer
    * 
    * @param filename  File containing the data 
    */
-  void Run(const char* filename="forward_dndeta.C") 
+  void Run(const char* filename="forward_dndeta.root") 
   {
-    if (!Open(filename)) return;
+    Double_t max = 0, rmax=0, amax=0;
 
-    Double_t max = 0;
+    gStyle->SetPalette(1);
 
-    // Create our stack of results
-    THStack* results = StackResults(max);
+    // --- Open input file -------------------------------------------
+    TFile* file = TFile::Open(filename, "READ");
+    if (!file) { 
+      Error("Open", "Cannot open %s", filename);
+      return;
+    }
+    // --- Get forward list ------------------------------------------
+    TList* forward = static_cast<TList*>(file->Get("ForwardResults"));
+    if (!forward) { 
+      Error("Open", "Couldn't find list ForwardResults");
+      return;
+    }
+    // --- Get information on the run --------------------------------
+    FetchInformation(forward);
+    // --- Set the macro pathand load other data script --------------
+    gROOT->SetMacroPath(Form("%s:$(ALICE_ROOT)/PWG2/FORWARD/analysis2",
+                            gROOT->GetMacroPath()));
+    gROOT->LoadMacro("OtherData.C");
+
+    // --- Get the central results -----------------------------------
+    TList* clusters = static_cast<TList*>(file->Get("CentralResults"));
+    if (!clusters) Warning("Open", "Couldn't find list CentralResults");
+
+    // --- Get the central results -----------------------------------
+    TList* mcTruth = static_cast<TList*>(file->Get("MCTruthResults"));
+    if (!mcTruth) Warning("Open", "Couldn't find list MCTruthResults");
+
+    // --- Make our containtes ---------------------------------------
+    fResults   = new THStack("results", "Results");
+    fRatios    = new THStack("ratios",  "Ratios");
+    fLeftRight = new THStack("asymmetry", "Left-right asymmetry");
+    fOthers    = new TMultiGraph();
+    
+    // --- Loop over input data --------------------------------------
+    /*TObjArray* mcA =*/ FetchResults(mcTruth,  "MCTruth", max, rmax, amax);
+    TObjArray* fwdA = FetchResults(forward,  "Forward", max, rmax, amax);
+    TObjArray* cenA = FetchResults(clusters, "Central", max, rmax, amax);
 
-    // Create our stack of other results 
-    TMultiGraph* other = 0;
-    if (fShowOthers || fShowAlice) other = StackOther(max);
+    // --- Get trigger information -----------------------------------
+    TList* sums = static_cast<TList*>(file->Get("ForwardSums"));
+    if (sums) {
+      TList* all = static_cast<TList*>(sums->FindObject("all"));
+      if (all) {
+       fTriggers = FetchResult(all, "triggers");
+       if (!fTriggers) all->ls();
+      }
+      else  {
+       Warning("Run", "List all not found in ForwardSums");
+       sums->ls();
+      }
+    }
+    else { 
+      Warning("Run", "No ForwardSums directory found in %s", file->GetName());
+      file->ls();
+    }
+    
+    // --- Check our stacks ------------------------------------------
+    if (!fResults->GetHists() || 
+       fResults->GetHists()->GetEntries() <= 0) { 
+      Error("Run", "No histograms in result stack!");
+      return;
+    }
+    if (!fOthers->GetListOfGraphs() || 
+       fOthers->GetListOfGraphs()->GetEntries() <= 0) { 
+      Warning("Run", "No other data found - disabling that");
+      fShowOthers = 0;
+    }
+    if (!fRatios->GetHists() || 
+       fRatios->GetHists()->GetEntries() <= 0) { 
+      Warning("Run", "No ratio data found - disabling that");
+      // fRatios->ls();
+      fShowRatios = false;
+    }
+    if (!fLeftRight->GetHists() || 
+       fLeftRight->GetHists()->GetEntries() <= 0) { 
+      Warning("Run", "No left/right data found - disabling that");
+      // fLeftRight->ls();
+      fShowLeftRight = false;
+    }
+    if (fFwdSysErr > 0) { 
+      if (fCenSysErr <= 0) fCenSysErr = fFwdSysErr;
+      for (Int_t i = 0; i < fwdA->GetEntriesFast(); i++) {
+       TH1* fwd = static_cast<TH1*>(fwdA->At(i));
+       TH1* cen = static_cast<TH1*>(cenA->At(i));
+       CorrectForward(fwd);
+       CorrectCentral(cen);
+       Double_t low, high;
+       TH1* tmp = Merge(cen, fwd, low, high);
+       TF1* f   = FitMerged(tmp, low, high);
+       MakeSysError(tmp, cen, fwd, f);
+       delete f;
+       Info("", "Adding systematic error histogram %s", 
+            tmp->GetName());
+       fResults->GetHists()->AddFirst(tmp, "e5");
+       TH1* tmp2 = Symmetrice(tmp);
+       tmp2->SetFillColor(tmp->GetFillColor());
+       tmp2->SetFillStyle(tmp->GetFillStyle());
+       tmp2->SetMarkerStyle(tmp->GetMarkerStyle());
+       tmp2->SetLineWidth(tmp->GetLineWidth());
+       fResults->GetHists()->AddFirst(tmp2, "e5");
+       fResults->Modified();
+      }
+    }
+    delete fwdA;
+    delete cenA;
     
-    Double_t smax = 0;
-    THStack* ratios = 0;
-    if (fShowRatios) ratios = StackRatios(other, smax);
+    // --- Close the input file --------------------------------------
+    file->Close();
 
-    Double_t amax = 0;
-    THStack* leftright = 0;
-    if (fShowLeftRight) leftright = StackLeftRight(amax);
+    
 
-    Plot(results, other, max, ratios, smax, leftright, amax);
+    // --- Plot results ----------------------------------------------
+    Plot(max, rmax, amax);
   }
-    
+
   //__________________________________________________________________
   /** 
-   * Open input file, and find data 
-   * 
-   * @param filename File name
+   * Fetch the information on the run from the results list
    * 
-   * @return true on success 
+   * @param results  Results list
    */
-  Bool_t Open(const char* filename)
+  void FetchInformation(const TList* results)
   {
-    TFile* file = TFile::Open(filename, "READ");
-    if (!file) { 
-      Error("Open", "Cannot open %s", filename);
-      return false;
-    }
-    
-    TList* results = static_cast<TList*>(file->Get("ForwardResults"));
-    if (!results) { 
-      Error("Open", "Couldn't find list ForwardResults");
-      return false;
-    }
-
-    fForward   = GetResult(results, "dndetaForward");
-    fForwardMC = GetResult(results, "dndetaForwardMC");
-    fTruth     = GetResult(results, "dndetaTruth");
-    fCentral   = GetResult(results, "dndetaCentral");
-
     if (!fTrigString) 
-      fTrigString = static_cast<TNamed*>(results->FindObject("trigString"));
+      fTrigString = static_cast<TNamed*>(results->FindObject("trigger"));
+    if (!fNormString) 
+      fNormString = static_cast<TNamed*>(results->FindObject("scheme"));
     if (!fSNNString) 
       fSNNString  = static_cast<TNamed*>(results->FindObject("sNN"));
     if (!fSysString) 
       fSysString  = static_cast<TNamed*>(results->FindObject("sys"));
     if (!fVtxAxis)
       fVtxAxis    = static_cast<TAxis*>(results->FindObject("vtxAxis"));
-    
-    if (!fTrigString) fTrigString = new TNamed("trigString", "unknown");
+    if (!fCentAxis) 
+      fCentAxis   = static_cast<TAxis*>(results->FindObject("centAxis"));
+
+    TNamed* options = static_cast<TAxis*>(results->FindObject("options"));
+    if (!fTrigString) fTrigString = new TNamed("trigger", "unknown");
+    if (!fNormString) fNormString = new TNamed("scheme", "unknown");
     if (!fSNNString)  fSNNString  = new TNamed("sNN", "unknown");
     if (!fSysString)  fSysString  = new TNamed("sys", "unknown");
     if (!fVtxAxis) { 
@@ -267,216 +416,288 @@ struct dNdetaDrawer
       fVtxAxis->SetTitle("v_{z} range unspecified");
     }
 
-    TList* sums = static_cast<TList*>(file->Get("ForwardSums"));
-    if (sums) 
-      fTriggers = GetResult(sums, "triggers");
-
-    if (!fForward) { 
-      Error("Open", "Couldn't find the result of the forward analysis");
-      return false;
+    TString centTxt("none");
+    if (fCentAxis) { 
+      Int_t nCent = fCentAxis->GetNbins();
+      centTxt = Form("%d bins", nCent);
+      for (Int_t i = 0; i <= nCent; i++) 
+       centTxt.Append(Form("%c%d", i == 0 ? ' ' : '-', 
+                           int(fCentAxis->GetXbins()->At(i))));
     }
-    file->Close();
-
-    
-    fForwardHHD = GetHHD();
-
-    return true;
+    Info("FetchInformation", 
+        "Initialized for\n"
+        "   Trigger:       %-30s  (%d)\n"
+        "   sqrt(sNN):     %-30s  (%dGeV)\n"
+        "   System:        %-30s  (%d)\n"
+        "   Vz range:      %-30s  (%f,%f)\n"
+        "   Normalization: %-30s  (%d)\n"
+        "   Centrality:    %s\n"
+        "   Options:       %s",
+        fTrigString->GetTitle(), fTrigString->GetUniqueID(), 
+        fSNNString->GetTitle(),  fSNNString->GetUniqueID(), 
+        fSysString->GetTitle(),  fSysString->GetUniqueID(), 
+        fVtxAxis->GetTitle(), fVtxAxis->GetXmin(), fVtxAxis->GetXmax(),
+        fNormString->GetTitle(), fNormString->GetUniqueID(),
+        centTxt.Data(), (options ? options->GetTitle() : "none"));
   }
   //__________________________________________________________________
-  /** 
-   * Make a histogram stack of results 
-   * 
-   * @param max On return, the maximum value in the stack 
-   * 
-   * @return Newly allocated stack
-   */
-  THStack* StackResults(Double_t& max)
+  TMultiGraph* FetchOthers(UShort_t centLow, UShort_t centHigh)
   {
-    THStack* stack = new THStack("results", "Stack of Results");
-    max = TMath::Max(max, AddHistogram(stack, fTruth,      "e5 p"));
-    max = TMath::Max(max, AddHistogram(stack, fForwardHHD, "", fForwardHHDSym));
-    max = TMath::Max(max, AddHistogram(stack, fForwardMC,  "", fForwardMCSym));
-    max = TMath::Max(max, AddHistogram(stack, fCentral,    ""));
-    max = TMath::Max(max, AddHistogram(stack, fForward,    "", fForwardSym));
-    return stack;
+    TMultiGraph* thisOther = 0;
+    if (fShowOthers == 0) return 0;
+
+    UShort_t sys   = (fSysString  ? fSysString->GetUniqueID() : 0);
+    UShort_t trg   = (fTrigString ? fTrigString->GetUniqueID() : 0);
+    UShort_t snn   = (fSNNString  ? fSNNString->GetUniqueID() : 0);
+    Long_t   ret   = gROOT->ProcessLine(Form("GetData(%d,%d,%d,%d,%d,%d);",
+                                            sys,snn,trg,
+                                            centLow,centHigh,
+                                            fShowOthers));
+    if (!ret) return 0;
+
+    thisOther = reinterpret_cast<TMultiGraph*>(ret);    
+    return thisOther;
   }
   //__________________________________________________________________
   /** 
-   * Make a histogram stack of results 
+   * Get the results from the top-level list 
    * 
-   * @param max On return, the maximum value in the stack 
-   * 
-   * @return Newly allocated stack
+   * @param list  List 
+   * @param name  name 
+   * @param max   On return, maximum of data 
+   * @param rmax  On return, maximum of ratios
+   * @param amax  On return, maximum of left-right comparisons
    */
-  TMultiGraph* StackOther(Double_t& max) const
+  TObjArray* 
+  FetchResults(const TList* list, 
+              const char*  name, 
+              Double_t&    max,
+              Double_t&    rmax,
+              Double_t&    amax)
   {
-    gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/OtherData.C");
-    Int_t    error = 0;
-    Bool_t   onlya = (fShowOthers ? false : true);
-    Int_t    trg   = (fTrigString ? fTrigString->GetUniqueID() : 0);
-    UShort_t snn   = (fSNNString  ? fSNNString->GetUniqueID() : 0);
-    Long_t   ret   = gROOT->ProcessLine(Form("GetData(%d,%d,%d);",
-                                            snn,trg,onlya));
-    if (error) { 
-      Error("StackOther", "Failed to execute GetData(%d,%d,%d)", 
-           snn, trg, onlya);
-      return 0;
+    UShort_t   n = fCentAxis ? fCentAxis->GetNbins() : 0;
+    if (n == 0) {
+      TList* all = static_cast<TList*>(list->FindObject("all"));
+      if (!all) {
+       Error("FetchResults", "Couldn't find list 'all' in %s", 
+             list->GetName());
+       return 0;
+      }
+      TObjArray* a = new TObjArray;
+      TH1*       h = FetchResults(all, name, FetchOthers(0,0), 
+                                 -1000, 0, max, rmax, amax);
+      a->AddAt(h, 0);
+      return a;
     }
-    if (!ret) { 
-      Warning("StackOther", "No other data found for sNN=%d, trigger=%d", 
-             snn, trg);
-      return 0;
+    
+    TObjArray* a = new TObjArray;
+    for (UShort_t i = 0; i < n; i++) { 
+      UShort_t centLow  = fCentAxis->GetBinLowEdge(i+1);
+      UShort_t centHigh = fCentAxis->GetBinUpEdge(i+1);
+      TString  lname    = Form("cent%03d_%03d", centLow, centHigh);
+      TList*   thisCent = static_cast<TList*>(list->FindObject(lname));
+      Int_t    col      = GetCentralityColor(i+1);
+
+      TString centTxt = Form("%3d%%-%3d%% central", centLow, centHigh);
+      if (!thisCent) {
+       Error("FetchResults", "Couldn't find list '%s' in %s", 
+             lname.Data(), list->GetName());
+       continue;
+      }
+      TH1* h = FetchResults(thisCent, name, FetchOthers(centLow, centHigh), 
+                           col, centTxt.Data(), max, rmax, amax);
+      a->AddAt(h, i);
     }
-    TMultiGraph* other = reinterpret_cast<TMultiGraph*>(ret);
-
-    TGraphAsymmErrors* o      = 0;
-    TIter              next(other->GetListOfGraphs());
-    while ((o = static_cast<TGraphAsymmErrors*>(next()))) 
-      max = TMath::Max(max, TMath::MaxElement(o->GetN(), o->GetY()));
-
-    return other;
+    return a;
+  } 
+  //__________________________________________________________________
+  Int_t GetCentralityColor(Int_t bin) const
+  {
+    UShort_t centLow  = fCentAxis->GetBinLowEdge(bin);
+    UShort_t centHigh = fCentAxis->GetBinUpEdge(bin);
+    Float_t  fc       = (centLow+double(centHigh-centLow)/2) / 100;
+    Int_t    nCol     = gStyle->GetNumberOfColors();
+    Int_t    icol     = TMath::Min(nCol-1,int(fc * nCol + .5));
+    Int_t    col      = gStyle->GetColorPalette(icol);
+    //Info("GetCentralityColor","%3d: %3d-%3d -> %3d",bin,centLow,centHigh,col);
+    return col;
   }
+  //__________________________________________________________________
+  void SetAttributes(TH1* h, Int_t color)
+  {
+    if (!h) return;
+    if (color < 0) return;
+    // h->SetLineColor(color);
+    h->SetMarkerColor(color);
+    // h->SetFillColor(color);
+  }
+  //__________________________________________________________________
+  void SetAttributes(TGraph* g, Int_t color)
+  {
+    if (!g) return;
+    if (color < 0) return;
+    // g->SetLineColor(color);
+    g->SetMarkerColor(color);
+    // g->SetFillColor(color);
+  }
+  //__________________________________________________________________
+  void ModifyTitle(TNamed* /*h*/, const char* /*centTxt*/)
+  {
+    return;
+    // if (!centTxt || !h) return;
+    // h->SetTitle(Form("%s, %s", h->GetTitle(), centTxt));
+  }
+
   //__________________________________________________________________
   /** 
-   * Make a histogram stack of ratios of results to other data
+   * Fetch results for a particular centrality bin
    * 
-   * @param max On return, the maximum value in the stack 
-   * 
-   * @return Newly allocated stack
+   * @param list       List 
+   * @param name       Name 
+   * @param thisOther  Other graphs 
+   * @param color      Color 
+   * @param centTxt    Centrality text
+   * @param max        On return, data maximum
+   * @param rmax       On return, ratio maximum 
+   * @param amax       On return, left-right maximum 
    */
-  THStack* StackRatios(TMultiGraph* others, Double_t& max) 
+  TH1* FetchResults(const TList* list, 
+                   const char*  name, 
+                   TMultiGraph* thisOther,
+                   Int_t        color,
+                   const char*  centTxt,
+                   Double_t&    max,
+                   Double_t&    rmax,
+                   Double_t&    amax)
   {
-    THStack* ratios = new THStack("ratios", "Ratios");
-
-    if (others) {
-      TGraphAsymmErrors* ua5_1  = 0;
-      TGraphAsymmErrors* ua5_2  = 0;
-      TGraphAsymmErrors* alice  = 0;
-      TGraphAsymmErrors* cms    = 0;
-      TGraphAsymmErrors* o      = 0;
-      TIter              nextG(others->GetListOfGraphs());
-      while ((o = static_cast<TGraphAsymmErrors*>(nextG()))) {
-       ratios->Add(Ratio(fForward,          o, max));
-       ratios->Add(Ratio(fForwardSym,       o, max));
-       ratios->Add(Ratio(fForwardHHD,       o, max));
-       ratios->Add(Ratio(fForwardHHDSym,    o, max));
-       ratios->Add(Ratio(fCentral,          o, max));
-       TString oName(o->GetName());
-       oName.ToLower();
-       if (oName.Contains("ua5"))  { if (ua5_1) ua5_2 = o; else ua5_1 = o; }
-       if (oName.Contains("alice")) alice = o;
-       if (oName.Contains("cms"))   cms = o;
-      }
-      if (ua5_1 && alice) ratios->Add(Ratio(alice, ua5_1, max));
-      if (ua5_2 && alice) ratios->Add(Ratio(alice, ua5_2, max));
-      if (cms   && alice) ratios->Add(Ratio(alice, cms,   max));
+    TH1* dndeta      = FetchResult(list, Form("dndeta%s", name));
+    TH1* dndetaMC    = FetchResult(list, Form("dndeta%sMC", name));
+    TH1* dndetaTruth = FetchResult(list, "dndetaTruth");
+    TH1* dndetaSym   = 0;
+    TH1* dndetaMCSym = 0;
+    SetAttributes(dndeta,     color);
+    SetAttributes(dndetaMC,   fCentAxis ? color : color+2);
+    SetAttributes(dndetaTruth,color);
+    SetAttributes(dndetaSym,  color);
+    SetAttributes(dndetaMCSym,fCentAxis ? color : color+2);
+    if (dndetaMC && fCentAxis) 
+      dndetaMC->SetMarkerStyle(dndetaMC->GetMarkerStyle()+2);
+    if (dndetaMCSym && fCentAxis) 
+      dndetaMCSym->SetMarkerStyle(dndetaMCSym->GetMarkerStyle()+2);
+    if (dndetaTruth && fCentAxis) {
+      dndetaTruth->SetMarkerStyle(34);
+      dndetaTruth->SetMarkerColor(kYellow-1);
     }
+    ModifyTitle(dndeta,     centTxt);
+    ModifyTitle(dndetaMC,   centTxt);
+    ModifyTitle(dndetaTruth,centTxt);
+    ModifyTitle(dndetaSym,  centTxt);
+    ModifyTitle(dndetaMCSym,centTxt);
+      
 
-    // If we have data from HHD's analysis, then do the ratio of 
-    // our result to that data. 
-    if (fForwardHHD) { 
-      ratios->Add(Ratio(fForward,    fForwardHHD,    max));
-      ratios->Add(Ratio(fForwardSym, fForwardHHDSym, max));
-    }
+    max = TMath::Max(max, AddHistogram(fResults, dndetaTruth, "e5 p"));
+    max = TMath::Max(max, AddHistogram(fResults, dndetaMC,    dndetaMCSym));
+    max = TMath::Max(max, AddHistogram(fResults, dndeta,      dndetaSym));
 
-    // Do comparison to MC 
-    if (fForwardMC) { 
-      ratios->Add(Ratio(fForward,    fForwardMC,    max));
-      ratios->Add(Ratio(fForwardSym, fForwardMCSym, max));
+    if (dndetaTruth) {
+      fTruth = dndetaTruth;
     }
-
-    // Check if we have ratios 
-    if (!ratios->GetHists() || 
-       (ratios->GetHists()->GetEntries() <= 0)) { 
-      delete ratios; 
-      ratios = 0; 
+    else {
+      if (fShowRings) {
+       THStack* rings = static_cast<THStack*>(list->FindObject("dndetaRings"));
+       if (rings) { 
+         TIter next(rings->GetHists());
+         TH1*  hist = 0;
+         while ((hist = static_cast<TH1*>(next()))) 
+           max = TMath::Max(max, AddHistogram(fResults, hist));
+       }
+      }
+      // Info("FetchResults", "Got %p, %p, %p from %s with name %s, max=%f", 
+      //      dndeta, dndetaMC, dndetaTruth, list->GetName(), name, max);
+      
+      if (fShowLeftRight) {
+       fLeftRight->Add(Asymmetry(dndeta,    amax));
+       fLeftRight->Add(Asymmetry(dndetaMC,  amax));
+      }
+      
+      if (thisOther) {
+       TIter next(thisOther->GetListOfGraphs());
+       TGraph* g = 0;
+       while ((g = static_cast<TGraph*>(next()))) {
+         fRatios->Add(Ratio(dndeta,    g, rmax));
+         fRatios->Add(Ratio(dndetaSym, g, rmax));
+         SetAttributes(g, color);
+         ModifyTitle(g, centTxt);
+         if (!fOthers->GetListOfGraphs() || 
+             !fOthers->GetListOfGraphs()->FindObject(g->GetName())) {
+           max = TMath::Max(max,TMath::MaxElement(g->GetN(), g->GetY()));
+           fOthers->Add(g);
+         }
+       }
+       // fOthers->Add(thisOther);
+      }
     }
-    return ratios;
-  }
-  //__________________________________________________________________
-  /** 
-   * Make a histogram stack of the left-right asymmetry 
-   * 
-   * @param max On return, the maximum value in the stack 
-   * 
-   * @return Newly allocated stack
-   */
-  THStack* StackLeftRight(Double_t& max)
-  {
-    THStack* ret = new THStack("leftright", "Left-right asymmetry");
-    ret->Add(Asymmetry(fForward,    max));
-    ret->Add(Asymmetry(fForwardHHD, max));
-    ret->Add(Asymmetry(fForwardMC,  max));
-
-    if (!ret->GetHists() || 
-       (ret->GetHists()->GetEntries() <= 0)) { 
-      delete ret; 
-      ret = 0; 
+    if (dndetaMC) { 
+      fRatios->Add(Ratio(dndeta,    dndetaMC,    rmax));
+      fRatios->Add(Ratio(dndetaSym, dndetaMCSym, rmax));
     }
-    return ret;
+    if (fTruth) {
+      fRatios->Add(Ratio(dndeta,      fTruth, rmax));
+      fRatios->Add(Ratio(dndetaSym,   fTruth, rmax));
+    }
+    return dndeta;
   }
   //__________________________________________________________________
   /** 
    * Plot the results
-   * 
-   * @param results    Results
-   * @param others     Other data
    * @param max        Max value 
-   * @param ratios     Stack of ratios (optional)
    * @param rmax       Maximum diviation from 1 of ratios 
-   * @param leftright  Stack of left-right asymmetry (optional)         
    * @param amax       Maximum diviation from 1 of asymmetries 
    */
-  void Plot(THStack*     results,    
-           TMultiGraph* others, 
-           Double_t     max, 
-           THStack*     ratios,     
+  void Plot(Double_t     max, 
            Double_t     rmax,
-           THStack*     leftright, 
            Double_t     amax)
   {
     gStyle->SetOptTitle(0);
     gStyle->SetTitleFont(132, "xyz");
     gStyle->SetLabelFont(132, "xyz");
     
-    Int_t    h = 800;
-    Int_t    w = 800; // h / TMath::Sqrt(2);
-    if (!ratios) w *= 1.4;
-    if (!leftright) w *= 1.4;
+    Int_t    h  = 800;
+    Int_t    w  = 800; // h / TMath::Sqrt(2);
+    Double_t y1 = 0;
+    Double_t y2 = 0;
+    Double_t y3 = 0;
+    if (!fShowRatios)    w  *= 1.3;
+    else                 y1 =  0.3;
+    if (!fShowLeftRight) w  *= 1.3;
+    else { 
+      Double_t y11 = y1;
+      y1 = (y11 > 0.0001 ? 0.4 : 0.2);
+      y2 = (y11 > 0.0001 ? 0.2 : 0.3);
+    }
     TCanvas* c = new TCanvas("Results", "Results", w, h);
     c->SetFillColor(0);
     c->SetBorderSize(0);
     c->SetBorderMode(0);
 
-    Double_t y1 = 0;
-    Double_t y2 = 0;
-    Double_t y3 = 0;
-    if (ratios)    y1 = 0.3;
-    if (leftright) { 
-      if (y1 > 0.0001) {
-       y2 = 0.2;
-       y1 = 0.4;
-      }
-      else {
-       y1 = 0.2;
-       y2 = y1;
-      }
-    }
-    PlotResults(results, others, max, y1);
+    PlotResults(max, y1);
     c->cd();
 
-    PlotRatios(ratios, rmax, y2, y1);
+    PlotRatios(rmax, y2, y1);
     c->cd( );
 
-    PlotLeftRight(leftright, amax, y3, y2);
+    PlotLeftRight(amax, y3, y2);
     c->cd();
 
     
     Int_t   vMin = fVtxAxis->GetXmin();
     Int_t   vMax = fVtxAxis->GetXmax();    
     TString trg(fTrigString->GetTitle());
-    Int_t   nev  = fTriggers->GetBinContent(fTriggers->GetNbinsX());
+    Int_t   nev  = 0;
+    if (fTriggers) nev = fTriggers->GetBinContent(1);
     trg          = trg.Strip(TString::kBoth);
+    trg.ReplaceAll(" ", "_");
+    trg.ReplaceAll(">", "Gt");
     TString base(Form("dndeta_%s_%s_%s_%c%02d%c%02dcm_%09dev",
                      fSysString->GetTitle(), 
                      fSNNString->GetTitle(), 
@@ -487,18 +708,156 @@ struct dNdetaDrawer
     c->SaveAs(Form("%s.png",  base.Data()));
     c->SaveAs(Form("%s.root", base.Data()));
     c->SaveAs(Form("%s.C",    base.Data()));
+    base.ReplaceAll("dndeta", "export");
+    Export(base);
+  }
+  //__________________________________________________________________
+  /** 
+   * Build main legend 
+   * 
+   * @param stack   Stack to include 
+   * @param mg      (optional) Multi graph to include 
+   * @param x1      Lower X coordinate in the range [0,1]
+   * @param y1      Lower Y coordinate in the range [0,1]
+   * @param x2      Upper X coordinate in the range [0,1]
+   * @param y2             Upper Y coordinate in the range [0,1]
+   */
+  void BuildLegend(THStack* stack, TMultiGraph* mg, 
+                  Double_t x1, Double_t y1, Double_t x2, Double_t y2)
+  {
+    TLegend* l = new TLegend(x1,y1,x2,y2);
+    l->SetNColumns(fCentAxis ? 1 : 2);
+    l->SetFillColor(0);
+    l->SetFillStyle(0);
+    l->SetBorderSize(0);
+    l->SetTextFont(132);
+
+    // Loop over items in stack and get unique items, while ignoring
+    // mirrored data and systematic error bands 
+    TIter    next(stack->GetHists());
+    TH1*     hist = 0;
+    TObjArray unique;
+    unique.SetOwner();
+    Bool_t   sysErrSeen = false;
+    while ((hist = static_cast<TH1*>(next()))) { 
+      TString t(hist->GetTitle());
+      TString n(hist->GetName());
+      n.ToLower();
+      if (t.Contains("mirrored")) continue;
+      if (n.Contains("syserror")) { sysErrSeen = true; continue; }
+      if (unique.FindObject(t.Data())) continue;
+      TObjString* s = new TObjString(hist->GetTitle());
+      s->SetUniqueID(((hist->GetMarkerStyle() & 0xFFFF) << 16) |
+                    ((hist->GetMarkerColor() & 0xFFFF) <<  0));
+      unique.Add(s);
+      // l->AddEntry(hist, hist->GetTitle(), "pl");
+    }
+    if (mg) {
+      // If we have other stuff, scan for unique names 
+      TIter nexto(mg->GetListOfGraphs());
+      TGraph* g = 0;
+      while ((g = static_cast<TGraph*>(nexto()))) { 
+       TString n(g->GetTitle());
+       if (n.Contains("mirrored")) continue;
+       if (unique.FindObject(n.Data())) continue;
+       TObjString* s = new TObjString(n);
+       s->SetUniqueID(((g->GetMarkerStyle() & 0xFFFF) << 16) |
+                      ((g->GetMarkerColor() & 0xFFFF) <<  0));
+       unique.Add(s);
+       // l->AddEntry(hist, hist->GetTitle(), "pl");
+      }
+    }
+
+    // Add legend entries for unique items only
+    TIter nextu(&unique);
+    TObject* s = 0;
+    Int_t i = 0;
+    while ((s = nextu())) { 
+      TLegendEntry* dd = l->AddEntry(Form("data%2d", i++), 
+                                    s->GetName(), "lp");
+      Int_t style = (s->GetUniqueID() >> 16) & 0xFFFF;
+      Int_t color = (s->GetUniqueID() >>  0) & 0xFFFF;
+      dd->SetLineColor(kBlack);
+      if (fCentAxis) dd->SetMarkerColor(kBlack);
+      else           dd->SetMarkerColor(color);
+      dd->SetMarkerStyle(style);
+    }
+    if (sysErrSeen) {
+      // Add entry for systematic errors 
+      TLegendEntry* d0 = l->AddEntry("d0", Form("%4.1f%% Systematic error", 
+                                               100*fFwdSysErr), "f");
+      d0->SetLineColor(SYSERR_COLOR);
+      d0->SetMarkerColor(SYSERR_COLOR);
+      d0->SetFillColor(SYSERR_COLOR);
+      d0->SetFillStyle(SYSERR_STYLE);
+      d0->SetMarkerStyle(0);
+      d0->SetLineWidth(0);
+      i++;
+    }
+    if (!fCentAxis && i % 2 == 1)  {
+      // To make sure the 'data' and 'mirrored' entries are on a line
+      // by themselves 
+      TLegendEntry* dd = l->AddEntry("dd", "   ", "");
+      dd->SetTextSize(0);
+      dd->SetFillStyle(0);
+      dd->SetFillColor(0);
+      dd->SetLineWidth(0);
+      dd->SetLineColor(0);
+      dd->SetMarkerSize(0);
+    }
+    // Add entry for 'data'
+    TLegendEntry* d1 = l->AddEntry("d1", "Data", "lp");
+    d1->SetLineColor(kBlack);
+    d1->SetMarkerColor(kBlack);
+    d1->SetMarkerStyle(20);
+    // Add entry for 'mirrored data'
+    TLegendEntry* d2 = l->AddEntry("d2", "Mirrored data", "lp");
+    d2->SetLineColor(kBlack);
+    d2->SetMarkerColor(kBlack);
+    d2->SetMarkerStyle(24);
+    
+    l->Draw();
+  }
+  //__________________________________________________________________
+  /** 
+   * Build centrality legend 
+   * 
+   * @param axis    Stack to include 
+   * @param x1      Lower X coordinate in the range [0,1]
+   * @param y1      Lower Y coordinate in the range [0,1]
+   * @param x2      Upper X coordinate in the range [0,1]
+   * @param y2             Upper Y coordinate in the range [0,1]
+   */
+  void BuildCentLegend(Double_t x1, Double_t y1, Double_t x2, Double_t y2)
+  {
+    if (!fCentAxis) return;
+
+    TLegend* l = new TLegend(x1,y1,x2,y2);
+    l->SetNColumns(1);
+    l->SetFillColor(0);
+    l->SetFillStyle(0);
+    l->SetBorderSize(0);
+    l->SetTextFont(132);
+
+    Int_t n = fCentAxis->GetNbins();
+    for (Int_t i = 1; i <= n; i++) { 
+      Double_t low = fCentAxis->GetBinLowEdge(i);
+      Double_t upp = fCentAxis->GetBinUpEdge(i);
+      TLegendEntry* e = l->AddEntry(Form("dummy%02d", i),
+                                   Form("%3d%% - %3d%%", 
+                                        int(low), int(upp)), "pl");
+      e->SetMarkerColor(GetCentralityColor(i));
+    }
+    l->Draw();
   }
   //__________________________________________________________________
   /** 
    * Plot the results
    *    
-   * @param results   Results
-   * @param others    Other data
    * @param max       Maximum 
    * @param yd        Bottom position of pad 
    */
-  void PlotResults(THStack* results, TMultiGraph* others, 
-                  Double_t max, Double_t yd) 
+  void PlotResults(Double_t max, Double_t yd) 
   {
     // Make a sub-pad for the result itself
     TPad* p1 = new TPad("p1", "p1", 0, yd, 1.0, 1.0, 0, 0, 0);
@@ -506,65 +865,78 @@ struct dNdetaDrawer
     p1->SetBorderSize(0);
     p1->SetBorderMode(0);
     p1->SetBottomMargin(yd > 0.001 ? 0.001 : 0.1);
-    p1->SetRightMargin(0.05);
-    p1->SetGridx();
+    p1->SetRightMargin(0.03);
+    if (fShowLeftRight || fShowRatios) p1->SetGridx();
     p1->SetTicks(1,1);
     p1->SetNumber(1);
     p1->Draw();
     p1->cd();
-    
-    results->SetMaximum(1.15*max);
-    results->SetMinimum(yd > 0.00001 ? -0.1 : 0);
 
-    FixAxis(results, 1/(1-yd)/1.7, "#frac{1}{N} #frac{dN_{ch}}{d#eta}");
+    // Info("PlotResults", "Plotting results with max=%f", max);
+    fResults->SetMaximum(1.15*max);
+    fResults->SetMinimum(yd > 0.00001 ? -0.1 : 0);
+
+    FixAxis(fResults, (1-yd)*(yd > .001 ? 1 : .9 / 1.2), 
+           "#font[12]{#frac{1}{N} "
+           "#frac{dN_{#font[132]{ch}}}{d#font[152]{#eta}}}");
 
     p1->Clear();
-    results->DrawClone("nostack e1");
+    fResults->DrawClone("nostack e1");
 
-    fRangeParam->fSlave1Axis = results->GetXaxis();
+    fRangeParam->fSlave1Axis = fResults->GetXaxis();
     fRangeParam->fSlave1Pad  = p1;
 
     // Draw other data
-    if (others) {
+    if (fShowOthers != 0) {
       TGraphAsymmErrors* o      = 0;
-      TIter              nextG(others->GetListOfGraphs());
+      TIter              nextG(fOthers->GetListOfGraphs());
       while ((o = static_cast<TGraphAsymmErrors*>(nextG())))
         o->DrawClone("same p");
     }
 
     // Make a legend in the main result pad
-    TLegend* l = p1->BuildLegend(.15,p1->GetBottomMargin()+.01,.90,.35);
-    l->SetNColumns(2);
-    l->SetFillColor(0);
-    l->SetFillStyle(0);
-    l->SetBorderSize(0);
-    l->SetTextFont(132);
+    BuildCentLegend(.12, 1-p1->GetTopMargin()-.01-.5,  
+                   .35, 1-p1->GetTopMargin()-.01-.1);
+    Double_t x1 = (fCentAxis ? .7 : .15); 
+    Double_t x2 = (fCentAxis ? 1-p1->GetRightMargin()-.01: .90);
+    Double_t y1 = (fCentAxis ? .5: p1->GetBottomMargin()+.01); 
+    Double_t y2 = (fCentAxis ? 1-p1->GetTopMargin()-.01-.15 : .35);
+                  
+    BuildLegend(fResults, fOthers, x1, y1, x2, y2);
 
     // Put a title on top
+    fTitle.ReplaceAll("@", " ");
     TLatex* tit = new TLatex(0.10, 0.95, fTitle.Data());
     tit->SetNDC();
     tit->SetTextFont(132);
     tit->SetTextSize(0.05);
     tit->Draw();
 
+    Int_t aliceBlue = TColor::GetColor(41,73,156);
     // Put a nice label in the plot
     TString     eS;
     UShort_t    snn = fSNNString->GetUniqueID();
     const char* sys = fSysString->GetTitle();
+    if (snn == 2750) snn = 2760;
     if (snn > 1000) eS = Form("%4.2fTeV", float(snn)/1000);
     else            eS = Form("%3dGeV", snn);
-    TLatex* tt = new TLatex(.93, .93, Form("%s #sqrt{s}=%s, %s", 
+    TLatex* tt = new TLatex(.93, .93, Form("%s #sqrt{s%s}=%s, %s", 
                                           sys, 
+                                          (fCentAxis ? "_{NN}" : ""),
                                           eS.Data(), 
+                                          fCentAxis ? "by centrality" : 
                                           fTrigString->GetTitle()));
+    tt->SetTextColor(aliceBlue);
     tt->SetNDC();
     tt->SetTextFont(132);
     tt->SetTextAlign(33);
     tt->Draw();
 
     // Put number of accepted events on the plot
-    Int_t nev = fTriggers->GetBinContent(fTriggers->GetNbinsX());
+    Int_t nev = 0;
+    if (fTriggers) nev = fTriggers->GetBinContent(1);
     TLatex* et = new TLatex(.93, .83, Form("%d events", nev));
+    et->SetTextColor(aliceBlue);
     et->SetNDC();
     et->SetTextFont(132);
     et->SetTextAlign(33);
@@ -576,31 +948,39 @@ struct dNdetaDrawer
       vt->SetNDC();
       vt->SetTextFont(132);
       vt->SetTextAlign(33);
+      vt->SetTextColor(aliceBlue);
       vt->Draw();
     }
     // results->Draw("nostack e1 same");
 
-    fRangeParam->fSlave1Axis = FindXAxis(p1, results->GetName());
+    fRangeParam->fSlave1Axis = FindXAxis(p1, fResults->GetName());
     fRangeParam->fSlave1Pad  = p1;
 
 
     // Mark the plot as preliminary
-    TLatex* pt = new TLatex(.12, .93, "Preliminary");
+    TLatex* pt = new TLatex(.12, .93, "Work in progress");
     pt->SetNDC();
     pt->SetTextFont(22);
-    pt->SetTextSize(0.07);
-    pt->SetTextColor(kRed+1);
+    // pt->SetTextSize();
+    pt->SetTextColor(TColor::GetColor(234,26,46));
     pt->SetTextAlign(13);
     pt->Draw();
 
-    if (!gSystem->AccessPathName("ALICE.png")) { 
-      TPad* logo = new TPad("logo", "logo", .12, .65, .25, .85, 0, 0, 0);
-      logo->SetFillStyle(0);
-      logo->Draw();
-      logo->cd();
+    const char*  logos[] = { "ALICE.png", "FMD.png", 0 };
+    const char** logo    = logos;
+    while (*logo) {
+      if (gSystem->AccessPathName(*logo)) {
+       logo++;
+       continue;
+      }
+      TPad* pad = new TPad("logo", "logo", .12, .7, .25, .9, 0, 0, 0);
+      pad->SetFillStyle(0);
+      pad->Draw();
+      pad->cd();
       TImage* i = TImage::Create();
-      i->ReadImage("ALICE.png");
+      i->ReadImage(*logo);
       i->Draw();
+      break;
     }
     p1->cd();
   }
@@ -608,20 +988,20 @@ struct dNdetaDrawer
   /** 
    * Plot the ratios 
    * 
-   * @param ratios  Ratios to plot (if any)
    * @param max     Maximum diviation from 1 
    * @param y1      Lower y coordinate of pad
    * @param y2      Upper y coordinate of pad
    */
-  void PlotRatios(THStack* ratios, Double_t max, Double_t y1, Double_t y2) 
+  void PlotRatios(Double_t max, Double_t y1, Double_t y2) 
   {
-    if (!ratios) return;
+    if (fShowRatios == 0) return;
+
     bool isBottom = (y1 < 0.0001);
     Double_t yd = y2 - y1;
     // Make a sub-pad for the result itself
     TPad* p2 = new TPad("p2", "p2", 0, y1, 1.0, y2, 0, 0, 0);
     p2->SetTopMargin(0.001);
-    p2->SetRightMargin(0.05);
+    p2->SetRightMargin(0.03);
     p2->SetBottomMargin(isBottom ? 1/yd * 0.07 : 0.0001);
     p2->SetGridx();
     p2->SetTicks(1,1);
@@ -630,15 +1010,18 @@ struct dNdetaDrawer
     p2->cd();
 
     // Fix up axis
-    FixAxis(ratios, 1/yd/1.7, "Ratios", 7);
+    FixAxis(fRatios, yd, "Ratios", 7);
 
-    ratios->SetMaximum(1+TMath::Max(.22,1.05*max));
-    ratios->SetMinimum(1-TMath::Max(.32,1.05*max));
+    fRatios->SetMaximum(1+TMath::Max(.22,1.05*max));
+    fRatios->SetMinimum(1-TMath::Max(.32,1.05*max));
     p2->Clear();
-    ratios->DrawClone("nostack e1");
+    fRatios->DrawClone("nostack e1");
 
     
     // Make a legend
+    BuildLegend(fRatios, 0, .15,p2->GetBottomMargin()+.01,.9,
+               isBottom ? .6 : .4);
+#if 0
     TLegend* l2 = p2->BuildLegend(.15,p2->GetBottomMargin()+.01,.9,
                                  isBottom ? .6 : .4);
     l2->SetNColumns(2);
@@ -646,11 +1029,11 @@ struct dNdetaDrawer
     l2->SetFillStyle(0);
     l2->SetBorderSize(0);
     l2->SetTextFont(132);
-
+#endif
     // Make a nice band from 0.9 to 1.1
     TGraphErrors* band = new TGraphErrors(2);
-    band->SetPoint(0, fForwardSym->GetXaxis()->GetXmin(), 1);
-    band->SetPoint(1, fForward->GetXaxis()->GetXmax(), 1);
+    band->SetPoint(0, fResults->GetXaxis()->GetXmin(), 1);
+    band->SetPoint(1, fResults->GetXaxis()->GetXmax(), 1);
     band->SetPointError(0, 0, .1);
     band->SetPointError(1, 0, .1);
     band->SetFillColor(kYellow+2);
@@ -661,15 +1044,15 @@ struct dNdetaDrawer
     band->DrawClone("X L same");
     
     // Replot the ratios on top
-    ratios->DrawClone("nostack e1 same");
+    fRatios->DrawClone("nostack e1 same");
 
     if (isBottom) {
-      fRangeParam->fMasterAxis = FindXAxis(p2, ratios->GetName());
+      fRangeParam->fMasterAxis = FindXAxis(p2, fRatios->GetName());
       p2->AddExec("range", Form("RangeExec((dNdetaDrawer::RangeParam*)%p)", 
                                fRangeParam));
     }
     else { 
-      fRangeParam->fSlave2Axis = FindXAxis(p2, ratios->GetName());
+      fRangeParam->fSlave2Axis = FindXAxis(p2, fRatios->GetName());
       fRangeParam->fSlave2Pad  = p2;
     }
   }
@@ -677,21 +1060,20 @@ struct dNdetaDrawer
   /** 
    * Plot the asymmetries
    * 
-   * @param ratios  Asymmetries to plot (if any)
    * @param max     Maximum diviation from 1 
    * @param y1      Lower y coordinate of pad
    * @param y2      Upper y coordinate of pad
    */
-  void PlotLeftRight(THStack* leftright, Double_t max, 
-                    Double_t y1, Double_t y2) 
+  void PlotLeftRight(Double_t max, Double_t y1, Double_t y2) 
   {
-    if (!leftright) return;
+    if (!fShowLeftRight) return;
+
     bool isBottom = (y1 < 0.0001);
     Double_t yd = y2 - y1;
     // Make a sub-pad for the result itself
     TPad* p3 = new TPad("p3", "p3", 0, y1, 1.0, y2, 0, 0, 0);
     p3->SetTopMargin(0.001);
-    p3->SetRightMargin(0.05);
+    p3->SetRightMargin(0.03);
     p3->SetBottomMargin(isBottom ? 1/yd * 0.07 : 0.0001);
     p3->SetGridx();
     p3->SetTicks(1,1);
@@ -699,49 +1081,32 @@ struct dNdetaDrawer
     p3->Draw();
     p3->cd();
 
-    TH1* dummy = 0;
-    if (leftright->GetHists()->GetEntries() == 1) { 
-      // Add dummy histogram
-      dummy = new TH1F("dummy","", 10, -6, 6);
-      dummy->SetLineColor(0);
-      dummy->SetFillColor(0);
-      dummy->SetMarkerColor(0);
-      leftright->Add(dummy);
-    }
-
     // Fix up axis
-    FixAxis(leftright, 1/yd/1.7, "Right/Left", 4);
+    FixAxis(fLeftRight, yd, "Right/Left", 4);
 
-    leftright->SetMaximum(1+TMath::Max(.12,1.05*max));
-    leftright->SetMinimum(1-TMath::Max(.15,1.05*max));
+    fLeftRight->SetMaximum(1+TMath::Max(.12,1.05*max));
+    fLeftRight->SetMinimum(1-TMath::Max(.15,1.05*max));
     p3->Clear();
-    leftright->DrawClone("nostack e1");
+    fLeftRight->DrawClone("nostack e1");
 
     
     // Make a legend
-    TLegend* l2 = p3->BuildLegend(.15,p3->GetBottomMargin()+.01,.9,.5);
-    l2->SetNColumns(2);
-    l2->SetFillColor(0);
-    l2->SetFillStyle(0);
-    l2->SetBorderSize(0);
-    l2->SetTextFont(132);
-#ifndef __CINT__
-    if (dummy) {
-      TList* prims = l2->GetListOfPrimitives();
-      TIter next(prims);
-      TLegendEntry* o = 0;
-      while ((o = static_cast<TLegendEntry*>(next()))) { 
-       TString lbl(o->GetLabel());
-       if (lbl != "dummy") continue; 
-       prims->Remove(o);
-       break;
-      }
-    }
-#endif
+    Double_t xx1 = (fCentAxis ? .7                           : .15); 
+    Double_t xx2 = (fCentAxis ? 1-p3->GetRightMargin()-.01   : .90);
+    Double_t yy1 = p3->GetBottomMargin()+.01;
+    Double_t yy2 = (fCentAxis ? 1-p3->GetTopMargin()-.01-.15 : .5);
+    BuildLegend(fLeftRight, 0, xx1, yy1, xx2, yy2);
+    // TLegend* l2 = p3->BuildLegend(.15,p3->GetBottomMargin()+.01,.9,.5);
+    // l2->SetNColumns(2);
+    // l2->SetFillColor(0);
+    // l2->SetFillStyle(0);
+    // l2->SetBorderSize(0);
+    // l2->SetTextFont(132);
+
     // Make a nice band from 0.9 to 1.1
     TGraphErrors* band = new TGraphErrors(2);
-    band->SetPoint(0, fForwardSym->GetXaxis()->GetXmin(), 1);
-    band->SetPoint(1, fForward->GetXaxis()->GetXmax(), 1);
+    band->SetPoint(0, fResults->GetXaxis()->GetXmin(), 1);
+    band->SetPoint(1, fResults->GetXaxis()->GetXmax(), 1);
     band->SetPointError(0, 0, .05);
     band->SetPointError(1, 0, .05);
     band->SetFillColor(kYellow+2);
@@ -751,14 +1116,14 @@ struct dNdetaDrawer
     band->Draw("3 same");
     band->DrawClone("X L same");
 
-    leftright->DrawClone("nostack e1 same");
+    fLeftRight->DrawClone("nostack e1 same");
     if (isBottom) {
-      fRangeParam->fMasterAxis = FindXAxis(p3, leftright->GetName());
+      fRangeParam->fMasterAxis = FindXAxis(p3, fLeftRight->GetName());
       p3->AddExec("range", Form("RangeExec((dNdetaDrawer::RangeParam*)%p)", 
                                fRangeParam));
     }
     else { 
-      fRangeParam->fSlave2Axis = FindXAxis(p3, leftright->GetName());
+      fRangeParam->fSlave2Axis = FindXAxis(p3, fLeftRight->GetName());
       fRangeParam->fSlave2Pad  = p3;
     }
   }
@@ -776,60 +1141,19 @@ struct dNdetaDrawer
    * 
    * @return 
    */
-  TH1* GetResult(TList* list, const char* name) const 
+  TH1* FetchResult(const TList* list, const char* name) const 
   {
     if (!list) return 0;
     
     TH1* ret = static_cast<TH1*>(list->FindObject(name));
-    if (!ret) 
+#if 0
+    if (!ret) {
+      // all->ls();
       Warning("GetResult", "Histogram %s not found", name);
-    
-    return ret;
-  }
-  //__________________________________________________________________
-  /** 
-   * Get the result from previous analysis code 
-   * 
-   * @param fn  File to open 
-   * @param nsd Whether this is NSD
-   * 
-   * @return null or result of previous analysis code 
-   */
-  TH1* GetHHD() 
-  {
-    if (fHHDFile.IsNull()) return 0;
-    const char* fn = fHHDFile.Data();
-    Bool_t nsd = (fTrigString ? fTrigString->GetUniqueID() & 0x4 : false);
-    TDirectory* savdir = gDirectory;
-    if (gSystem->AccessPathName(fn)) { 
-      Warning("GetHHD", "Output of HHD analysis (%s) not available", fn);
-      return 0;
     }
-    TFile* file = TFile::Open(fn, "READ");
-    if (!file) { 
-      Warning("GetHHD", "couldn't open HHD file %s", fn);
-      return 0;
-    }
-    TString hist(Form("dNdeta_dNdeta%s", (nsd ? "NSD" : "")));
-    TH1* h = static_cast<TH1*>(file->Get(hist.Data()));
-    if (!h) { 
-      Warning("GetHHD", "Couldn't find HHD histogram %s in %s", 
-             hist.Data(), fn);
-      file->Close();
-      savdir->cd();
-      return 0;
-    }
-    TH1* r = static_cast<TH1*>(h->Clone("dndeta_hhd"));
-    r->SetTitle("ALICE Forward (HHD)");
-    r->SetFillStyle(0);
-    r->SetFillColor(0);
-    r->SetMarkerStyle(21);
-    r->SetMarkerColor(kPink+1);
-    r->SetDirectory(0);
+#endif
 
-    file->Close();
-    savdir->cd();
-    return r;
+    return ret;
   }
   //__________________________________________________________________
   /** 
@@ -841,7 +1165,7 @@ struct dNdetaDrawer
    * 
    * @return Maximum of histogram 
    */
-  Double_t AddHistogram(THStack* stack, TH1* hist, Option_t* option) const 
+  Double_t AddHistogram(THStack* stack, TH1* hist, Option_t* option="") const 
   {
     // Check if we have input 
     if (!hist) return 0;
@@ -863,8 +1187,8 @@ struct dNdetaDrawer
    * 
    * @return Maximum of histogram 
    */
-  Double_t AddHistogram(THStack* stack, TH1* hist, Option_t* option, 
-                       TH1*& sym) const 
+  Double_t AddHistogram(THStack* stack, TH1* hist, TH1*& sym,
+                       Option_t* option="") const 
   {
     // Check if we have input 
     if (!hist) return 0;
@@ -885,7 +1209,6 @@ struct dNdetaDrawer
    * Rebin a histogram 
    * 
    * @param h     Histogram to rebin
-   * @param rebin Rebinning factor 
    * 
    * @return 
    */
@@ -904,7 +1227,7 @@ struct dNdetaDrawer
     TH1* tmp = static_cast<TH1*>(h->Clone("tmp"));
     tmp->Rebin(fRebin);
     tmp->SetDirectory(0);
-
+    tmp->Reset();
     // The new number of bins 
     Int_t nBinsNew = nBins / fRebin;
     for(Int_t i = 1;i<= nBinsNew; i++) {
@@ -936,7 +1259,7 @@ struct dNdetaDrawer
        nbins++;
       }
       
-      if(content > 0 && nbins > 0) {
+      if(content > 0 && nbins > ) {
        tmp->SetBinContent(i, wsum / sumw);
        tmp->SetBinError(i,1./TMath::Sqrt(sumw));
       }
@@ -1015,6 +1338,7 @@ struct dNdetaDrawer
     // Double_t dBin  = (high - low) / oBins;
     // Int_t    tBins = Int_t(2*high/dBin+.5);
     // ret->SetBins(tBins, -high, high);
+    ret->SetDirectory(0);
     ret->Reset();
     ret->SetTitle(Form("%s (+/-)", h->GetTitle()));
     ret->SetYTitle("Right/Left");
@@ -1109,6 +1433,73 @@ struct dNdetaDrawer
     return ret;
   }
   //__________________________________________________________________
+  /** 
+   * Make the ratio of h1 to h2 
+   * 
+   * @param o1  First object (numerator) 
+   * @param o2  Second object (denominator)
+   * @param max Maximum diviation from 1 
+   * 
+   * @return o1 / o2
+   */
+  TH1* Ratio(const TObject* o1, const TObject* o2, Double_t& max) const
+  {
+    if (!o1 || !o2) return 0;
+
+    TH1*        r  = 0;
+    const TAttMarker* m1 = 0;
+    const TAttMarker* m2 = 0;
+    const TH1* h1 = dynamic_cast<const TH1*>(o1); 
+    if (h1) { 
+      m1 = h1;
+      const TH1* h2 = dynamic_cast<const TH1*>(o2); 
+      if (h2) { 
+       m2 = h2;
+       r = RatioHH(h1,h2);
+      }
+      else {
+       const TGraph* g2 = dynamic_cast<const TGraph*>(o2);
+       if (g2) { 
+         m2 = g2;
+         r = RatioHG(h1,g2);      
+       }
+      }
+    }
+    else {
+      const TGraphAsymmErrors* g1 = dynamic_cast<const TGraphAsymmErrors*>(o1);
+      if (g1) { 
+       m1 = g1;
+       const TGraphAsymmErrors* g2 = 
+         dynamic_cast<const TGraphAsymmErrors*>(o2);
+       if (g2) {
+         m2 = g2;
+         r = RatioGG(g1, g2);
+       }
+      }
+    }
+    if (!r) {
+      Warning("Ratio", "Don't know how to divide a %s (%s) with a %s (%s)", 
+             o1->ClassName(), o1->GetName(), o2->ClassName(), o2->GetName());
+      return 0;
+    }
+    // Check that the histogram isn't empty
+    if (r->GetEntries() <= 0) { 
+      delete r; 
+      r = 0; 
+    }
+    if (r) {
+      r->SetMarkerStyle(m2->GetMarkerStyle());
+      r->SetMarkerColor(m1->GetMarkerColor());
+      r->SetMarkerSize(0.9*m1->GetMarkerSize());
+      r->SetName(Form("%s_over_%s", o1->GetName(), o2->GetName()));
+      r->SetTitle(Form("%s / %s", o1->GetTitle(), o2->GetTitle()));
+      r->SetDirectory(0);
+      max = TMath::Max(RatioMax(r), max);
+    }
+
+    return r;
+  }
+  //__________________________________________________________________
   /** 
    * Compute the ratio of @a h to @a g.  @a g is evaluated at the bin
    * centers of @a h 
@@ -1118,17 +1509,12 @@ struct dNdetaDrawer
    * 
    * @return h/g 
    */
-  TH1* Ratio(const TH1* h, const TGraph* g, Double_t& max) const 
+  TH1* RatioHG(const TH1* h, const TGraph* g) const 
   {
     if (!h || !g) return 0;
 
     TH1* ret = static_cast<TH1*>(h->Clone("tmp"));
-    ret->SetName(Form("%s_over_%s", h->GetName(), g->GetName()));
-    ret->SetTitle(Form("%s / %s", h->GetTitle(), g->GetTitle()));
     ret->Reset();
-    ret->SetMarkerStyle(g->GetMarkerStyle());
-    ret->SetMarkerColor(h->GetMarkerColor());
-    ret->SetMarkerSize(0.9*g->GetMarkerSize());
     Double_t xlow  = g->GetX()[0];
     Double_t xhigh = g->GetX()[g->GetN()-1];
     if (xlow > xhigh) { Double_t t = xhigh; xhigh = xlow; xlow = t; }
@@ -1146,12 +1532,6 @@ struct dNdetaDrawer
       ret->SetBinContent(i, c / f);
       ret->SetBinError(i, h->GetBinError(i) / f);
     }
-    if (ret->GetEntries() <= 0) { 
-      delete ret; 
-      ret = 0; 
-    }
-    else 
-      max = TMath::Max(RatioMax(ret), max);
     return ret;
   }
   //__________________________________________________________________
@@ -1163,17 +1543,11 @@ struct dNdetaDrawer
    * 
    * @return h1 / h2
    */
-  TH1* Ratio(const TH1* h1, const TH1* h2, Double_t& max) const
+  TH1* RatioHH(const TH1* h1, const TH1* h2) const
   {
     if (!h1 || !h2) return 0;
-    TH1* t1 = static_cast<TH1*>(h1->Clone(Form("%s_%s", 
-                                              h1->GetName(), 
-                                              h2->GetName())));
-    t1->SetTitle(Form("%s / %s", h1->GetTitle(), h2->GetTitle()));
+    TH1* t1 = static_cast<TH1*>(h1->Clone("tmp"));
     t1->Divide(h2);
-    t1->SetMarkerColor(h1->GetMarkerColor());
-    t1->SetMarkerStyle(h2->GetMarkerStyle());
-    max = TMath::Max(RatioMax(t1), max);
     return t1;
   }
   //__________________________________________________________________
@@ -1185,8 +1559,8 @@ struct dNdetaDrawer
    * 
    * @return g1 / g2 in a histogram 
    */
-  TH1* Ratio(const TGraphAsymmErrors* g1, 
-            const TGraphAsymmErrors* g2, Double_t& max) const
+  TH1* RatioGG(const TGraphAsymmErrors* g1, 
+              const TGraphAsymmErrors* g2) const
   {
     Int_t    nBins = g1->GetN();
     TArrayF  bins(nBins+1);
@@ -1201,18 +1575,13 @@ struct dNdetaDrawer
       if (i == 0) dx  = dxi;
       else if (dxi != dx) dx = 0;
     }
-    TString name(Form("%s_%s", g1->GetName(), g2->GetName()));
-    TString title(Form("%s / %s", g1->GetTitle(), g2->GetTitle()));
     TH1* h = 0;
     if (dx != 0) {
-      h = new TH1F(name.Data(), title.Data(), nBins, bins[0], bins[nBins]);
+      h = new TH1F("tmp", "tmp", nBins, bins[0], bins[nBins]);
     }
     else {
-      h = new TH1F(name.Data(), title.Data(), nBins, bins.fArray);
+      h = new TH1F("tmp", "tmp", nBins, bins.fArray);
     }
-    h->SetMarkerStyle(g2->GetMarkerStyle());
-    h->SetMarkerColor(g1->GetMarkerColor());
-    h->SetMarkerSize(0.9*g2->GetMarkerSize());
 
     Double_t low  = g2->GetX()[0];
     Double_t high = g2->GetX()[g2->GetN()-1];
@@ -1227,7 +1596,6 @@ struct dNdetaDrawer
       h->SetBinContent(i+1, c1 / c2);
       h->SetBinError(i+1, e1 / c2);
     }
-    max = TMath::Max(RatioMax(h), max);
     return h;
   }  
   /* @} */
@@ -1274,27 +1642,47 @@ struct dNdetaDrawer
    * @param force  Whether to draw the stack first or not
    * @param ynDiv  Divisions on Y axis
    */
-  void FixAxis(THStack* stack, Double_t s, const char* ytitle,
+  void FixAxis(THStack* stack, Double_t yd, const char* ytitle,
                Int_t ynDiv=210, Bool_t force=true)
   {
+    if (!stack) { 
+      Warning("FixAxis", "No stack passed for %s!", ytitle);
+      return;
+    }
     if (force) stack->Draw("nostack e1");
 
     TH1* h = stack->GetHistogram();
-    if (!h) return;
+    if (!h) { 
+      Warning("FixAxis", "Stack %s has no histogram", stack->GetName());
+      return;
+    }
+    Double_t s = 1/yd/1.2;
+    // Info("FixAxis", "for %s, s=1/%f=%f", stack->GetName(), yd, s);
 
-    h->SetXTitle("#eta");
+    h->SetXTitle("#font[152]{#eta}");
     h->SetYTitle(ytitle);
     TAxis* xa = h->GetXaxis();
     TAxis* ya = h->GetYaxis();
+
+    // Int_t   npixels = 20
+    // Float_t dy = gPad->AbsPixeltoY(0) - gPad->AbsPixeltoY(npixels);
+    // Float_t ts = dy/(gPad->GetY2() - gPad->GetY1());
+
     if (xa) {
-      xa->SetTitle("#eta");
+      // xa->SetTitle(h->GetXTitle());
       // xa->SetTicks("+-");
       xa->SetTitleSize(s*xa->GetTitleSize());
       xa->SetLabelSize(s*xa->GetLabelSize());
       xa->SetTickLength(s*xa->GetTickLength());
+      // xa->SetTitleOffset(xa->GetTitleOffset()/s);
+
+      if (stack != fResults) {
+       TAxis* rxa = fResults->GetXaxis();
+       xa->Set(rxa->GetNbins(), rxa->GetXmin(), rxa->GetXmax());
+      }
     }
     if (ya) {
-      ya->SetTitle(ytitle);
+      // ya->SetTitle(h->GetYTitle());
       ya->SetDecimals();
       // ya->SetTicks("+-");
       ya->SetNdivisions(ynDiv);
@@ -1303,36 +1691,279 @@ struct dNdetaDrawer
       ya->SetLabelSize(s*ya->GetLabelSize());
     }
   }
+  //__________________________________________________________________
+  /** 
+   * Merge two histograms into one 
+   * 
+   * @param cen    Central part
+   * @param fwd    Forward part
+   * @param xlow   On return, lower eta bound
+   * @param xhigh  On return, upper eta bound
+   * 
+   * @return Newly allocated histogram or null
+   */
+  TH1* 
+  Merge(const TH1* cen, const TH1* fwd, Double_t& xlow, Double_t& xhigh)
+  {
+    TH1* tmp = static_cast<TH1*>(fwd->Clone("tmp"));
+    TString name(fwd->GetName());
+    name.ReplaceAll("Forward", "Merged");
+    tmp->SetName(name);
+
+    // tmp->SetMarkerStyle(28);
+    // tmp->SetMarkerColor(kBlack);
+    tmp->SetDirectory(0);
+    xlow  = 100;
+    xhigh = -100;
+    for (Int_t i = 1; i <= tmp->GetNbinsX(); i++) {
+      Double_t cc = cen->GetBinContent(i);
+      Double_t cf = fwd->GetBinContent(i);
+      Double_t ec = cen->GetBinError(i);
+      Double_t ef = fwd->GetBinError(i);
+      Double_t nc = cf;
+      Double_t ne = ef;
+      if (cc < 0.001 && cf < 0.01) continue;
+      xlow  = TMath::Min(tmp->GetXaxis()->GetBinLowEdge(i),xlow);
+      xhigh = TMath::Max(tmp->GetXaxis()->GetBinUpEdge(i),xhigh);
+      if (cc > 0.001) {
+       nc = cc;
+       ne = ec;
+       if (cf > 0.001) {
+         nc  = (cf + cc) / 2;
+         ne  = TMath::Sqrt(ec*ec + ef*ef);
+       }
+      }
+      tmp->SetBinContent(i, nc);
+      tmp->SetBinError(i, ne);
+    }
+    return tmp;
+  }
+  //____________________________________________________________________
+  /** 
+   * Fit  @f$g(x;A_1,A_2,\sigma_1,\sigma_2)@f$ to histogram data 
+   * 
+   * @param tmp    Histogram
+   * @param xlow   Lower x bound
+   * @param xhigh  Upper x bound 
+   *
+   * @return Fitted function 
+   */
+  TF1* 
+  FitMerged(TH1* tmp, Double_t xlow, Double_t xhigh)
+  {
+    TF1* tmpf  = new TF1("tmpf", "gaus", xlow, xhigh);
+    tmp->Fit(tmpf, "NQ", "");
+    tmp->SetDirectory(0);
+
+    TF1* fit = new TF1("f", myFunc, xlow, xhigh, 4);
+    fit->SetParNames("a_{1}", "a_{2}", "#sigma_{1}", "#sigma_{2}");
+    fit->SetParameters(tmpf->GetParameter(0), 
+                      .2, 
+                      tmpf->GetParameter(2), 
+                      tmpf->GetParameter(2)/4);
+    fit->SetParLimits(3, 0, 100);
+    fit->SetParLimits(4, 0, 100);
+    tmp->Fit(fit,"0W","");
+
+    delete tmpf;
+    return fit;
+  }
+  //____________________________________________________________________
+  /** 
+   * Make band of systematic errors 
+   * 
+   * @param tmp Histogram
+   * @param fit Fit 
+   */
+  void
+  MakeSysError(TH1* tmp, TH1* cen, TH1* fwd, TF1* fit)
+  {
+    for (Int_t i = 1; i <= tmp->GetNbinsX(); i++) {
+      Double_t tc = tmp->GetBinContent(i);
+      if (tc < 0.01) continue;
+      Double_t fc = fwd->GetBinContent(i);
+      Double_t cc = cen->GetBinContent(i);
+      Double_t sysErr = fFwdSysErr;
+      if (cc > .01 && fc > 0.01) 
+       sysErr = (fFwdSysErr+fCenSysErr) / 2;
+      else if (cc > .01) 
+       sysErr = fCenSysErr;
+      Double_t x = tmp->GetXaxis()->GetBinCenter(i);
+      Double_t y = fit->Eval(x);
+      tmp->SetBinContent(i, y);
+      tmp->SetBinError(i,sysErr*y);
+    }
+    TString name(tmp->GetName());
+    name.ReplaceAll("Merged", "SysError");
+    tmp->SetName(name);
+    tmp->SetMarkerColor(SYSERR_COLOR);
+    tmp->SetLineColor(SYSERR_COLOR);
+    tmp->SetFillColor(SYSERR_COLOR);
+    tmp->SetFillStyle(SYSERR_STYLE);
+    tmp->SetMarkerStyle(0);
+    tmp->SetLineWidth(0);
+  }
+  void CorrectForward(TH1* h) const
+  {
+    if (!fRemoveOuters) return;
+    
+    for (Int_t i = 1; i <= h->GetNbinsX(); i++) { 
+      Double_t eta = h->GetBinCenter(i);
+      if (TMath::Abs(eta) < 2.3) { 
+       h->SetBinContent(i, 0);
+       h->SetBinError(i, 0);
+      }
+    }
+  }
+  void CorrectCentral(TH1* h) const 
+  {
+    if (fClusterScale.IsNull()) return;
+    TString t(h->GetTitle());
+    Info("CorrectCentral", "Replacing Central with Tracklets in %s", t.Data());
+    t.ReplaceAll("Central", "Tracklets");
+    h->SetTitle(t);
+
+    TF1* cf = new TF1("clusterScale", fClusterScale);
+    for (Int_t i = 1; i <= h->GetNbinsX(); i++) { 
+      Double_t eta = h->GetBinCenter(i);
+      Double_t f   = cf->Eval(eta);
+      Double_t c   = h->GetBinContent(i);
+      if (f < .1) f = 1;
+      h->SetBinContent(i, c / f);
+    }
+    delete cf;
+  }
+  //____________________________________________________________________
+  void Export(const char* basename)
+  {
+    TString bname(basename);
+    bname.ReplaceAll(" ", "_");
+    bname.ReplaceAll("-", "_");
+    TString fname(Form("%s.C", bname.Data()));
+
+    std::ofstream out(fname.Data());
+    if (!out) { 
+      Error("Export", "Failed to open output file %s", fname.Data());
+      return;
+    }
+    out << "// Create by dNdetaDrawer\n"
+       << "void " << bname << "(THStack* stack, TLegend* l, Int_t m)\n"
+       << "{"
+       << "   Int_t ma[] = { 24, 25, 26, 32,\n"
+       << "                  20, 21, 22, 33,\n"
+       << "                  34, 30, 29, 0, \n"
+       << "                  23, 27 };\n"
+       << "   Int_t mm = ((m < 20 || m > 34) ? 0 : ma[m-20]);\n\n";
+    TList* hists = fResults->GetHists();
+    TIter  next(hists);
+    TH1*   hist = 0;
+    while ((hist = static_cast<TH1*>(next()))) { 
+      TString hname = hist->GetName();
+      hname.Append(Form("_%04x", (gRandom->Integer(0xffff) & 0xffff)));
+      hist->SetName(hname);
+      hist->GetListOfFunctions()->Clear();
+      hist->SavePrimitive(out, "nodraw");
+      bool mirror = hname.Contains("mirror");
+      bool syserr = hname.Contains("SysError");
+      if (!syserr) 
+       out << "   " << hname << "->SetMarkerStyle(" 
+           << (mirror ? "mm" : "m") << ");\n";
+      else 
+       out << "   " << hname << "->SetMarkerStyle(1);\n";
+      out << "   stack->Add(" << hname 
+         << (syserr ? ",\"e5\"" : "") << ");\n\n";
+    }
+    UShort_t    snn = fSNNString->GetUniqueID();
+    // const char* sys = fSysString->GetTitle();
+    TString eS;
+    if      (snn == 2750)     snn = 2760;
+    if      (snn < 1000)      eS = Form("%3dGeV", snn);
+    else if (snn % 1000 == 0) eS = Form("%dTeV", snn/1000);
+    else                      eS = Form("%4.2fTeV", float(snn)/1000);
+    out << "  if (l) {\n"
+       << "    TLegendEntry* e = l->AddEntry(\"\",\"" << eS << "\",\"pl\");\n"
+       << "    e->SetMarkerStyle(m);\n"
+       << "    e->SetMarkerColor(kBlack);\n"
+       << "  }\n"
+       << "}\n" << std::endl;
+  }
+             
   /* @} */
 
 
 
   //__________________________________________________________________
-  Bool_t      fShowOthers;   // Show other data
-  Bool_t      fShowAlice;    // Show ALICE published data
-  Bool_t      fShowRatios;   // Show ratios 
-  Bool_t      fShowLeftRight;// Show asymmetry 
-  UShort_t    fRebin;        // Rebinning factor 
-  Bool_t      fCutEdges;     // Whether to cut edges
-  TString     fTitle;        // Title on plot
-  TString     fHHDFile;      // File name of old results
-  TNamed*     fTrigString;   // Trigger string (read, or set)
-  TNamed*     fSNNString;    // Energy string (read, or set)
-  TNamed*     fSysString;    // Collision system string (read or set)
-  TAxis*      fVtxAxis;      // Vertex cuts (read or set)
-  TH1*        fForward;      // Results
-  TH1*        fForwardMC;    // MC results
-  TH1*        fForwardHHD;   // Old results
-  TH1*        fTruth;        // MC truth
-  TH1*        fCentral;      // Central region data
-  TH1*        fForwardSym;   // Symmetric extension
-  TH1*        fForwardMCSym; // Symmetric extension
-  TH1*        fForwardHHDSym;// Symmetric extension
-  TH1*        fTriggers;     // Number of triggers
-  RangeParam* fRangeParam;   // Parameter object for range zoom 
-  
+  /** 
+   * @{ 
+   * @name Options 
+   */
+  Bool_t       fShowRatios;   // Show ratios 
+  Bool_t       fShowLeftRight;// Show asymmetry 
+  Bool_t       fShowRings;    // Show rings too
+  Bool_t       fExport;       // Export results to file
+  Bool_t       fCutEdges;     // Whether to cut edges
+  Bool_t       fRemoveOuters; // Whether to remove outers
+  UShort_t     fShowOthers;   // Show other data
+  /* @} */
+  /** 
+   * @{ 
+   * @name Settings 
+   */
+  UShort_t     fRebin;        // Rebinning factor 
+  Double_t     fFwdSysErr;    // Systematic error in forward range
+  Double_t     fCenSysErr;    // Systematic error in central range 
+  TString      fTitle;        // Title on plot
+  TString      fClusterScale; // Scaling of clusters to tracklets      
+  /* @} */
+  /** 
+   * @{ 
+   * @name Read (or set) information 
+   */
+  TNamed*      fTrigString;   // Trigger string (read, or set)
+  TNamed*      fNormString;   // Normalisation string (read, or set)
+  TNamed*      fSNNString;    // Energy string (read, or set)
+  TNamed*      fSysString;    // Collision system string (read or set)
+  TAxis*       fVtxAxis;      // Vertex cuts (read or set)
+  TAxis*       fCentAxis;     // Centrality axis
+  /* @} */
+  /** 
+   * @{ 
+   * @name Resulting plots 
+   */
+  THStack*     fResults;      // Stack of results 
+  THStack*     fRatios;       // Stack of ratios 
+  THStack*     fLeftRight;    // Left-right asymmetry
+  TMultiGraph* fOthers;       // Older data 
+  TH1*         fTriggers;     // Number of triggers
+  TH1*         fTruth;        // Pointer to truth 
+  /* @} */
+  RangeParam*  fRangeParam;   // Parameter object for range zoom 
 };
 
+//____________________________________________________________________
+/** 
+ * Function to calculate 
+ * @f[
+ *  g(x;A_1,A_2,\sigma_1,\sigma_2) = 
+ *       A_1\left(\frac{1}{2\pi\sigma_1}e^{(x/\sigma_1)^2} - 
+ *           A_2\frac{1}{2\pi\sigma_2}e^{(x/\sigma_2)^2}\right)
+ * @f]
+ * 
+ * @param xp Pointer to x array
+ * @param pp Pointer to parameter array 
+ * 
+ * @return @f$g(x;A_1,A_2,\sigma_1,\sigma_2)@f$
+ */
+Double_t myFunc(Double_t* xp, Double_t* pp)
+{
+  Double_t x  = xp[0];
+  Double_t a1 = pp[0];
+  Double_t a2 = pp[1];
+  Double_t s1 = pp[2];
+  Double_t s2 = pp[3];
+  return a1*(TMath::Gaus(x, 0, s1) - a2 * TMath::Gaus(x, 0, s2));
+}
+
 //=== Stuff for auto zooming =========================================
 void UpdateRange(dNdetaDrawer::RangeParam* p)
 {
@@ -1348,7 +1979,6 @@ void UpdateRange(dNdetaDrawer::RangeParam* p)
   Int_t    last  = p->fMasterAxis->GetLast();
   Double_t x1    = p->fMasterAxis->GetBinCenter(first);
   Double_t x2    = p->fMasterAxis->GetBinCenter(last);
-  //Info("UpdateRange", "Range set to [%3d,%3d]->[%f,%f]", first, last, x1,x2);
 
   if (p->fSlave1Axis) { 
     Int_t i1 = p->fSlave1Axis->FindBin(x1);
@@ -1389,28 +2019,88 @@ void RangeExec(dNdetaDrawer::RangeParam* p)
   UpdateRange(p);
 }
 
-//=== Steering function ==============================================  
+//=== Steering functions
+//==============================================  
+void
+Usage()
+{
+  Info("DrawdNdeta", "Usage: DrawdNdeta(FILE,TITLE,REBIN,OTHERS,FLAGS)\n\n"
+       "  const char* FILE   File name to open (\"forward_root\")\n"
+       "  const char* TITLE  Title to put on plot (\"\")\n"
+       "  UShort_t    REBIN  Rebinning factor (1)\n"
+       "  UShort_t    OTHERS Other data to draw - more below (0x7)\n"
+       "  UShort_t    FLAGS  Visualisation flags - more below (0x7)\n\n"
+       " OTHERS is a bit mask of\n\n"
+       "  0x1   Show UA5 data (INEL,NSD, ppbar, 900GeV)\n"
+       "  0x2   Show CMS data (NSD, pp)\n"
+       "  0x4   Show published ALICE data (INEL,INEL>0,NSD, pp)\n"
+       "  0x8   Show event genertor data\n\n"
+       " FLAGS is a bit mask of\n\n"
+       "  0x1   Show ratios of data to other data and possibly MC\n"
+       "  0x2   Show left-right asymmetry\n"
+       "  0x4   Show systematic error band\n"
+       "  0x8   Show individual ring results (INEL only)\n"
+       "  0x10  Cut edges when rebinning\n"
+       "  0x20  Remove FMDxO points\n"
+       "  0x40  Do not make our own canvas\n"
+       );
+}
+
+//____________________________________________________________________
+/** 
+ * Draw @f$ dN/d\eta@f$ 
+ * 
+ * @param filename  File name 
+ * @param flags     Flags 
+ * @param title     Title 
+ * @param rebin     Rebinning factor 
+ * @param cutEdges  Whether to cut edges when rebinning
+ * @param sNN       (optional) Collision energy [GeV]
+ * @param sys       (optional) Collision system (1: pp, 2: PbPb)
+ * @param trg       (optional) Trigger (1: INEL, 2: INEL>0, 4: NSD)   
+ * @param vzMin     Least @f$ v_z@f$
+ * @param vzMax     Largest @f$ v_z@f$
+ *
+ * @ingroup pwg2_forward_dndeta
+ */
 void
 DrawdNdeta(const char* filename="forward_dndeta.root", 
-          Int_t       flags=0xf,
           const char* title="",
           UShort_t    rebin=5, 
-          Bool_t      cutEdges=false)
+          UShort_t    others=0x7,
+          UShort_t    flags=0x7,
+          UShort_t    sNN=0, 
+          UShort_t    sys=0,
+          UShort_t    trg=0,
+          Float_t     vzMin=999, 
+          Float_t     vzMax=-999)
 {
-  dNdetaDrawer d;
+  TString fname(filename);
+  fname.ToLower();
+  if (fname.CompareTo("help") == 0 || 
+      fname.CompareTo("--help") == 0) { 
+    Usage();
+    return;
+  }
+  dNdetaDrawer* pd = new dNdetaDrawer;
+  dNdetaDrawer& d = *pd;
   d.SetRebin(rebin);
-  d.SetCutEdges(cutEdges);
   d.SetTitle(title);
-  d.SetHHDFile("");
-  d.SetShowOthers(flags & 0x1);
-  d.SetShowAlice(flags & 0x2);
-  d.SetShowRatios(flags & 0x4);
-  d.SetShowLeftRight(flags & 0x8);
+  d.SetShowOthers(others);
+  d.SetShowRatios(flags & 0x1);
+  d.SetShowLeftRight(flags & 0x2);
+  d.SetForwardSysError(flags & 0x4 ? 0.076 : 0);
+  d.SetShowRings(flags & 0x8);
+  d.SetCutEdges(flags & 0x10);
+  d.fRemoveOuters = (flags & 0x20);
+  d.SetExport(flags & 0x40);
+  // d.fClusterScale = "1.06 -0.003*x +0.0119*x*x";
   // Do the below if your input data does not contain these settings 
-  // d.SetSNN(900);            // Collision energy per nucleon pair (GeV)
-  // d.SetSys(1);              // Collision system (1:pp, 2:PbPB)
-  // d.SetTrigger(1);          // Collision trigger (1:INEL, 2:INEL>0, 4:NSD)
-  // d.SetVertexRange(-10,10); // Collision vertex range (cm)
+  if (sNN > 0) d.SetSNN(sNN);     // Collision energy per nucleon pair (GeV)
+  if (sys > 0) d.SetSys(sys);     // Collision system (1:pp, 2:PbPB)
+  if (trg > 0) d.SetTrigger(trg); // Collision trigger (1:INEL, 2:INEL>0, 4:NSD)
+  if (vzMin < 999 && vzMax > -999) 
+    d.SetVertexRange(vzMin,vzMax); // Collision vertex range (cm)
   d.Run(filename);
 }
 //____________________________________________________________________