Th1 scaling axis

Hello, following an old topic Can we shift histogram for several channels? - #2 by Pepe_Le_Pew I wrote this macro to scale x-axis.

scaleaxis.cpp (1.6 KB)

Now I need to get a,b,c parameters from terminal when running the macro.
I know I can get them replacing

void scaleaxis()
by
void scaleaxis(double a, double b, double c)

and running as

.x scaleaxis.cpp(0,10,0)

scaleaxis.cpp (1.6 KB)

but I’m having problem to pass a,b,c to the ScaleX function, so that it can evaluate

v = a + b*x + c*x*x;

without defining a,b,c in it.

How to do that?

root [2] .x scaleaxis.cpp(0,10,0)
In file included from input_line_10:1:
scaleaxis.cpp:40:10: error: use of undeclared identifier 'a'
  invoke(a,b,c, &scaleaxis);
         ^
scaleaxis.cpp:40:12: error: use of undeclared identifier 'b'
  invoke(a,b,c, &scaleaxis);
           ^
scaleaxis.cpp:40:14: error: use of undeclared identifier 'c'
  invoke(a,b,c, &scaleaxis);
             ^
scaleaxis.cpp:40:18: error: use of undeclared identifier 'scaleaxis'
  invoke(a,b,c, &scaleaxis);
                 ^
scaleaxis.cpp:41:19: error: use of undeclared identifier 'a'
  cout << "a=" << a << "b=" << b << "c=" << c << endl;
                  ^
scaleaxis.cpp:41:32: error: use of undeclared identifier 'b'
  cout << "a=" << a << "b=" << b << "c=" << c << endl;
                               ^
scaleaxis.cpp:41:45: error: use of undeclared identifier 'c'
  cout << "a=" << a << "b=" << b << "c=" << c << endl;
                                            ^
scaleaxis.cpp:42:7: error: use of undeclared identifier 'a'
  v = a + b*x + c*x*x;
      ^
scaleaxis.cpp:42:11: error: use of undeclared identifier 'b'
  v = a + b*x + c*x*x;
          ^
scaleaxis.cpp:42:17: error: use of undeclared identifier 'c'
  v = a + b*x + c*x*x;

scaleaxis.cpp (1.7 KB)

Yes, the error message is correct. See your code:

Double_t ScaleX(Double_t x)
{
  Double_t v;
  invoke(a,b,c, &scaleaxis);
  cout << "a=" << a << "b=" << b << "c=" << c << endl;
  v = a + b*x + c*x*x;
  return v;
}

Hi @couet,

I replaced

Double_t ScaleX(Double_t x)

by

Double_t ScaleX(Double_t x, double a, double b, double c, void scaleaxis(double a, double b, double c))

but I got this error

root [0]
Processing scaleaxis.cpp...
In file included from input_line_8:1:
scaleaxis.cpp:40:3: error: no matching function for call to 'invoke'
  invoke(a,b,c, &scaleaxis);
  ^~~~~~
scaleaxis.cpp:32:6: note: candidate function not viable: no known conversion from 'void (**)(double, double, double)' to 'void (*)(double, double, double)' for 4th argument; remove &
void invoke(double a, double b, double c, void (*func)(double, double, double))
     ^
software/gcc/10.2.0/lib/gcc/x86_64-pc-linux-gnu/10.2.0/../../../../include/c++/10.2.0/functional:85:5: note: candidate template ignored: substitution failure [with _Callable = double &, _Args = <double &, double &, void (**)(double, double, double)>]: no type named 'type' in 'std::invoke_result<double &, double &, double &, void (**)(double, double, double)>'
    invoke(_Callable&& __fn, _Args&&... __args)
    ^
In file included from input_line_8:1:
SimulazioniFatte/21Nepgamma/Risonanza_6998/scaleaxis.cpp:76:2: error: no matching function for call to 'ScaleXaxis'
        ScaleXaxis(h,ScaleX);
        ^~~~~~~~~~
SimulazioniFatte/21Nepgamma/Risonanza_6998/scaleaxis.cpp:65:6: note: candidate function not viable: no known conversion from 'Double_t (Double_t, double, double, double, void (*)(double, double, double))' (aka 'double (double, double, double, double, void (*)(double, double, double))') to 'Double_t (*)(Double_t)' (aka 'double (*)(double)') for 2nd argument
void ScaleXaxis(TH1 *h, Double_t (*Scale)(Double_t))

then I also removed the & (As written in the error) but now I get

Processing scaleaxis.cpp...
In file included from input_line_8:1:
scaleaxis.cpp:76:2: error: no matching function for call to 'ScaleXaxis'
        ScaleXaxis(h,ScaleX);
        ^~~~~~~~~~
