TGraph with numpy: unexpected truncation

When creating a TGraph using PyROOT and numpy arrays I noticed something unexpected. Using the following:

g = ROOT.TGraph(3, np.array([1,2,3]), np.array([4.5,5.4,6.3]))

and later saving the graph to a file, the y values shown are correct, but the x values are all set to zero. Using instead

g = ROOT.TGraph(3, np.array([1.,2.,3.]), np.array([4.5,5.4,6.3]))

or

g = ROOT.TGraph(3, np.array([1,2,3], dtype='d'), np.array([4.5,5.4,6.3]))

the graph is displayed as expected.
I would expect the values to be cast to double, or that I should at least receive an error specifying that I am calling the following constructor:

TGraph (Int_t n, const Int_t *x, const Double_t *y)

which does not exist.

Interestingly, if I instead run the following:

g = ROOT.TGraph(3, np.array([1,2,3], dtype='i'), np.array([4.5,5.4,6.3]))

I get the error messages I would expect:

TypeError: none of the 11 overloaded methods succeeded. Full details:
  TGraph::TGraph() =>
    takes at most 0 arguments (3 given)
  TGraph::TGraph(int n) =>
    takes at most 1 arguments (3 given)
  TGraph::TGraph(const TGraph& gr) =>
    takes at most 1 arguments (3 given)
  TGraph::TGraph(const TVectorT<float>& vx, const TVectorT<float>& vy) =>
    takes at most 2 arguments (3 given)
  TGraph::TGraph(const TVectorT<double>& vx, const TVectorT<double>& vy) =>
    takes at most 2 arguments (3 given)
  TGraph::TGraph(const TH1* h) =>
    takes at most 1 arguments (3 given)
  TGraph::TGraph(const TF1* f, const char* option = "") =>
    takes at most 2 arguments (3 given)
  TGraph::TGraph(const char* filename, const char* format = "%lg %lg", const char* option = "") =>
    could not convert argument 1 (expected string or Unicode object, int found)
  TGraph::TGraph(int n, const int* x, const int* y) =>
    could not convert argument 3 ('numpy.ndarray' object has no attribute 'typecode' and given element size (8) do not match needed (4))
  TGraph::TGraph(int n, const float* x, const float* y) =>
    could not convert argument 3 ('numpy.ndarray' object has no attribute 'typecode' and given element size (8) do not match needed (4))
  TGraph::TGraph(int n, const double* x, const double* y) =>
    could not convert argument 2 ('numpy.ndarray' object has no attribute 'typecode' and given element size (4) do not match needed (8))

Please note that numpy's default type is np.int64 and the option dtype='i' uses np.int32. Therefore, something wrong happens when PyRoot looks at the former type.

This other post seems related: TGraphErrors taking numpy arrays as arguments.

Hi @bfontana ,
Thank you for reporting this issue.

I tried with current PyROOT in master and I can indeed reproduce your issue.

I also tried with experimental PyROOT, the new PyROOT we are working on, which will be made the default in mid 2020. In this new PyROOT, you get the right behaviour:

>>> import ROOT
>>> import numpy as np
>>> g = ROOT.TGraph(3, np.array([1,2,3]), np.array([4.5,5.4,6.3]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: none of the 11 overloaded methods succeeded. Full details:
  TGraph::TGraph(const TGraph& gr) =>
    TypeError: takes at most 1 arguments (3 given)
  TGraph::TGraph(const TH1* h) =>
    TypeError: takes at most 1 arguments (3 given)
  TGraph::TGraph(const TF1* f, const char* option = "") =>
    TypeError: takes at most 2 arguments (3 given)
  TGraph::TGraph(const TVectorT<float>& vx, const TVectorT<float>& vy) =>
    TypeError: takes at most 2 arguments (3 given)
  TGraph::TGraph(const TVectorT<double>& vx, const TVectorT<double>& vy) =>
    TypeError: takes at most 2 arguments (3 given)
  TGraph::TGraph() =>
    TypeError: takes at most 0 arguments (3 given)
  TGraph::TGraph(int n) =>
    TypeError: takes at most 1 arguments (3 given)
  TGraph::TGraph(const char* filename, const char* format = "%lg %lg", const char* option = "") =>
    TypeError: could not convert argument 1 (bad argument type for built-in operation)
  TGraph::TGraph(int n, const int* x, const int* y) =>
    TypeError: could not convert argument 2 (could not convert argument to buffer or nullptr)
  TGraph::TGraph(int n, const float* x, const float* y) =>
    TypeError: could not convert argument 2 (could not convert argument to buffer or nullptr)
  TGraph::TGraph(int n, const double* x, const double* y) =>
    TypeError: could not convert argument 2 (could not convert argument to buffer or nullptr)

We are now fixing only critical bugs in the current PyROOT, and most of the effort goes to the new PyROOT. Since this is solved in the new PyROOT and I understand you can live with your workaround for now (constructing the numpy array with floats), I will ask you to wait for the new PyROOT to come :slight_smile: Or, if you want to use it already, you just need to build ROOT with -Dpyroot_experimental=ON.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.