From 6a796f5f7c85f93e2bacf3269e8854c9a2f256b6 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 11 Mar 2020 10:01:49 -0400 Subject: [PATCH] [python] Add an "axis" function to the matplotlib module --- python/port/genhdr/qstrdefs.in.h | 2 +- python/port/mod/matplotlib/modpyplot.cpp | 59 ++++++++++++++++- python/port/mod/matplotlib/modpyplot.h | 6 ++ python/port/mod/matplotlib/modpyplot_table.c | 8 ++- python/port/mod/matplotlib/plot_controller.h | 16 +---- python/port/mod/matplotlib/plot_store.cpp | 68 ++++++++++++++++++++ python/port/mod/matplotlib/plot_store.h | 36 +++++++++-- python/port/mod/matplotlib/plot_view.cpp | 9 ++- python/port/mod/matplotlib/plot_view.h | 4 +- python/port/port.cpp | 2 + 10 files changed, 183 insertions(+), 27 deletions(-) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index be88dc99e..b52bb5921 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -74,11 +74,11 @@ Q(get_pixel) Q(set_pixel) // Matplotlib QSTRs +Q(axis) Q(plot) Q(pyplot) Q(show) - // Turtle QSTRs Q(turtle) Q(forward) diff --git a/python/port/mod/matplotlib/modpyplot.cpp b/python/port/mod/matplotlib/modpyplot.cpp index 065d6dd5c..482afe24d 100644 --- a/python/port/mod/matplotlib/modpyplot.cpp +++ b/python/port/mod/matplotlib/modpyplot.cpp @@ -1,17 +1,72 @@ extern "C" { #include "modpyplot.h" } +#include #include "port.h" #include "plot_controller.h" -Matplotlib::PlotController sPlotController; +Matplotlib::PlotStore * sPlotStore = nullptr; +Matplotlib::PlotController * sPlotController = nullptr; + +// Internal functions + +mp_obj_t modpyplot___init__() { + static Matplotlib::PlotStore plotStore; + static Matplotlib::PlotController plotController(&plotStore); + sPlotStore = &plotStore; + sPlotController = &plotController; + sPlotStore->flush(); + return mp_const_none; +} + +void modpyplot_gc_collect() { + if (sPlotStore != nullptr) { + return; + } + MicroPython::collectRootsAtAddress( + reinterpret_cast(&sPlotStore), + sizeof(Matplotlib::PlotStore) + ); +} + +/* axis(arg) + * - arg = [xmin, xmax, ymin, ymax] + * - arg = True, False + * Returns : xmin, xmax, ymin, ymax : float */ + +mp_obj_t modpyplot_axis(mp_obj_t arg) { + mp_obj_is_type(arg, &mp_type_enumerate); +#warning Use mp_obj_is_bool when upgrading uPy + if (mp_obj_is_type(arg, &mp_type_bool)) { + sPlotStore->setGrid(mp_obj_is_true(arg)); + } else { + mp_obj_t * items; + mp_obj_get_array_fixed_n(arg, 4, &items); + sPlotStore->setXMin(mp_obj_get_float(items[0])); + sPlotStore->setXMax(mp_obj_get_float(items[1])); + sPlotStore->setYMin(mp_obj_get_float(items[2])); + sPlotStore->setYMax(mp_obj_get_float(items[3])); + } + + // Build the return value + mp_obj_t coords[4]; + coords[0] = mp_obj_new_float(sPlotStore->xMin()); + coords[1] = mp_obj_new_float(sPlotStore->xMax()); + coords[2] = mp_obj_new_float(sPlotStore->yMin()); + coords[3] = mp_obj_new_float(sPlotStore->yMax()); + return mp_obj_new_tuple(4, coords); +} mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y) { + assert(sPlotStore != nullptr); + sPlotStore->addDots(x, y); // Ensure x and y are arrays // "Push" x and y on bigger arrays + return mp_const_none; } mp_obj_t modpyplot_show() { MicroPython::ExecutionEnvironment * env = MicroPython::ExecutionEnvironment::currentExecutionEnvironment(); - env->displayViewController(&sPlotController); + env->displayViewController(sPlotController); + return mp_const_none; } diff --git a/python/port/mod/matplotlib/modpyplot.h b/python/port/mod/matplotlib/modpyplot.h index e5d2853f9..1dca0b9d9 100644 --- a/python/port/mod/matplotlib/modpyplot.h +++ b/python/port/mod/matplotlib/modpyplot.h @@ -1,6 +1,12 @@ #include +mp_obj_t modpyplot___init__(); +void modpyplot_gc_collect(); + +mp_obj_t modpyplot_axis(mp_obj_t arg); mp_obj_t modpyplot_plot(mp_obj_t x, mp_obj_t y); + +// axis(*args, emit=True, **kwargs) //mp_obj_t grid(); //mp_obj_t scatter(mp_obj_t x, mp_obj_t y); //mp_obj_t bar(); diff --git a/python/port/mod/matplotlib/modpyplot_table.c b/python/port/mod/matplotlib/modpyplot_table.c index 41f0ef6f6..92ff1fae3 100644 --- a/python/port/mod/matplotlib/modpyplot_table.c +++ b/python/port/mod/matplotlib/modpyplot_table.c @@ -1,10 +1,14 @@ #include "modpyplot.h" -MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_plot_obj, modpyplot_plot); -MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot___init___obj, modpyplot___init__); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(modpyplot_axis_obj, modpyplot_axis); +STATIC MP_DEFINE_CONST_FUN_OBJ_2(modpyplot_plot_obj, modpyplot_plot); +STATIC MP_DEFINE_CONST_FUN_OBJ_0(modpyplot_show_obj, modpyplot_show); STATIC const mp_rom_map_elem_t modpyplot_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pyplot) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&modpyplot___init___obj) }, + { MP_ROM_QSTR(MP_QSTR_axis), MP_ROM_PTR(&modpyplot_axis_obj) }, { MP_ROM_QSTR(MP_QSTR_plot), MP_ROM_PTR(&modpyplot_plot_obj) }, { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&modpyplot_show_obj) }, }; diff --git a/python/port/mod/matplotlib/plot_controller.h b/python/port/mod/matplotlib/plot_controller.h index 27ab135b9..604da207f 100644 --- a/python/port/mod/matplotlib/plot_controller.h +++ b/python/port/mod/matplotlib/plot_controller.h @@ -1,20 +1,16 @@ #ifndef PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H #define PYTHON_MATPLOTLIB_PLOT_CONTROLLER_H -//#include #include #include #include "plot_view.h" #include "plot_store.h" -#include - namespace Matplotlib { class PlotController : public Shared::SimpleInteractiveCurveViewController { public: - PlotController() : Shared::SimpleInteractiveCurveViewController(nullptr, &m_cursor), m_store(), m_view(&m_store) {} - //virtual View * view() override { return &m_view; } + PlotController(PlotStore * store) : Shared::SimpleInteractiveCurveViewController(nullptr, &m_cursor), m_store(store), m_view(m_store) {} float cursorBottomMarginRatio() override { return 0.0f; @@ -22,22 +18,16 @@ public: virtual void reloadBannerView() override { } - bool handleEvent(Ion::Events::Event event) override { - printf("EVENT!!\n"); - return Shared::SimpleInteractiveCurveViewController::handleEvent(event); - } - virtual bool handleEnter() override { - printf("ENTER !!\n"); return false; } protected: Shared::CurveView * curveView() override { return &m_view; } - Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return &m_store; } + Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_store; } private: + PlotStore * m_store; Shared::CurveViewCursor m_cursor; - PlotStore m_store; PlotView m_view; }; diff --git a/python/port/mod/matplotlib/plot_store.cpp b/python/port/mod/matplotlib/plot_store.cpp index 7c9680232..681077f44 100644 --- a/python/port/mod/matplotlib/plot_store.cpp +++ b/python/port/mod/matplotlib/plot_store.cpp @@ -1 +1,69 @@ #include "plot_store.h" + +namespace Matplotlib { + +PlotStore::PlotStore() : Shared::InteractiveCurveViewRange(), + m_grid(false) +{ + flush(); +} + +void PlotStore::flush() { + m_dots = mp_obj_new_list(0, nullptr); +} + +void PlotStore::addDots(mp_obj_t x, mp_obj_t y) { + mp_obj_t items[2] = {x, y}; + mp_obj_t tuple = mp_obj_new_tuple(2, items); + mp_obj_list_append(m_dots, tuple); + + //mp_obj_tuple_t * t = static_cast(MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL))); + //t->items[0] = MP_OBJ_NEW_SMALL_INT(r); +} + +PlotStore::Dot PlotStore::dotAtIndex(int i) { + size_t numberOfTuples; + mp_obj_t * tuples; + mp_obj_list_get(m_dots, &numberOfTuples, &tuples); + + mp_obj_t firstTuple = tuples[0]; + size_t numberOfObjects; + mp_obj_t * objects; + mp_obj_tuple_get(firstTuple, &numberOfObjects, &objects); + + mp_obj_t x = objects[0]; + mp_obj_t y = objects[1]; + + size_t numberOfX; + mp_obj_t * xValues; + mp_obj_list_get(x, &numberOfX, &xValues); + size_t numberOfY; + mp_obj_t * yValues; + mp_obj_list_get(y, &numberOfY, &yValues); + + float goodX = mp_obj_get_float(xValues[i]); + float goodY = mp_obj_get_float(yValues[i]); + + return PlotStore::Dot(goodX, goodY, KDColorRed); +} + +int PlotStore::numberOfDots() { + size_t numberOfTuples; + mp_obj_t * tuples; + mp_obj_list_get(m_dots, &numberOfTuples, &tuples); + + mp_obj_t firstTuple = tuples[0]; + size_t numberOfObjects; + mp_obj_t * objects; + mp_obj_tuple_get(firstTuple, &numberOfObjects, &objects); + + mp_obj_t x = objects[0]; + + size_t numberOfX; + mp_obj_t * xValues; + mp_obj_list_get(x, &numberOfX, &xValues); + + return numberOfX; +} + +} diff --git a/python/port/mod/matplotlib/plot_store.h b/python/port/mod/matplotlib/plot_store.h index b7435ea9b..1cca7b3b9 100644 --- a/python/port/mod/matplotlib/plot_store.h +++ b/python/port/mod/matplotlib/plot_store.h @@ -3,19 +3,41 @@ //#include #include +extern "C" { +#include +} namespace Matplotlib { class PlotStore : public Shared::InteractiveCurveViewRange { public: - PlotStore() : Shared::InteractiveCurveViewRange() {} - /* - float xMin() const override { return 0.0f; } - float xMax() const override { return 1.0f; } - float yMin() const override { return 0.0f; } - float yMax() const override { return 1.0f; } - */ + PlotStore(); + void flush(); + + class Dot { + public: + Dot(float x, float y, KDColor color) : m_x(x), m_y(y), m_color(color) {} + float x() const { return m_x; } + float y() const { return m_y; } + KDColor color() const { return m_color; } + private: + float m_x; + float m_y; + KDColor m_color; + }; + + // TODO: Use an iterator here. It will be a lot faster + Dot dotAtIndex(int i); + int numberOfDots(); + + void addDots(mp_obj_t x, mp_obj_t y); + + void setGrid(bool grid) { m_grid = grid; } + bool grid() { return m_grid; } private: + mp_obj_t m_dots; + bool m_grid; + /* mp_obj_array_t * m_plots; mp_obj_array_t * m_arrows; diff --git a/python/port/mod/matplotlib/plot_view.cpp b/python/port/mod/matplotlib/plot_view.cpp index ca6f6c35b..904953bdc 100644 --- a/python/port/mod/matplotlib/plot_view.cpp +++ b/python/port/mod/matplotlib/plot_view.cpp @@ -4,10 +4,17 @@ namespace Matplotlib { void PlotView::drawRect(KDContext * ctx, KDRect rect) const { ctx->fillRect(rect, KDColorWhite); - drawGrid(ctx, rect); + if (m_store->grid()) { + drawGrid(ctx, rect); + } drawAxes(ctx, rect); drawLabelsAndGraduations(ctx, rect, Axis::Vertical, true); drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, true); + + for (int i=0; inumberOfDots(); i++) { + PlotStore::Dot dot = m_store->dotAtIndex(i); + drawDot(ctx, rect, dot.x(), dot.y(), dot.color()); + } } } diff --git a/python/port/mod/matplotlib/plot_view.h b/python/port/mod/matplotlib/plot_view.h index 2514c4fe2..5e01f8ed1 100644 --- a/python/port/mod/matplotlib/plot_view.h +++ b/python/port/mod/matplotlib/plot_view.h @@ -8,8 +8,10 @@ namespace Matplotlib { class PlotView : public Shared::LabeledCurveView { public: - PlotView(PlotStore * s) : Shared::LabeledCurveView(s) {} + PlotView(PlotStore * s) : Shared::LabeledCurveView(s), m_store(s) {} void drawRect(KDContext * ctx, KDRect rect) const override; +private: + PlotStore * m_store; }; } diff --git a/python/port/port.cpp b/python/port/port.cpp index 5c56064cc..d727332a4 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -20,6 +20,7 @@ extern "C" { #include "py/stackctrl.h" #include "mphalport.h" #include "mod/turtle/modturtle.h" +#include "mod/matplotlib/modpyplot.h" } static MicroPython::ScriptProvider * sScriptProvider = nullptr; @@ -176,6 +177,7 @@ void gc_collect(void) { gc_collect_start(); modturtle_gc_collect(); + modpyplot_gc_collect(); /* get the registers. * regs is the also the last object on the stack so the stack is bound by