scaleaxis.cpp:65:6: note: candidate function not viable: no known conversion from 'Double_t (Double_t, double, double, double, void (*)(double, double, double))' (aka 'double (double, double, double, double, void (*)(double, double, double))') to 'Double_t (*)(Double_t)' (aka 'double (*)(double)') for 2nd argument
void ScaleXaxis(TH1 *h, Double_t (*Scale)(Double_t))

scaleaxis.cpp (1.8 KB)

you call:

	ScaleXaxis(h,ScaleX);

But you do not have a such function (matching this signature).

Then, I replaced

void ScaleAxis(TAxis *a, Double_t (*Scale)(Double_t))

by

void ScaleAxis(TAxis *a, Double_t (*Scale)(Double_t, double, double, double, void(double, double, double)))

but I got

root [0]
Processing scaleaxis.cpp...
In file included from input_line_8:1:
scaleaxis.cpp:53:63: error: too few arguments to function call, expected 5, have 1
      for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i]);
                                                    ~~~~~     ^
scaleaxis.cpp:59:33: error: too few arguments to function call, expected 5, have 1
              Scale(a->GetXmin()),
              ~~~~~             ^
scaleaxis.cpp:60:33: error: too few arguments to function call, expected 5, have 1
              Scale(a->GetXmax()));
              ~~~~~             ^
scaleaxis.cpp:68:3: error: no matching function for call to 'ScaleAxis'
  ScaleAxis(h->GetXaxis(), Scale);
  ^~~~~~~~~
scaleaxis.cpp:47:6: note: candidate function not viable: no known conversion from 'Double_t (*)(Double_t)' (aka 'double (*)(double)') to 'Double_t (*)(Double_t, double, double, double, void (*)(double, double, double))' (aka 'double (*)(double, double, double, double, void (*)(double, double, double))') for 2nd argument
void ScaleAxis(TAxis *a, Double_t (*Scale)(Double_t, double, double, double, void(double, double, double)))
     ^
scaleaxis.cpp:76:2: error: no matching function for call to 'ScaleXaxis'
        ScaleXaxis(h,ScaleX);
        ^~~~~~~~~~
scaleaxis.cpp:65:6: note: candidate function not viable: no known conversion from 'Double_t (Double_t, double, double, double, void (*)(double, double, double))' (aka 'double (double, double, double, double, void (*)(double, double, double))') to 'Double_t (*)(Double_t)' (aka 'double (*)(double)') for 2nd argument
void ScaleXaxis(TH1 *h, Double_t (*Scale)(Double_t))
     ^
root [1]

and I’m not sure that I’m going to the right way, because in your link, the function was called as

cout << invoke(20, 10, &multiply) << '\n' ;

i.e. using the &, on the contrary, in my case the compiler asked to remove the &…then I’m not sure that I’m not making other mistakes

scaleaxis.cpp (1.8 KB)

That’s really elementary C++

your function’s signature is:

Double_t ScaleX(Double_t x, double a, double b, double c, void scaleaxis(double a, double b, double c))

And you call it with:

Scale(X[i]);

That’s why you get this error… read C++ doc …

I replaced

for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i],a,b,c,scalexaxis);

by

for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i],a,b,c,scalexaxis);

but I got

root [0]
Processing scaleaxis.cpp...
In file included from input_line_8:1:
scaleaxis.cpp:53:66: error: use of undeclared identifier 'b'
      for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i],a,b,c,scalexaxis);
                                                                 ^
scaleaxis.cpp:53:68: error: use of undeclared identifier 'c'
      for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i],a,b,c,scalexaxis);
                                                                   ^
scaleaxis.cpp:53:70: error: use of undeclared identifier 'scalexaxis'
      for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i],a,b,c,scalexaxis);
                                                                     ^
scaleaxis.cpp:59:33: error: too few arguments to function call, expected 5, have 1
              Scale(a->GetXmin()),
              ~~~~~             ^
scaleaxis.cpp:60:33: error: too few arguments to function call, expected 5, have 1
              Scale(a->GetXmax()));
              ~~~~~             ^
scaleaxis.cpp:68:3: error: no matching function for call to 'ScaleAxis'
  ScaleAxis(h->GetXaxis(), Scale);
  ^~~~~~~~~
scaleaxis.cpp:47:6: note: candidate function not viable: no known conversion from 'Double_t (*)(Double_t)' (aka 'double (*)(double)') to 'Double_t (*)(Double_t, double, double, double, void (*)(double, double, double))' (aka 'double (*)(double, double, double, double, void (*)(double, double, double))') for 2nd argument
void ScaleAxis(TAxis *a, Double_t (*Scale)(Double_t, double, double, double, void(double, double, double)))
     ^
