From b4e2b8aacb626986a1f0f1bf887e1b615a84f204 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 10 Oct 2017 14:50:24 +1100 Subject: [PATCH 01/10] simple plot works --- lib/matplotlib/backends/_tkagg.py | 61 ++++++++++++++++++++++++++++++ lib/matplotlib/backends/tkagg.py | 62 +++++++++++++++++++++---------- 2 files changed, 103 insertions(+), 20 deletions(-) create mode 100644 lib/matplotlib/backends/_tkagg.py diff --git a/lib/matplotlib/backends/_tkagg.py b/lib/matplotlib/backends/_tkagg.py new file mode 100644 index 000000000000..64a66df4ec78 --- /dev/null +++ b/lib/matplotlib/backends/_tkagg.py @@ -0,0 +1,61 @@ +from __future__ import (absolute_import, division, print_function, + unicode_literals) +from _tkinter.tklib_cffi import ffi as tkffi, lib as tklib +from _tkinter.tclobj import FromTclStringNDArray +import numpy as np + +app = None + +def PyAggImagePhoto(photoimage, data, mode): + interp = PyAggImagePhoto.interp + if not tklib.Tk_MainWindow(interp): + raise _tkinter.TclError("this isn't a Tk application") + photo = tklib.Tk_FindPhoto(interp, photoimage) + if not photo: + tklib.Tcl_AppendResult(interp, "destination photo must exist", 0) + return tklib.TCL_ERROR + img = FromTclStringNDArray(data) + has_bbox = False + pBlock = tkffi.new('Tk_PhotoImageBlock[1]') + block = pBlock[0] + block.pixelSize = 1 + if mode == 0: + block.offset[0] = block.offset[1] = block.offset[2] = 0 + nval = 1 + else: + block.offset[0] = 0 + block.offset[1] = 1 + block.offset[2] = 2 + if mode == 1: + block.offset[3] = 0 + block.pixelSize = 3 + nval = 3 + else: + block.offset[3] = 3 + block.pixelSize = 4 + if has_bbox: + block.width = destwidth + block.height = destheight + block.pitch = deststride + block.pixelPtr = destbuffer + + tklib.Tk_PhotoPutBlock_NoComposite(photo, pBlock, destx, desty, + destwidth, destheight); + + else: + block.width = shape[1] + block.height = shape[0] + block.pitch = img.strides[0] + block.pixelPtr = tkffi.from_buffer(img) + + #/* Clear current contents */ + tklib.Tk_PhotoBlank(photo); + #/* Copy opaque block to photo image, and leave the rest to TK */ + tklib.Tk_PhotoPutBlock_NoComposite(photo, pBlock, 0, 0, + block.width, block.height); + return tklib.TCL_OK + +def tkinit(tk): + tk.createcommand(b"PyAggImagePhoto", PyAggImagePhoto) + PyAggImagePhoto.interp = tk.interp + diff --git a/lib/matplotlib/backends/tkagg.py b/lib/matplotlib/backends/tkagg.py index 979bc3cc24fa..7cc301666142 100644 --- a/lib/matplotlib/backends/tkagg.py +++ b/lib/matplotlib/backends/tkagg.py @@ -7,29 +7,51 @@ import numpy as np from matplotlib.backends import _tkagg +from platform import python_implementation -def blit(photoimage, aggimage, bbox=None, colormode=1): - tk = photoimage.tk - - if bbox is not None: - bbox_array = bbox.__array__() - else: - bbox_array = None - data = np.asarray(aggimage) - try: - tk.call( - "PyAggImagePhoto", photoimage, - id(data), colormode, id(bbox_array)) - except Tk.TclError: +if python_implementation() == 'PyPy': + def blit(photoimage, aggimage, bbox=None, colormode=1): + tk = photoimage.tk + + if bbox is not None: + bbox_array = bbox.__array__() + else: + bbox_array = None + data = np.asarray(aggimage) + try: + tk.call( + "PyAggImagePhoto", photoimage, + data, colormode, bbox_array) + except Tk.TclError: + _tkagg.tkinit(tk) + tk.call("PyAggImagePhoto", photoimage, + data, colormode, bbox_array) + +else: + def blit(photoimage, aggimage, bbox=None, colormode=1): + tk = photoimage.tk + + if bbox is not None: + bbox_array = bbox.__array__() + else: + bbox_array = None + data = np.asarray(aggimage) try: + import pdb;pdb.set_trace() + tk.call( + "PyAggImagePhoto", photoimage, + id(data), colormode, id(bbox_array)) + except Tk.TclError: try: - _tkagg.tkinit(tk.interpaddr(), 1) - except AttributeError: - _tkagg.tkinit(id(tk), 0) - tk.call("PyAggImagePhoto", photoimage, - id(data), colormode, id(bbox_array)) - except (ImportError, AttributeError, Tk.TclError): - raise + import pdb;pdb.set_trace() + try: + _tkagg.tkinit(tk.interpaddr(), 1) + except AttributeError: + _tkagg.tkinit(id(tk), 0) + tk.call("PyAggImagePhoto", photoimage, + id(data), colormode, id(bbox_array)) + except (ImportError, AttributeError, Tk.TclError): + raise def test(aggimage): import time From 68492fbd6926cbb55dae4dc12519a16382eaa8d7 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 16 Oct 2017 21:25:58 +0300 Subject: [PATCH 02/10] flesh out bbox handling, fix mpl_PyFile_Dup for PyPy which is like python3 --- lib/matplotlib/backends/_tkagg.py | 41 ++++++++++++++++++++++--------- lib/matplotlib/backends/tkagg.py | 2 -- src/file_compat.h | 2 +- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/backends/_tkagg.py b/lib/matplotlib/backends/_tkagg.py index 64a66df4ec78..3c87f35f902e 100644 --- a/lib/matplotlib/backends/_tkagg.py +++ b/lib/matplotlib/backends/_tkagg.py @@ -6,23 +6,40 @@ app = None -def PyAggImagePhoto(photoimage, data, mode): +def PyAggImagePhoto(photoimage, data_as_str, mode, bbox_as_str=None): interp = PyAggImagePhoto.interp if not tklib.Tk_MainWindow(interp): raise _tkinter.TclError("this isn't a Tk application") photo = tklib.Tk_FindPhoto(interp, photoimage) if not photo: - tklib.Tcl_AppendResult(interp, "destination photo must exist", 0) + tklib.Tcl_AppendResult(interp, "destination photo must exist", 0) return tklib.TCL_ERROR - img = FromTclStringNDArray(data) - has_bbox = False + data = FromTclStringNDArray(data_as_str) + if bbox_as_str: + try: + bbox = FromTclStringNDArray(bbox_as_str) + except: + tklib.Tcl_AppendResult(interp, "bbox not valid", 0) + return tklib.TCL_ERROR + destx = int(bbox[0, 0]) + desty = data.shape[0] - int(bbox[1, 1]) + destwidth = int(bbox[1, 0] - bbox[0, 0]) + destheight = int(bbox[1, 1] - bbox[0, 1]) + deststride = 4 * destwidth; + destbuffer = np.empty([destheight, destwidth, 4], dtype='uint8') + has_bbox = True + destbuffer[:,:,:] = data[desty:desty+destheight, destx:destx+destwidth,:] + else: + has_bbox = False + destbuffer = None + destx = desty = destwidth = destheight = deststride = 0; pBlock = tkffi.new('Tk_PhotoImageBlock[1]') block = pBlock[0] block.pixelSize = 1 if mode == 0: block.offset[0] = block.offset[1] = block.offset[2] = 0 nval = 1 - else: + else: block.offset[0] = 0 block.offset[1] = 1 block.offset[2] = 2 @@ -37,25 +54,25 @@ def PyAggImagePhoto(photoimage, data, mode): block.width = destwidth block.height = destheight block.pitch = deststride - block.pixelPtr = destbuffer + block.pixelPtr = tkffi.from_buffer(destbuffer) tklib.Tk_PhotoPutBlock_NoComposite(photo, pBlock, destx, desty, destwidth, destheight); else: - block.width = shape[1] - block.height = shape[0] - block.pitch = img.strides[0] - block.pixelPtr = tkffi.from_buffer(img) + block.width = data.shape[1] + block.height = data.shape[0] + block.pitch = data.strides[0] + block.pixelPtr = tkffi.from_buffer(data) #/* Clear current contents */ tklib.Tk_PhotoBlank(photo); #/* Copy opaque block to photo image, and leave the rest to TK */ tklib.Tk_PhotoPutBlock_NoComposite(photo, pBlock, 0, 0, block.width, block.height); - return tklib.TCL_OK + return tklib.TCL_OK def tkinit(tk): tk.createcommand(b"PyAggImagePhoto", PyAggImagePhoto) PyAggImagePhoto.interp = tk.interp - + diff --git a/lib/matplotlib/backends/tkagg.py b/lib/matplotlib/backends/tkagg.py index 7cc301666142..12fb17b14189 100644 --- a/lib/matplotlib/backends/tkagg.py +++ b/lib/matplotlib/backends/tkagg.py @@ -37,13 +37,11 @@ def blit(photoimage, aggimage, bbox=None, colormode=1): bbox_array = None data = np.asarray(aggimage) try: - import pdb;pdb.set_trace() tk.call( "PyAggImagePhoto", photoimage, id(data), colormode, id(bbox_array)) except Tk.TclError: try: - import pdb;pdb.set_trace() try: _tkagg.tkinit(tk.interpaddr(), 1) except AttributeError: diff --git a/src/file_compat.h b/src/file_compat.h index a8f04eaeddca..42fdd162288c 100644 --- a/src/file_compat.h +++ b/src/file_compat.h @@ -48,7 +48,7 @@ extern "C" { /* * PyFile_* compatibility */ -#if PY3K +#if defined(PY3K) | defined(PYPY_VERSION) /* * Get a FILE* handle to the file represented by the Python object From 8e80a20381139d4d84d112e30056751fadb49d48 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 3 Nov 2017 16:51:21 +0200 Subject: [PATCH 03/10] change interface in PyAggImagePhoto to avoid id() --- lib/matplotlib/backends/tkagg.py | 63 +++++++++---------------- setupext.py | 2 - src/_tkagg.cpp | 80 ++++++++++++-------------------- 3 files changed, 52 insertions(+), 93 deletions(-) diff --git a/lib/matplotlib/backends/tkagg.py b/lib/matplotlib/backends/tkagg.py index 12fb17b14189..f563c5877404 100644 --- a/lib/matplotlib/backends/tkagg.py +++ b/lib/matplotlib/backends/tkagg.py @@ -7,49 +7,32 @@ import numpy as np from matplotlib.backends import _tkagg -from platform import python_implementation -if python_implementation() == 'PyPy': - def blit(photoimage, aggimage, bbox=None, colormode=1): - tk = photoimage.tk - - if bbox is not None: - bbox_array = bbox.__array__() - else: - bbox_array = None - data = np.asarray(aggimage) - try: - tk.call( - "PyAggImagePhoto", photoimage, - data, colormode, bbox_array) - except Tk.TclError: - _tkagg.tkinit(tk) - tk.call("PyAggImagePhoto", photoimage, - data, colormode, bbox_array) - -else: - def blit(photoimage, aggimage, bbox=None, colormode=1): - tk = photoimage.tk - - if bbox is not None: - bbox_array = bbox.__array__() - else: - bbox_array = None - data = np.asarray(aggimage) +def blit(photoimage, aggimage, bbox=None, colormode=1): + tk = photoimage.tk + + if bbox is not None: + bbox_array = bbox.__array__() + # x1, x2, y1, y2 + bboxptr = (bbox_array[0, 0], bbox_array[1, 0], bbox_array[0, 1], bbox_array[1, 1]) + else: + bboxptr = 0 + data = np.asarray(aggimage) + dataptr = (data.ctypes.data, data.shape[0], data.shape[1]) + try: + tk.call( + "PyAggImagePhoto", photoimage, + dataptr, colormode, bboxptr) + except Tk.TclError: try: - tk.call( - "PyAggImagePhoto", photoimage, - id(data), colormode, id(bbox_array)) - except Tk.TclError: try: - try: - _tkagg.tkinit(tk.interpaddr(), 1) - except AttributeError: - _tkagg.tkinit(id(tk), 0) - tk.call("PyAggImagePhoto", photoimage, - id(data), colormode, id(bbox_array)) - except (ImportError, AttributeError, Tk.TclError): - raise + _tkagg.tkinit(tk.interpaddr(), 1) + except AttributeError: + _tkagg.tkinit(tk, 0) + tk.call("PyAggImagePhoto", photoimage, + dataptr, colormode, bboxptr) + except (ImportError, AttributeError, Tk.TclError): + raise def test(aggimage): import time diff --git a/setupext.py b/setupext.py index 2856545fbc59..72996259e368 100644 --- a/setupext.py +++ b/setupext.py @@ -1513,13 +1513,11 @@ def runtime_check(self): def get_extension(self): sources = [ - 'src/py_converters.cpp', 'src/_tkagg.cpp' ] ext = make_extension('matplotlib.backends._tkagg', sources) self.add_flags(ext) - Numpy().add_flags(ext) LibAgg().add_flags(ext, add_sources=False) return ext diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index 830831400d50..67eb8744142d 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -13,16 +13,15 @@ #include #include -#include "py_converters.h" - // Include our own excerpts from the Tcl / Tk headers #include "_tkmini.h" #if defined(_MSC_VER) -# define SIZE_T_FORMAT "%Iu" +# define IMG_FORMAT "%Iu %d %d" #else -# define SIZE_T_FORMAT "%zu" +# define IMG_FORMAT "%zu %d %d" #endif +# define BBOX_FORMAT "%f %f %f %f" typedef struct { @@ -44,16 +43,15 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int { Tk_PhotoHandle photo; Tk_PhotoImageBlock block; - PyObject *bufferobj; // vars for blitting - PyObject *bboxo; - size_t aggl, bboxl; + size_t pdata; + int wdata, hdata; + float x1, x2, y1, y2; bool has_bbox; - uint8_t *destbuffer; + uint8_t *destbuffer, *buffer; int destx, desty, destwidth, destheight, deststride; - //unsigned long tmp_ptr; long mode; long nval; @@ -73,24 +71,14 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int TCL_APPEND_RESULT(interp, "destination photo must exist", (char *)NULL); return TCL_ERROR; } - /* get array (or object that can be converted to array) pointer */ - if (sscanf(argv[2], SIZE_T_FORMAT, &aggl) != 1) { - TCL_APPEND_RESULT(interp, "error casting pointer", (char *)NULL); - return TCL_ERROR; - } - bufferobj = (PyObject *)aggl; - - numpy::array_view buffer; - try { - buffer = numpy::array_view(bufferobj); - } catch (...) { - TCL_APPEND_RESULT(interp, "buffer is of wrong type", (char *)NULL); - PyErr_Clear(); + /* get buffer from str which is "ptr height width" */ + if (sscanf(argv[2], IMG_FORMAT, &pdata, &hdata, &wdata) != 3) { + TCL_APPEND_RESULT(interp, + "error reading data, expected ptr height width", + (char *)NULL); return TCL_ERROR; } - int srcheight = buffer.dim(0); - - /* XXX insert aggRenderer type check */ + buffer = (uint8_t*)pdata; /* get array mode (0=mono, 1=rgb, 2=rgba) */ mode = atol(argv[3]); @@ -100,27 +88,22 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int } /* check for bbox/blitting */ - if (sscanf(argv[4], SIZE_T_FORMAT, &bboxl) != 1) { - TCL_APPEND_RESULT(interp, "error casting pointer", (char *)NULL); - return TCL_ERROR; - } - bboxo = (PyObject *)bboxl; - - if (bboxo != NULL && bboxo != Py_None) { - agg::rect_d rect; - if (!convert_rect(bboxo, &rect)) { - return TCL_ERROR; - } - + if (sscanf(argv[4], BBOX_FORMAT, &x1, &x2, &y1, &y2) == 4) { has_bbox = true; + } + else { + has_bbox = false; + } - destx = (int)rect.x1; - desty = srcheight - (int)rect.y2; - destwidth = (int)(rect.x2 - rect.x1); - destheight = (int)(rect.y2 - rect.y1); + if (has_bbox) { + int srcstride = wdata * 4; + destx = x1; + desty = hdata - y2; + destwidth = x2 - x1; + destheight = y2 - y1; deststride = 4 * destwidth; - destbuffer = new agg::int8u[deststride * destheight]; + destbuffer = new uint8_t[deststride * destheight]; if (destbuffer == NULL) { TCL_APPEND_RESULT(interp, "could not allocate memory", (char *)NULL); return TCL_ERROR; @@ -128,11 +111,10 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int for (int i = 0; i < destheight; ++i) { memcpy(destbuffer + (deststride * i), - &buffer(i + desty, destx, 0), + &buffer[(i + desty) * srcstride + (destx * 4)], deststride); } } else { - has_bbox = false; destbuffer = NULL; destx = desty = destwidth = destheight = deststride = 0; } @@ -168,10 +150,10 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int delete[] destbuffer; } else { - block.width = buffer.dim(1); - block.height = buffer.dim(0); + block.width = wdata; + block.height = hdata; block.pitch = (int)block.width * nval; - block.pixelPtr = buffer.data(); + block.pixelPtr = buffer; /* Clear current contents */ TK_PHOTO_BLANK(photo); @@ -457,15 +439,11 @@ PyMODINIT_FUNC PyInit__tkagg(void) m = PyModule_Create(&_tkagg_module); - import_array(); - return (load_tkinter_funcs() == 0) ? m : NULL; } #else PyMODINIT_FUNC init_tkagg(void) { - import_array(); - Py_InitModule("_tkagg", functions); load_tkinter_funcs(); From 512e4d86ec5083ed74c750e2310abda72b8f9bbb Mon Sep 17 00:00:00 2001 From: mattip Date: Sun, 5 Nov 2017 21:00:31 +0200 Subject: [PATCH 04/10] search for cffi c-extension module to find c-functions --- lib/matplotlib/backends/_tkagg.py | 78 ------------------------------- lib/matplotlib/backends/tkagg.py | 16 +++---- src/_tkagg.cpp | 30 +++++++++--- 3 files changed, 31 insertions(+), 93 deletions(-) delete mode 100644 lib/matplotlib/backends/_tkagg.py diff --git a/lib/matplotlib/backends/_tkagg.py b/lib/matplotlib/backends/_tkagg.py deleted file mode 100644 index 3c87f35f902e..000000000000 --- a/lib/matplotlib/backends/_tkagg.py +++ /dev/null @@ -1,78 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -from _tkinter.tklib_cffi import ffi as tkffi, lib as tklib -from _tkinter.tclobj import FromTclStringNDArray -import numpy as np - -app = None - -def PyAggImagePhoto(photoimage, data_as_str, mode, bbox_as_str=None): - interp = PyAggImagePhoto.interp - if not tklib.Tk_MainWindow(interp): - raise _tkinter.TclError("this isn't a Tk application") - photo = tklib.Tk_FindPhoto(interp, photoimage) - if not photo: - tklib.Tcl_AppendResult(interp, "destination photo must exist", 0) - return tklib.TCL_ERROR - data = FromTclStringNDArray(data_as_str) - if bbox_as_str: - try: - bbox = FromTclStringNDArray(bbox_as_str) - except: - tklib.Tcl_AppendResult(interp, "bbox not valid", 0) - return tklib.TCL_ERROR - destx = int(bbox[0, 0]) - desty = data.shape[0] - int(bbox[1, 1]) - destwidth = int(bbox[1, 0] - bbox[0, 0]) - destheight = int(bbox[1, 1] - bbox[0, 1]) - deststride = 4 * destwidth; - destbuffer = np.empty([destheight, destwidth, 4], dtype='uint8') - has_bbox = True - destbuffer[:,:,:] = data[desty:desty+destheight, destx:destx+destwidth,:] - else: - has_bbox = False - destbuffer = None - destx = desty = destwidth = destheight = deststride = 0; - pBlock = tkffi.new('Tk_PhotoImageBlock[1]') - block = pBlock[0] - block.pixelSize = 1 - if mode == 0: - block.offset[0] = block.offset[1] = block.offset[2] = 0 - nval = 1 - else: - block.offset[0] = 0 - block.offset[1] = 1 - block.offset[2] = 2 - if mode == 1: - block.offset[3] = 0 - block.pixelSize = 3 - nval = 3 - else: - block.offset[3] = 3 - block.pixelSize = 4 - if has_bbox: - block.width = destwidth - block.height = destheight - block.pitch = deststride - block.pixelPtr = tkffi.from_buffer(destbuffer) - - tklib.Tk_PhotoPutBlock_NoComposite(photo, pBlock, destx, desty, - destwidth, destheight); - - else: - block.width = data.shape[1] - block.height = data.shape[0] - block.pitch = data.strides[0] - block.pixelPtr = tkffi.from_buffer(data) - - #/* Clear current contents */ - tklib.Tk_PhotoBlank(photo); - #/* Copy opaque block to photo image, and leave the rest to TK */ - tklib.Tk_PhotoPutBlock_NoComposite(photo, pBlock, 0, 0, - block.width, block.height); - return tklib.TCL_OK - -def tkinit(tk): - tk.createcommand(b"PyAggImagePhoto", PyAggImagePhoto) - PyAggImagePhoto.interp = tk.interp - diff --git a/lib/matplotlib/backends/tkagg.py b/lib/matplotlib/backends/tkagg.py index f563c5877404..c0e457375718 100644 --- a/lib/matplotlib/backends/tkagg.py +++ b/lib/matplotlib/backends/tkagg.py @@ -24,15 +24,13 @@ def blit(photoimage, aggimage, bbox=None, colormode=1): "PyAggImagePhoto", photoimage, dataptr, colormode, bboxptr) except Tk.TclError: - try: - try: - _tkagg.tkinit(tk.interpaddr(), 1) - except AttributeError: - _tkagg.tkinit(tk, 0) - tk.call("PyAggImagePhoto", photoimage, - dataptr, colormode, bboxptr) - except (ImportError, AttributeError, Tk.TclError): - raise + if hasattr(tk, 'interpaddr'): + _tkagg.tkinit(tk.interpaddr(), 1) + else: + # very old python? + _tkagg.tkinit(tk, 0) + tk.call("PyAggImagePhoto", photoimage, + dataptr, colormode, bboxptr) def test(aggimage): import time diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index 67eb8744142d..52129abbf169 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -181,7 +181,7 @@ static PyObject *_tkinit(PyObject *self, PyObject *args) } else { /* Do it the hard way. This will break if the TkappObject layout changes */ - app = (TkappObject *)PyLong_AsVoidPtr(arg); + app = (TkappObject *)arg; interp = app->interp; } @@ -320,7 +320,7 @@ int load_tkinter_funcs(void) * tkinter uses these symbols, and the symbols are therefore visible in the * tkinter dynamic library (module). */ -#if PY3K +#if PY_MAJOR_VERSION >= 3 #define TKINTER_PKG "tkinter" #define TKINTER_MOD "_tkinter" // From module __file__ attribute to char *string for dlopen. @@ -414,13 +414,31 @@ int load_tkinter_funcs(void) } tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); if (tkinter_lib == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "Cannot dlopen tkinter module file"); - goto exit; + /* Perhaps it is a cffi module, like in PyPy? */ + pString = PyObject_GetAttrString(pSubmodule, "tklib_cffi"); + if (pString == NULL) { + goto fail; + } + pString = PyObject_GetAttrString(pString, "__file__"); + if (pString == NULL) { + goto fail; + } + tkinter_libname = fname2char(pString); + if (tkinter_libname == NULL) { + goto fail; + } + tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); + } + if (tkinter_lib == NULL) { + goto fail; } ret = _func_loader(tkinter_lib); // dlclose probably safe because tkinter has been imported. dlclose(tkinter_lib); + goto exit; +fail: + PyErr_SetString(PyExc_RuntimeError, + "Cannot dlopen tkinter module file"); exit: Py_XDECREF(pModule); Py_XDECREF(pSubmodule); @@ -429,7 +447,7 @@ int load_tkinter_funcs(void) } #endif // end not Windows -#if PY3K +#if PY_MAJOR_VERSION >= 3 static PyModuleDef _tkagg_module = { PyModuleDef_HEAD_INIT, "_tkagg", "", -1, functions, NULL, NULL, NULL, NULL }; From 4c5dfaa300700fc1766841e97490fdd13f1afd32 Mon Sep 17 00:00:00 2001 From: mattip Date: Sun, 5 Nov 2017 22:02:26 +0200 Subject: [PATCH 05/10] pep8 --- lib/matplotlib/backends/tkagg.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/tkagg.py b/lib/matplotlib/backends/tkagg.py index c0e457375718..ee4fcedd2e04 100644 --- a/lib/matplotlib/backends/tkagg.py +++ b/lib/matplotlib/backends/tkagg.py @@ -14,7 +14,8 @@ def blit(photoimage, aggimage, bbox=None, colormode=1): if bbox is not None: bbox_array = bbox.__array__() # x1, x2, y1, y2 - bboxptr = (bbox_array[0, 0], bbox_array[1, 0], bbox_array[0, 1], bbox_array[1, 1]) + bboxptr = (bbox_array[0, 0], bbox_array[1, 0], + bbox_array[0, 1], bbox_array[1, 1]) else: bboxptr = 0 data = np.asarray(aggimage) From c2a7143e2d8b251e2f61ab2a325bed3dbfa1db0b Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 24 Nov 2017 00:21:32 +0200 Subject: [PATCH 06/10] fixes from review --- src/_tkagg.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index 52129abbf169..3c0ad3e85233 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -21,7 +21,7 @@ #else # define IMG_FORMAT "%zu %d %d" #endif -# define BBOX_FORMAT "%f %f %f %f" +#define BBOX_FORMAT "%f %f %f %f" typedef struct { @@ -47,7 +47,7 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int // vars for blitting size_t pdata; - int wdata, hdata; + int wdata, hdata, bbox_parse; float x1, x2, y1, y2; bool has_bbox; uint8_t *destbuffer, *buffer; @@ -88,11 +88,15 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int } /* check for bbox/blitting */ - if (sscanf(argv[4], BBOX_FORMAT, &x1, &x2, &y1, &y2) == 4) { + bbox_parse = sscanf(argv[4], BBOX_FORMAT, &x1, &x2, &y1, &y2); + if (bbox_parse == 4) { has_bbox = true; } - else { + else if ((bbox_parse == 1) && (x1 == 0)){ has_bbox = false; + } else { + TCL_APPEND_RESULT(interp, "illegal bbox", (char *)NULL); + return TCL_ERROR; } if (has_bbox) { From 09576fa7cebbc335a3e810b7d8d1820a5dda3293 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 24 Nov 2017 09:32:22 +0200 Subject: [PATCH 07/10] silence warnings, fix build on old MSC compilers --- src/_tkagg.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index 3c0ad3e85233..1afc09d396ce 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -13,6 +13,8 @@ #include #include +#include // uint8_t on old MSC_VER + // Include our own excerpts from the Tcl / Tk headers #include "_tkmini.h" @@ -101,10 +103,10 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int if (has_bbox) { int srcstride = wdata * 4; - destx = x1; - desty = hdata - y2; - destwidth = x2 - x1; - destheight = y2 - y1; + destx = (int)x1; + desty = (int)(hdata - y2); + destwidth = (int)(x2 - x1); + destheight = (int)(y2 - y1); deststride = 4 * destwidth; destbuffer = new uint8_t[deststride * destheight]; From 596345e6ec8a33759abe21563902e0d7e9b357e7 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Tue, 3 Oct 2017 10:43:15 -0700 Subject: [PATCH 08/10] Cleanup embedding_in_tk, remove embedding_in_tk2. embedding_in_tk2_sgskip is essentially a slightly simplified duplicate of embedding_in_tk_sgskip. --- .../embedding_in_tk2_sgskip.py | 49 ------------------- .../user_interfaces/embedding_in_tk_sgskip.py | 47 +++++++----------- 2 files changed, 17 insertions(+), 79 deletions(-) delete mode 100644 examples/user_interfaces/embedding_in_tk2_sgskip.py diff --git a/examples/user_interfaces/embedding_in_tk2_sgskip.py b/examples/user_interfaces/embedding_in_tk2_sgskip.py deleted file mode 100644 index ed3c5f1357a5..000000000000 --- a/examples/user_interfaces/embedding_in_tk2_sgskip.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -================ -Embedding In Tk2 -================ - -""" -import matplotlib -matplotlib.use('TkAgg') - -from numpy import arange, sin, pi -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg -from matplotlib.figure import Figure - -import sys -if sys.version_info[0] < 3: - import Tkinter as Tk -else: - import tkinter as Tk - - -def destroy(e): - sys.exit() - -root = Tk.Tk() -root.wm_title("Embedding in TK") - - -f = Figure(figsize=(5, 4), dpi=100) -a = f.add_subplot(111) -t = arange(0.0, 3.0, 0.01) -s = sin(2*pi*t) - -a.plot(t, s) -a.set_title('Tk embedding') -a.set_xlabel('X axis label') -a.set_ylabel('Y label') - - -# a tk.DrawingArea -canvas = FigureCanvasTkAgg(f, master=root) -canvas.draw() -canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) - -canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) - -button = Tk.Button(master=root, text='Quit', command=sys.exit) -button.pack(side=Tk.BOTTOM) - -Tk.mainloop() diff --git a/examples/user_interfaces/embedding_in_tk_sgskip.py b/examples/user_interfaces/embedding_in_tk_sgskip.py index b4ea1669c356..c54a033893e5 100644 --- a/examples/user_interfaces/embedding_in_tk_sgskip.py +++ b/examples/user_interfaces/embedding_in_tk_sgskip.py @@ -7,34 +7,23 @@ import matplotlib matplotlib.use('TkAgg') -from numpy import arange, sin, pi -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg -# implement the default mpl key bindings +import numpy as np +from matplotlib.backends.backend_tkagg import ( + FigureCanvasTkAgg, NavigationToolbar2TkAgg) +# Implement the default Matplotlib key bindings. from matplotlib.backend_bases import key_press_handler - - from matplotlib.figure import Figure +from six.moves import tkinter as Tk -import sys -if sys.version_info[0] < 3: - import Tkinter as Tk -else: - import tkinter as Tk root = Tk.Tk() -root.wm_title("Embedding in TK") - - -f = Figure(figsize=(5, 4), dpi=100) -a = f.add_subplot(111) -t = arange(0.0, 3.0, 0.01) -s = sin(2*pi*t) +root.wm_title("Embedding in Tk") -a.plot(t, s) +fig = Figure(figsize=(5, 4), dpi=100) +t = np.arange(0, 3, .01) +fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t)) - -# a tk.DrawingArea -canvas = FigureCanvasTkAgg(f, master=root) +canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea. canvas.draw() canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) @@ -42,12 +31,10 @@ toolbar.update() canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) - -def on_key_event(event): - print('you pressed %s' % event.key) - key_press_handler(event, canvas, toolbar) - -canvas.mpl_connect('key_press_event', on_key_event) +canvas.mpl_connect( + "key_press_event", lambda event: print("you pressed {}".format(event.key))) +canvas.mpl_connect( + "key_press_event", lambda event: key_press_handler(event, canvas, toolbar)) def _quit(): @@ -55,9 +42,9 @@ def _quit(): root.destroy() # this is necessary on Windows to prevent # Fatal Python Error: PyEval_RestoreThread: NULL tstate -button = Tk.Button(master=root, text='Quit', command=_quit) +button = Tk.Button(master=root, text="Quit", command=_quit) button.pack(side=Tk.BOTTOM) Tk.mainloop() -# If you put root.destroy() here, it will cause an error if -# the window is closed with the window manager. +# If you put root.destroy() here, it will cause an error if the window is +# closed with the window manager. From b40923d0f3638841a098129d1ef0897a2eda0ff8 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 12 Dec 2017 20:45:36 +0200 Subject: [PATCH 09/10] use agg:int8u not uint8_t --- src/_tkagg.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index 1afc09d396ce..d92d8e7ffc9d 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -13,7 +13,7 @@ #include #include -#include // uint8_t on old MSC_VER +#include // agg:int8u // Include our own excerpts from the Tcl / Tk headers #include "_tkmini.h" @@ -52,7 +52,7 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int int wdata, hdata, bbox_parse; float x1, x2, y1, y2; bool has_bbox; - uint8_t *destbuffer, *buffer; + agg::int8u *destbuffer, *buffer; int destx, desty, destwidth, destheight, deststride; long mode; @@ -80,7 +80,7 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int (char *)NULL); return TCL_ERROR; } - buffer = (uint8_t*)pdata; + buffer = (agg::int8u*)pdata; /* get array mode (0=mono, 1=rgb, 2=rgba) */ mode = atol(argv[3]); @@ -109,7 +109,7 @@ static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int destheight = (int)(y2 - y1); deststride = 4 * destwidth; - destbuffer = new uint8_t[deststride * destheight]; + destbuffer = new agg::int8u[deststride * destheight]; if (destbuffer == NULL) { TCL_APPEND_RESULT(interp, "could not allocate memory", (char *)NULL); return TCL_ERROR; From 270f05db4c1727000aa6e590c0f5fc8392458d56 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 12 Jan 2018 13:19:29 +0200 Subject: [PATCH 10/10] add whatsnew entry --- doc/users/next_whats_new/2018_01_10_pypy_tkagg_support.rst | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 doc/users/next_whats_new/2018_01_10_pypy_tkagg_support.rst diff --git a/doc/users/next_whats_new/2018_01_10_pypy_tkagg_support.rst b/doc/users/next_whats_new/2018_01_10_pypy_tkagg_support.rst new file mode 100644 index 000000000000..cd4fb18f06c1 --- /dev/null +++ b/doc/users/next_whats_new/2018_01_10_pypy_tkagg_support.rst @@ -0,0 +1,7 @@ +Rework TkAgg backend to support PyPy +------------------------------------ + +PyPy_ can plot using the TkAgg backend, supported on PyPy 5.9 +and greater (both PyPy for python 2.7 and PyPy for python 3.5) + +.. _PyPy: https:/www.pypy.org pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy