Logo ROOT  
Reference Guide
RDataFramePyz.cxx
Go to the documentation of this file.
1// Author: Stefan Wunsch CERN 04/2019
2// Original PyROOT code by Wim Lavrijsen, LBL
3
4/*************************************************************************
5 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "CPyCppyy.h"
13#include "CPPInstance.h"
14#include "ProxyWrappers.h"
15#include "PyROOTPythonize.h"
16#include "RConfig.h"
17#include "TInterpreter.h"
18#include "CPyCppyy/API.h"
19
20#include <utility> // std::pair
21#include <sstream> // std::stringstream
22
23////////////////////////////////////////////////////////////////////////////
24/// \brief Make an RDataFrame from a dictionary of numpy arrays
25/// \param[in] pydata Dictionary with numpy arrays
26///
27/// This function takes a dictionary of numpy arrays and creates an RDataFrame
28/// using the keys as column names and the numpy arrays as data.
30{
31 if (!pydata) {
32 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Invalid Python object.");
33 return NULL;
34 }
35
36 if (!PyDict_Check(pydata)) {
37 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Python object is not a dictionary.");
38 return NULL;
39 }
40
41 if (PyDict_Size(pydata) == 0) {
42 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Dictionary is empty.");
43 return NULL;
44 }
45
46
47 // Add PyObject (dictionary) holding RVecs to data source
48 std::stringstream code;
49 code << "ROOT::Internal::RDF::MakeNumpyDataFrame(";
50 std::stringstream pyaddress;
51 auto pyvecs = PyDict_New();
52 pyaddress << pyvecs;
53 code << "reinterpret_cast<PyObject*>(" << pyaddress.str() << "), ";
54
55 // Iterate over dictionary, convert numpy arrays to RVecs and put together interpreter code
56 PyObject *key, *value;
57 Py_ssize_t pos = 0;
58 const auto size = PyObject_Size(pydata);
59 auto counter = 0u;
60 while (PyDict_Next(pydata, &pos, &key, &value)) {
61 // Get name of key
62 if (!CPyCppyy_PyText_Check(key)) {
63 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Dictionary key is not convertible to a string.");
64 return NULL;
65 }
66 std::string keystr = CPyCppyy_PyText_AsString(key);
67
68 // Convert value to RVec and attach to dictionary
69 auto pyvec = PyROOT::AsRVec(NULL, value);
70 if (pyvec == NULL) {
71 PyErr_SetString(PyExc_RuntimeError,
72 ("Object not convertible: Dictionary entry " + keystr + " is not convertible with AsRVec.").c_str());
73 return NULL;
74 }
75 PyDict_SetItem(pyvecs, key, pyvec);
76 Py_DECREF(pyvec);
77
78 // Add pairs of column name and associated RVec to signature
79 std::string vectype = Cppyy::GetScopedFinalName(((CPyCppyy::CPPInstance*)pyvec)->ObjectIsA());
80 std::stringstream vecaddress;
81 vecaddress << ((CPyCppyy::CPPInstance*)pyvec)->GetObject();
82 code << "std::pair<std::string, " << vectype << "*>(\"" + keystr
83 << "\", reinterpret_cast<" << vectype+ "*>(" << vecaddress.str() << "))";
84 if (counter != size - 1) {
85 code << ",";
86 } else {
87 code << ");";
88 }
89 counter++;
90 }
91
92 // Create RDataFrame and build Python proxy
93 const auto err = gInterpreter->Declare("#include \"ROOT/RNumpyDS.hxx\"");
94 if (!err) {
95 PyErr_SetString(PyExc_RuntimeError, "Failed to find \"ROOT/RNumpyDS.hxx\".");
96 return NULL;
97 }
98 const auto codeStr = code.str();
99 auto address = (void*) gInterpreter->Calc(codeStr.c_str());
100 const auto pythonOwns = true;
101 auto pyobj = CPyCppyy::Instance_FromVoidPtr(address, "ROOT::RDataFrame", pythonOwns);
102
103 // Bind pyobject holding adopted memory to the RVec
104 if (PyObject_SetAttrString(pyobj, "__data__", pyvecs)) {
105 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Failed to set dictionary as attribute __data__.");
106 return NULL;
107 }
108 Py_DECREF(pyvecs);
109
110 return pyobj;
111}
#define CPyCppyy_PyText_AsString
Definition: CPyCppyy.h:97
#define CPyCppyy_PyText_Check
Definition: CPyCppyy.h:95
_object PyObject
Definition: PyMethodBase.h:41
#define gInterpreter
Definition: TInterpreter.h:556
CPYCPPYY_EXTERN PyObject * Instance_FromVoidPtr(void *addr, const std::string &classname, bool python_owns=false)
Definition: API.cxx:107
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
PyObject * MakeNumpyDataFrame(PyObject *self, PyObject *obj)
Make an RDataFrame from a dictionary of numpy arrays.
PyObject * AsRVec(PyObject *self, PyObject *obj)
Adopt memory of a Python object with array interface using an RVec.
Definition: RVecPyz.cxx:28