scaleaxis.cpp:76:2: error: no matching function for call to 'ScaleXaxis'
        ScaleXaxis(h,ScaleX);
        ^~~~~~~~~~
scaleaxis.cpp:65:6: note: candidate function not viable: no known conversion from 'Double_t (Double_t, double, double, double, void (*)(double, double, double))' (aka 'double (double, double, double, double, void (*)(double, double, double))') to 'Double_t (*)(Double_t)' (aka 'double (*)(double)') for 2nd argument
void ScaleXaxis(TH1 *h, Double_t (*Scale)(Double_t))
     ^
root [1]

then I also replaced

void ScaleAxis(TAxis *a, Double_t (*Scale)(Double_t))

by

void ScaleAxis(TAxis *a, Double_t (*Scale)(Double_t, double, double, double, void(double, double, double)))
and added the invoke function in this function too, but still doesn’t work

Processing scaleaxis.cpp...
In file included from input_line_8:1:
scaleaxis.cpp:50:12: error: use of undeclared identifier 'b'
  invoke(a,b,c, scaleaxis);
           ^
scaleaxis.cpp:50:14: error: use of undeclared identifier 'c'
  invoke(a,b,c, scaleaxis);
             ^
scaleaxis.cpp:50:17: error: use of undeclared identifier 'scaleaxis'
  invoke(a,b,c, scaleaxis);
                ^
scaleaxis.cpp:54:66: error: use of undeclared identifier 'b'
      for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i],a,b,c,scalexaxis);
                                                                 ^
scaleaxis.cpp:54:68: error: use of undeclared identifier 'c'
      for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i],a,b,c,scalexaxis);
                                                                   ^
/nfs/luna02/casaburf/SimulazioniFatte/21Nepgamma/Risonanza_6998/scaleaxis.cpp:54:70: error: use of undeclared identifier 'scalexaxis'
      for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i],a,b,c,scalexaxis);
                                                                     ^
scaleaxis.cpp:60:33: error: too few arguments to function call, expected 5, have 1
              Scale(a->GetXmin()),
              ~~~~~             ^
scaleaxis.cpp:61:33: error: too few arguments to function call, expected 5, have 1
              Scale(a->GetXmax()));
              ~~~~~             ^
scaleaxis.cpp:69:3: error: no matching function for call to 'ScaleAxis'
  ScaleAxis(h->GetXaxis(), Scale);
  ^~~~~~~~~
scaleaxis.cpp:47:6: note: candidate function not viable: no known conversion from 'Double_t (*)(Double_t)' (aka 'double (*)(double)') to 'Double_t (*)(Double_t, double, double, double, void (*)(double, double, double))' (aka 'double (*)(double, double, double, double, void (*)(double, double, double))') for 2nd argument
void ScaleAxis(TAxis *a, Double_t (*Scale)(Double_t, double, double, double, void scaleaxis(double a, double b, double c)))
     ^
scaleaxis.cpp:77:2: error: no matching function for call to 'ScaleXaxis'
        ScaleXaxis(h,ScaleX);
        ^~~~~~~~~~
scaleaxis.cpp:66:6: note: candidate function not viable: no known conversion from 'Double_t (Double_t, double, double, double, void (*)(double, double, double))' (aka 'double (double, double, double, double, void (*)(double, double, double))') to 'Double_t (*)(Double_t)' (aka 'double (*)(double)') for 2nd argument
void ScaleXaxis(TH1 *h, Double_t (*Scale)(Double_t))
     ^
root [1]

scaleaxis.cpp (1.9 KB)

Same as before, the compiler tells you exactly what’s wrong:

use of undeclared identifier 'b'

Means exactly that: you are using a variable which is not declared. Again basic: In C++ all variable MUST be declared. So: declare them …

I made some changes based on the errors I got step by step.
Then I got this error

root [0]
Processing scaleaxis.cpp...
In file included from input_line_8:1:
scaleaxis.cpp:70:52: error: too few arguments to function call, expected 5, have 4
  ScaleAxis(h->GetXaxis(), Scale(c0,c1,c2,scaleaxis));
                           ~~~~~                   ^
scaleaxis.cpp:78:15: error: no matching function for call to 'ScaleX'
        ScaleXaxis(h,ScaleX(c0,c1,c2,scaleaxis));
                     ^~~~~~
scaleaxis.cpp:37:10: note: candidate function not viable: requires 5 arguments, but 4 were provided
Double_t ScaleX(Double_t x, double c0, double c1, double c2, void scaleaxis(double c0, double c1, double c2))
         ^
root [1]

using this macro

scaleaxis.cpp (2.2 KB)

then I replaced

ScaleAxis(h->GetXaxis(), Scale(c0,c1,c2,scaleaxis));

by

ScaleAxis(h->GetXaxis(), Scale(Double_t x, c0,c1,c2,scaleaxis));

