@@ -417,6 +417,102 @@ PyObject* get_array(const std::vector<Numeric>& v)
417
417
418
418
#endif // WITHOUT_NUMPY
419
419
420
+ #ifdef USE_VARIADIC_TEMPLATES_ARGS
421
+
422
+ // ---------------------------------------------
423
+ // Analyse des keywords dans un tuple
424
+ //
425
+ std::pair<std::string, PyObject*> analyze_key_value (const char * key, const bool value) {
426
+ return {key, value ? Py_True : Py_False};
427
+ }
428
+
429
+ std::pair<std::string, PyObject*> analyze_key_value (const char * key, const int value) {
430
+ return {key, PyLong_FromLong (value)};
431
+ }
432
+
433
+ std::pair<std::string, PyObject*> analyze_key_value (const char * key, const long value) {
434
+ return {key, PyLong_FromLong (value)};
435
+ }
436
+
437
+ std::pair<std::string, PyObject*> analyze_key_value (const char * key, const double value) {
438
+ return {key, PyFloat_FromDouble (value)};
439
+ }
440
+
441
+ std::pair<std::string, PyObject*> analyze_key_value (const char * key, const char * value) {
442
+ return {key, PyString_FromString (value)};
443
+ }
444
+
445
+ std::pair<std::string, PyObject*> analyze_key_value (const char * key, const std::string& value) {
446
+ PyObject* str_value = PyString_FromString (value.c_str ());
447
+ return {key, str_value};
448
+ }
449
+
450
+ std::pair<std::string, PyObject*> analyze_key_value (const char * key, const std::vector<double >& value) {
451
+ // PyObject* py_levels = PyList_New(value.size());
452
+ // for (size_t i = 0; i < value.size(); ++i) {
453
+ // PyList_SetItem(py_levels, i, PyFloat_FromDouble(value.at(i)));
454
+ // }
455
+ return {key, get_array (value)};
456
+ }
457
+
458
+ std::pair<std::string, PyObject*> analyze_key_value (const char * key, const std::vector<int >& value) {
459
+ PyObject* args = PyTuple_New (value.size ());
460
+ for (size_t i = 0 ; i < value.size (); ++i) {
461
+ PyTuple_SetItem (args, i, PyLong_FromLong (value.at (i)));
462
+ }
463
+ return {key, get_array (value)};
464
+ }
465
+
466
+ template <class Tuple , std::size_t N>
467
+ struct AnalyzeKeywordsHelper {
468
+ static void analyze_keywords (const Tuple& kw, PyObject* keywords) {
469
+ AnalyzeKeywordsHelper<Tuple, N-2 >::analyze_keywords (kw, keywords);
470
+ std::string key;
471
+ PyObject* value;
472
+ std::tie (key, value) = analyze_key_value (std::get<N-2 >(kw), std::get<N-1 >(kw));
473
+ PyDict_SetItemString (keywords, key.c_str (), value);
474
+ Py_DECREF (value); // @TST
475
+ }
476
+ };
477
+
478
+ template <class Tuple >
479
+ struct AnalyzeKeywordsHelper <Tuple, 2 > {
480
+ static void analyze_keywords (const Tuple& kw, PyObject* keywords) {
481
+ std::string key;
482
+ PyObject* value;
483
+ std::tie (key, value) = analyze_key_value (std::get<0 >(kw), std::get<1 >(kw));
484
+ PyDict_SetItemString (keywords, key.c_str (), value);
485
+ Py_DECREF (value); // @TST
486
+ }
487
+ };
488
+
489
+ template <class ... Args>
490
+ PyObject* analyze_keywords (const std::tuple<Args...>& kw) {
491
+ // Inutile de vérifier que la longueur du tuple est un multiple de 2,
492
+ // car comme on avance de 2 en 2, l'instanciation du template ne peut pas se faire pour
493
+ // un tuple qui n'a pas un nombre pair d'items.
494
+ PyObject* keywords = PyDict_New ();
495
+ AnalyzeKeywordsHelper<decltype (kw), sizeof ...(Args)>::analyze_keywords (kw, keywords);
496
+ return keywords;
497
+ }
498
+
499
+ // ----------
500
+ // Identity type conversion to PyObject* (for functions `figure(Identity, tuple<Args...>&)` and `close(Identity)`)
501
+ //
502
+ PyObject* get_pyobject_from (const int value) {
503
+ return PyLong_FromLong (value);
504
+ }
505
+
506
+ PyObject* get_pyobject_from (const char * value) {
507
+ return PyString_FromString (value);
508
+ }
509
+
510
+ PyObject* get_pyobject_from (const std::string& value) {
511
+ return PyString_FromString (value.c_str ());
512
+ }
513
+ #endif // USE_VARIADIC_TEMPLATES_ARGS
514
+
515
+
420
516
template <typename Numeric>
421
517
bool plot (const std::vector<Numeric> &x, const std::vector<Numeric> &y, const std::map<std::string, std::string>& keywords)
422
518
{
@@ -739,35 +835,57 @@ bool hist(const std::vector<Numeric>& y, long bins=10,std::string color="b",
739
835
#endif // WITH_OPENCV
740
836
#endif // WITHOUT_NUMPY
741
837
838
+ template <typename NumericX, typename NumericY>
839
+ bool __scatter (const std::vector<NumericX>& x,
840
+ const std::vector<NumericY>& y,
841
+ PyObject* kwargs)
842
+ {
843
+ assert (x.size () == y.size ());
844
+
845
+ PyObject* xarray = get_array (x);
846
+ PyObject* yarray = get_array (y);
847
+
848
+ PyObject* args = PyTuple_New (2 );
849
+ PyTuple_SetItem (args, 0 , xarray);
850
+ PyTuple_SetItem (args, 1 , yarray);
851
+
852
+ PyObject* res = PyObject_Call (detail::_interpreter::get ().s_python_function_scatter , args, kwargs);
853
+
854
+ Py_DECREF (args);
855
+ Py_DECREF (kwargs);
856
+
857
+ if (!res) {
858
+ throw std::runtime_error (" Call to scatter(x, y [, marker]) failed." );
859
+ }
860
+
861
+ Py_DECREF (res);
862
+
863
+ return res;
864
+ }
865
+
866
+ // generic form
867
+ template <typename Numeric, class ... Args>
868
+ inline bool scatter (const std::vector<Numeric>& x, const std::vector<Numeric>& y, const std::tuple<Args...>& keywords)
869
+ {
870
+ PyObject* kwargs = analyze_keywords (keywords);
871
+ return __scatter (x, y, kwargs);
872
+ }
873
+
874
+ // specialized form
742
875
template <typename NumericX, typename NumericY>
743
876
bool scatter (const std::vector<NumericX>& x,
744
877
const std::vector<NumericY>& y,
745
878
const double s=1.0 , // The marker size in points**2
746
879
const std::unordered_map<std::string, std::string> & keywords = {})
747
880
{
748
- assert (x.size () == y.size ());
749
-
750
- PyObject* xarray = get_array (x);
751
- PyObject* yarray = get_array (y);
752
-
753
881
PyObject* kwargs = PyDict_New ();
754
882
PyDict_SetItemString (kwargs, " s" , PyLong_FromLong (s));
755
883
for (const auto & it : keywords)
756
884
{
757
885
PyDict_SetItemString (kwargs, it.first .c_str (), PyString_FromString (it.second .c_str ()));
758
886
}
759
887
760
- PyObject* plot_args = PyTuple_New (2 );
761
- PyTuple_SetItem (plot_args, 0 , xarray);
762
- PyTuple_SetItem (plot_args, 1 , yarray);
763
-
764
- PyObject* res = PyObject_Call (detail::_interpreter::get ().s_python_function_scatter , plot_args, kwargs);
765
-
766
- Py_DECREF (plot_args);
767
- Py_DECREF (kwargs);
768
- if (res) Py_DECREF (res);
769
-
770
- return res;
888
+ return __scatter (x, y, kwargs);
771
889
}
772
890
773
891
template <typename Numeric>
@@ -1246,6 +1364,36 @@ inline long figure(long number = -1)
1246
1364
return figureNumber;
1247
1365
}
1248
1366
1367
+ template <typename Identity, class ... Args>
1368
+ inline Identity figure (Identity number, const std::tuple<Args...>& keywords)
1369
+ {
1370
+ // Identity est de type int ou string
1371
+ PyObject* args = PyTuple_New (1 );
1372
+ PyTuple_SetItem (args, 0 , get_pyobject_from (number));
1373
+
1374
+ PyObject* kwargs = analyze_keywords (keywords);
1375
+
1376
+ PyObject* res = nullptr ;
1377
+ res = PyObject_Call (detail::_interpreter::get ().s_python_function_figure , args, kwargs);
1378
+
1379
+ Py_DECREF (args);
1380
+ Py_DECREF (kwargs);
1381
+
1382
+ if (!res) {
1383
+ PyErr_Print ();
1384
+ throw std::runtime_error (" Call to pyplot.figure(num) failed." );
1385
+ }
1386
+
1387
+ PyObject* num = PyObject_GetAttrString (res, " number" );
1388
+ if (!num) throw std::runtime_error (" Could not get number attribute of figure object" );
1389
+ auto figureNumber = static_cast <Identity>(PyLong_AsLong (num));
1390
+
1391
+ Py_DECREF (num);
1392
+ Py_DECREF (res);
1393
+
1394
+ return figureNumber;
1395
+ }
1396
+
1249
1397
inline bool fignum_exists (long number)
1250
1398
{
1251
1399
// Make sure interpreter is initialised
@@ -1660,6 +1808,23 @@ inline void close()
1660
1808
Py_DECREF (res);
1661
1809
}
1662
1810
1811
+ template <typename Identity>
1812
+ inline void close (Identity num)
1813
+ {
1814
+ PyObject* args = PyTuple_New (1 );
1815
+ PyTuple_SetItem (args, 0 , get_pyobject_from (num));
1816
+
1817
+ PyObject* res = PyObject_CallObject (detail::_interpreter::get ().s_python_function_close , args);
1818
+
1819
+ Py_DECREF (args);
1820
+
1821
+ if (!res) {
1822
+ throw std::runtime_error (" Call to close(num) failed." );
1823
+ }
1824
+
1825
+ Py_DECREF (res);
1826
+ }
1827
+
1663
1828
inline void xkcd () {
1664
1829
PyObject* res;
1665
1830
PyObject *kwargs = PyDict_New ();
0 commit comments