Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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/API.h"
13
14#include "../../cppyy/CPyCppyy/src/CPyCppyy.h"
15#include "../../cppyy/CPyCppyy/src/CPPInstance.h"
16#include "../../cppyy/CPyCppyy/src/ProxyWrappers.h"
17
18#include "PyROOTPythonize.h"
19#include "ROOT/RConfig.hxx"
20#include "TInterpreter.h"
21
22#include <utility> // std::pair
23#include <sstream> // std::stringstream
24
25////////////////////////////////////////////////////////////////////////////
26/// \brief Make an RDataFrame from a dictionary of numpy arrays
27/// \param[in] self Always null, since this is a module function.
28/// \param[in] pydata Dictionary with numpy arrays
29///
30/// This function takes a dictionary of numpy arrays and creates an RDataFrame
31/// using the keys as column names and the numpy arrays as data.
33{
34 if (!pydata) {
35 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Invalid Python object.");
36 return NULL;
37 }
38
39 if (!PyDict_Check(pydata)) {
40 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Python object is not a dictionary.");
41 return NULL;
42 }
43
44 if (PyDict_Size(pydata) == 0) {
45 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Dictionary is empty.");
46 return NULL;
47 }
48
49
50 // Add PyObject (dictionary) holding RVecs to data source
51 std::stringstream code;
52 code << "ROOT::Internal::RDF::MakeNumpyDataFrame(";
53 std::stringstream pyaddress;
54 auto pyvecs = PyDict_New();
55#ifdef _MSC_VER
56 pyaddress << "0x";
57#endif
58 pyaddress << pyvecs;
59 code << "reinterpret_cast<PyObject*>(" << pyaddress.str() << "), ";
60
61 // Iterate over dictionary, convert numpy arrays to RVecs and put together interpreter code
62 PyObject *key, *value;
63 Py_ssize_t pos = 0;
64 const auto size = PyObject_Size(pydata);
65 auto counter = 0u;
66 while (PyDict_Next(pydata, &pos, &key, &value)) {
67 // Get name of key
68 if (!CPyCppyy_PyText_Check(key)) {
69 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Dictionary key is not convertible to a string.");
70 return NULL;
71 }
72 std::string keystr = CPyCppyy_PyText_AsString(key);
73
74 // Convert value to RVec and attach to dictionary
75 auto pyvec = PyROOT::AsRVec(NULL, value);
76 if (pyvec == NULL) {
77 PyErr_SetString(PyExc_RuntimeError,
78 ("Object not convertible: Dictionary entry " + keystr + " is not convertible with AsRVec.").c_str());
79 return NULL;
80 }
81 PyDict_SetItem(pyvecs, key, pyvec);
82 Py_DECREF(pyvec);
83
84 // Add pairs of column name and associated RVec to signature
85 std::string vectype = Cppyy::GetScopedFinalName(((CPyCppyy::CPPInstance*)pyvec)->ObjectIsA());
86 std::stringstream vecaddress;
87#ifdef _MSC_VER
88 vecaddress << "0x";
89#endif
90 vecaddress << ((CPyCppyy::CPPInstance*)pyvec)->GetObject();
91 code << "std::pair<std::string, " << vectype << "*>(\"" + keystr
92 << "\", reinterpret_cast<" << vectype+ "*>(" << vecaddress.str() << "))";
93 if (counter != size - 1) {
94 code << ",";
95 } else {
96 code << ");";
97 }
98 counter++;
99 }
100
101 // Create RDataFrame and build Python proxy
102 const auto err = gInterpreter->Declare("#include \"ROOT/RNumpyDS.hxx\"");
103 if (!err) {
104 PyErr_SetString(PyExc_RuntimeError, "Failed to find \"ROOT/RNumpyDS.hxx\".");
105 return NULL;
106 }
107 const auto codeStr = code.str();
108 auto address = (void*) gInterpreter->Calc(codeStr.c_str());
109 const auto pythonOwns = true;
110 auto pyobj = CPyCppyy::Instance_FromVoidPtr(address, "ROOT::RDataFrame", pythonOwns);
111
112 // Bind pyobject holding adopted memory to the RVec
113 if (PyObject_SetAttrString(pyobj, "__data__", pyvecs)) {
114 PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Failed to set dictionary as attribute __data__.");
115 return NULL;
116 }
117 Py_DECREF(pyvecs);
118
119 return pyobj;
120}
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:76
#define CPyCppyy_PyText_Check
Definition CPyCppyy.h:74
_object PyObject
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
#define gInterpreter
CPYCPPYY_EXTERN PyObject * Instance_FromVoidPtr(void *addr, const std::string &classname, bool python_owns=false)
Definition API.cxx:118
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
PyObject * MakeNumpyDataFrameImpl(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:30