and
ScaleXaxis(h,ScaleX(c0,c1,c2,scaleaxis));

by

ScaleXaxis(h,ScaleX(Double_t x,c0,c1,c2,scaleaxis));

but now I get

root [0]
Processing scaleaxis.cpp...
In file included from input_line_8:1:
scaleaxis.cpp:70:34: error: unexpected type name 'Double_t': expected expression
  ScaleAxis(h->GetXaxis(), Scale(Double_t x,c0,c1,c2,scaleaxis));
                                 ^
scaleaxis.cpp:78:22: error: unexpected type name 'Double_t': expected expression
        ScaleXaxis(h,ScaleX(Double_t x,c0,c1,c2,scaleaxis));
                            ^
root [1]

scaleaxis.cpp (2.3 KB)

Hi @couet, do you know how to solve it?

This is simple C++ . Check your code the error message is clear.
And please fix this kind of thing:

void invoke(double c0, double c1, double c2, void (*func)(double, double, double))
{
    return c0,c1,c2;
}

How tdo you ecpect this to work ? invoke is void … and even if it was double how do you expect the return with 3 values to work ?

Here is a working code. Start from that and adjuste it as you need:

double ScaleX(double x, double c0, double c1, double c2)
{
   double v;
   v = c0 + c1*x + c2*x*x;
   return v;
}

double invoke(double x, double c0, double c1, double c2, double (*func)(double, double, double, double))
{
   return func(x, c0, c1, c2);
}

void scaleaxis()
{
   double x  = 3;
   double c0 = 0;
   double c1 = 1;
   double c2 = 2;
   cout << invoke(x, c0, c1, c2, &ScaleX) << '\n';
}
root [0] 
Processing scaleaxis.C...
21
root [1] 

Thank you @couet, I tried this code

scaleaxis.cpp (1.8 KB)

but always getting error

root [0]
Processing scaleaxis.cpp...
In file included from input_line_8:1:
/nfs/luna02/casaburf/SimulazioniFatte/21Nepgamma/Risonanza_6998/scaleaxis.cpp:81:2: error: no matching function for call to 'ScaleXaxis'
        ScaleXaxis(h, c0, c1, c2, ScaleX);
        ^~~~~~~~~~
/nfs/luna02/casaburf/SimulazioniFatte/21Nepgamma/Risonanza_6998/scaleaxis.cpp:65:6: note: candidate function not viable: no known conversion from 'Double_t (Double_t, double, double, double)' (aka 'double (double, double, double, double)') to 'Double_t (*)(Double_t)' (aka 'double (*)(double)') for 5th argument
void ScaleXaxis(TH1 *h, double c0, double c1, double c2, Double_t (*Scale)(Double_t))
     ^

send me filein.hist

Here.

The following code is correct C++ wise. You can run it with:

root [0] .x scaleaxis.cpp(1,2,3)
a = 1, b = 2, c = 3
Info in <TCanvas::MakeDefCanvas>:  created default TCanvas with name c1
root [1] 
double ScaleX(double x, double a, double b, double c)
{
  double v;
  v = a + b*x + c*x*x;
  return v;
}


void ScaleAxis(TAxis *axis, double a, double b, double c, double (*Scale)(double, double, double, double))
{
   if (!axis) return;
   if (axis->GetXbins()->GetSize()) {
      TArrayD X(*(axis->GetXbins()));
      for(Int_t i = 0; i < X.GetSize(); i++) X[i] = Scale(X[i], a, b, c);
      axis->Set((X.GetSize() - 1), X.GetArray());
   } else {
      axis->Set(axis->GetNbins(),
              Scale(axis->GetXmin(), a, b, c),
              Scale(axis->GetXmax(), a, b, c));
   }
   return;
}


void scaleaxis(double a, double b, double c) {
   cout << "a = " << a << ", b = " << b << ", c = " << c << endl;

   TFile *RootIn = TFile::Open("filein.hist","READ");
   TFile *RootOut = new TFile("fileout.hist","RECREATE");
   TH1F *h = (TH1F*)RootIn->Get("zint");
   if (!h) return;

   TAxis *XAxis = h->GetXaxis();
   ScaleAxis(XAxis, a, b, c, &ScaleX);

   h->ResetStats();
   h->Draw();
   h->Write();
   RootOut->Write();
   RootIn->Close();
   RootOut->Close();
}

Now I let you fisnish it and check if does what you need. That’s your job.

Read the comments in the source code of the original ScaleAxis function.

Thank you @couet, your code works!

I also modiefied to try to use the ScaleXaxis function.

scaleaxis.cpp (1.7 KB)

and looks like to work too!

@Wile_E_Coyote what comment are you referring?

1 Like