From 4ddec28865b581438a31fa3a4e2c2256d628901e Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 16 Sep 2020 20:31:37 -0400 Subject: [PATCH 01/50] Backport PR #18500: BUG: Fix all-masked imshow --- lib/matplotlib/image.py | 6 ++++-- lib/matplotlib/tests/test_image.py | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 14866cc1012c..ac5706ae7cf7 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -474,8 +474,10 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, # do not run the vmin/vmax through the same pipeline we can # have values close or equal to the boundaries end up on the # wrong side. - vrange = np.array([self.norm.vmin, self.norm.vmax], - dtype=scaled_dtype) + vmin, vmax = self.norm.vmin, self.norm.vmax + if vmin is np.ma.masked: + vmin, vmax = a_min, a_max + vrange = np.array([vmin, vmax], dtype=scaled_dtype) A_scaled -= a_min vrange -= a_min diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 87e3c121d4c0..6ffb2e2d0554 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -846,6 +846,14 @@ def test_mask_image(): ax2.imshow(A, interpolation='nearest') +def test_mask_image_all(): + # Test behavior with an image that is entirely masked does not warn + data = np.full((2, 2), np.nan) + fig, ax = plt.subplots() + ax.imshow(data) + fig.canvas.draw_idle() # would emit a warning + + @image_comparison(['imshow_endianess.png'], remove_text=True) def test_imshow_endianess(): x = np.arange(10) From a7ea0440c2bd2c6f0c09ec1e5f5d6378f57cd395 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Thu, 17 Sep 2020 09:13:49 -0700 Subject: [PATCH 02/50] Backport PR #18505: Fix depth shading when edge/facecolor is none. --- lib/mpl_toolkits/mplot3d/art3d.py | 2 +- lib/mpl_toolkits/tests/test_mplot3d.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 678cd0d7b872..02a310bd92bb 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -803,7 +803,7 @@ def _zalpha(colors, zs): # in all three dimensions. Otherwise, at certain orientations, # the min and max zs are very close together. # Should really normalize against the viewing depth. - if len(zs) == 0: + if len(colors) == 0 or len(zs) == 0: return np.zeros((0, 4)) norm = Normalize(min(zs), max(zs)) sats = 1 - norm(zs) * 0.7 diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index 9c63dc8f9fa8..7d4d9d3e1c77 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -237,8 +237,14 @@ def test_scatter3d(): def test_scatter3d_color(): fig = plt.figure() ax = fig.add_subplot(111, projection='3d') + + # Check that 'none' color works; these two should overlay to produce the + # same as setting just `color`. + ax.scatter(np.arange(10), np.arange(10), np.arange(10), + facecolor='r', edgecolor='none', marker='o') ax.scatter(np.arange(10), np.arange(10), np.arange(10), - color='r', marker='o') + facecolor='none', edgecolor='r', marker='o') + ax.scatter(np.arange(10, 20), np.arange(10, 20), np.arange(10, 20), color='b', marker='s') From 078ee9483b754bb22460d43a62e356149f8b7073 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Tue, 22 Sep 2020 16:00:39 -0400 Subject: [PATCH 03/50] Backport PR #18540: Call to ExitStack.push should have been ExitStack.callback. --- lib/matplotlib/axes/_base.py | 2 +- lib/matplotlib/tests/test_axes.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 404379adcecc..62dee0983fdb 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -2774,7 +2774,7 @@ def redraw_in_frame(self): with ExitStack() as stack: for artist in [*self._get_axis_list(), self.title, self._left_title, self._right_title]: - stack.push(artist.set_visible, artist.get_visible()) + stack.callback(artist.set_visible, artist.get_visible()) artist.set_visible(False) self.draw(self.figure._cachedRenderer) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 41df0f502347..4a9d1c2de57a 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -6350,6 +6350,13 @@ def test_bbox_aspect_axes_init(): assert_allclose(sizes, sizes[0]) +def test_redraw_in_frame(): + fig, ax = plt.subplots(1, 1) + ax.plot([1, 2, 3]) + fig.canvas.draw() + ax.redraw_in_frame() + + def test_invisible_axes(): # invisible axes should not respond to events... fig, ax = plt.subplots() From 3edd1765d98b59253eb4f7c95af871766918ea9b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 23 Sep 2020 13:22:26 -0400 Subject: [PATCH 04/50] Merge pull request #18549 from jklymak/fix-pcolorarg-convert-before-interp FIX: unit-convert pcolorargs before interpolating --- lib/matplotlib/axes/_axes.py | 21 ++++++++------------- lib/matplotlib/tests/test_axes.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 7018bbb3626d..72ca0e6266d4 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -5535,8 +5535,7 @@ def imshow(self, X, cmap=None, norm=None, aspect=None, self.add_image(im) return im - @staticmethod - def _pcolorargs(funcname, *args, shading='flat'): + def _pcolorargs(self, funcname, *args, shading='flat', **kwargs): # - create X and Y if not present; # - reshape X and Y as needed if they are 1-D; # - check for proper sizes based on `shading` kwarg; @@ -5567,6 +5566,10 @@ def _pcolorargs(funcname, *args, shading='flat'): # Check x and y for bad data... C = np.asanyarray(args[2]) X, Y = [cbook.safe_masked_invalid(a) for a in args[:2]] + # unit conversion allows e.g. datetime objects as axis values + self._process_unit_info(xdata=X, ydata=Y, kwargs=kwargs) + X = self.convert_xunits(X) + Y = self.convert_yunits(Y) if funcname == 'pcolormesh': if np.ma.is_masked(X) or np.ma.is_masked(Y): raise ValueError( @@ -5815,14 +5818,10 @@ def pcolor(self, *args, shading=None, alpha=None, norm=None, cmap=None, if shading is None: shading = rcParams['pcolor.shading'] shading = shading.lower() - X, Y, C, shading = self._pcolorargs('pcolor', *args, shading=shading) + X, Y, C, shading = self._pcolorargs('pcolor', *args, shading=shading, + kwargs=kwargs) Ny, Nx = X.shape - # unit conversion allows e.g. datetime objects as axis values - self._process_unit_info(xdata=X, ydata=Y, kwargs=kwargs) - X = self.convert_xunits(X) - Y = self.convert_yunits(Y) - # convert to MA, if necessary. C = ma.asarray(C) X = ma.asarray(X) @@ -6091,14 +6090,10 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None, kwargs.setdefault('edgecolors', 'None') X, Y, C, shading = self._pcolorargs('pcolormesh', *args, - shading=shading) + shading=shading, kwargs=kwargs) Ny, Nx = X.shape X = X.ravel() Y = Y.ravel() - # unit conversion allows e.g. datetime objects as axis values - self._process_unit_info(xdata=X, ydata=Y, kwargs=kwargs) - X = self.convert_xunits(X) - Y = self.convert_yunits(Y) # convert to one dimensional arrays C = C.ravel() diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 41df0f502347..c0d2181ace62 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -1188,6 +1188,22 @@ def test_pcolornearest(fig_test, fig_ref): ax.pcolormesh(x2, y2, Z, shading='nearest') +@check_figures_equal(extensions=["png"]) +def test_pcolornearestunits(fig_test, fig_ref): + ax = fig_test.subplots() + x = [datetime.datetime.fromtimestamp(x * 3600) for x in range(10)] + y = np.arange(0, 3) + np.random.seed(19680801) + Z = np.random.randn(2, 9) + ax.pcolormesh(x, y, Z, shading='flat') + + ax = fig_ref.subplots() + # specify the centers + x2 = [datetime.datetime.fromtimestamp((x + 0.5) * 3600) for x in range(9)] + y2 = y[:-1] + np.diff(y) / 2 + ax.pcolormesh(x2, y2, Z, shading='nearest') + + @check_figures_equal(extensions=["png"]) def test_pcolordropdata(fig_test, fig_ref): ax = fig_test.subplots() From 1b4ca8fbcf24f3353877eec84f478a3f0826ba7c Mon Sep 17 00:00:00 2001 From: David Stansby Date: Tue, 29 Sep 2020 11:06:14 +0100 Subject: [PATCH 05/50] Backport PR #18604: Update test image to fix Ghostscript 9.53. --- .../test_axes/transparent_markers.pdf | Bin 2326 -> 2218 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.pdf b/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.pdf index d1245169e994157aab13bd152a611d4f87cd4587..305bcb90ab9932abfc07b30773a5ff2252bcfe8f 100644 GIT binary patch literal 2218 zcmai0eK=HU6z{2LSB)rrsHJotBDBohnYm^}Y78@3VHlJcjBzm&Gu*itHXrSV6_HI5 z75Uoom8}(#wpx`o^f|3swnX*VjgnezQhV=wAbNK1KX=Y=&Uw!{zxREA=NfYySQelq zm0(=m4OBG|K!5~Df0(N!;SR9Ny(x(JC z%1|~J<)bh_RR*ynVice#e{=XK3L|0w!c78^gGdBi7zKQ>JPs^ueOQJ9M5hQWr@iXU zRK1-59zf)V@q>lpP{2wVzSS*A1Pf4rrdWKk9FT+o>IN8Mu>_T3DX@4ZRthY}ENkTg zY(x?r3E*uqxd71tju8rA4>pz>vpf;LSQ^PkV6h-h-MP{qOGI>mgN1y1i40p8PX^Jf z04jxy=iuNWsG2bkSSpD|1Q>-lM-vp{tWMz%FGpQ3OBjw(1Q1!_7>5q9KoX2mz8MyW zqG14t?~Df?C`A#NA3=~EO7M0O8_?$WTsK2^x|x`LUvdDPz1;MM<9){kfsNvC8&mX) zTM~OT1k^xKulKw6U~&leWaA#m8b`*tlnW(?DNQo@>8JPIX9%hbD5wyoa!Z;-z!* z{u7b?!DG1>N?lN5$fw(4kZR@i#`IBw4Aw?AubGgzp6cq$X-9jjwqzPQ*kmv5{81zi z3ew!ZSt}#eU$?z1Zn*UNg5LYy^-q&QrcYJF*40^W-vw5BSa?6{*u&th@sC_lUOC&h zVy&*z&?)_vi<h3)AGD{uK%m;b4G1CqM~K*PiSn5Wsa5}Z73h|9-_stcy8@xyvDv?(py?JiK$6r z=^M&5lXlRD^JKjsA?mB5H{7NdSJD0|E158RfGHn__V{J7;59fVmKW~0g^W$sFr2)F%$=qU>ubi z#-?l>KsA{#W=Q{A+5gsnWPrw`=?o^?2*mdF2DXD^(BMoUk}{ZdA&d>K%9}+JF(3&c zKV1oTO3|DZ$oTmP8pbkN7QiR1i~*>M$~Nh#=r9=Bp@HKw3O~iNI@)T{u@tS(fhzE- zz~7uh7Np;uR|=pCnr2{xBtBj=Wo5EhJ=Bla>qY(e4LJ83LD5Do4d8qcq5-NlnW2R6 zZH7XrC_Q7Kc;T%aOX)HZ+m^ieNV-kx-rD0;_wC*_UYc3wUK=^w9V@svHFqgkCr+DF zF;d>L{cdyF?U@sU-3xsDFKiDB-?GhT=IZ>*p4*mq?tOpS>Nga*^A5_}=2tPnpLqZA zFzQ@qGyB-1^1~eqYhxSKW!{Y?S)SjthvYX6a|_SQId!7KBc>}ZDtPffeQT!gIehQV z*11K-Pm`X8*5y3wc>MU^#`%kC@AZA(IlML@FsEjGC~M2Oe<5A-r1{>RsPKm;{NyE@ zRYx~@hX*(1?BjwuF2#nbGJFrXQM;ly#V_t@RP#T?P?na} zw$(o(uJTmj@vrcG4^Da(m&e8}ILDoyaOOd~`f!IT)9>A5#gwomal`qqNX+&}<(b|Q zjhns7c>3#w&2%a+8!m#J9<_We|U1l>im_Bb+_xen@`60Em`^cyxqFfSs$(U=&%imX^Q z&$9ko)lW716}01xB%Gwlzi2-~ttL+A-gM)1STt?6k2PcCim_R1R#1bivOC?~?@a2y$ zkCKsB0t=1FO5yB{M9r|70PSa-$gah6lo8sdTS9Het;-_qC6VM3At5oMR@?MjNcCth zcIkU#d&dcqW6!t?sul=bI<=!KhgOWw)tTB1lY!^1y%$9D_;uv!Xkd{2SrFK~$j-{* z1Eob!C8R6IuwZhgjGYnsKduNR?q(9n0Be#bsg%5)cp?rAGb(;X*Ol From 8b25e2f38de556ec6fdfffd27518ebec8393fe6e Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 1 Oct 2020 11:18:57 -0400 Subject: [PATCH 06/50] Backport PR #18621: Fix singleshot timers in wx. --- lib/matplotlib/backends/backend_wx.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 460057cc30e6..0b94f2116ada 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -87,9 +87,6 @@ def _timer_set_interval(self): if self._timer.IsRunning(): self._timer_start() # Restart with new interval. - def _timer_set_single_shot(self): - self._timer.Start() - class RendererWx(RendererBase): """ From 1fa9903715751f39361484982709ce962c470b3f Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 2 Oct 2020 19:23:43 -0400 Subject: [PATCH 07/50] Backport PR #18636: BLD: certifi is not a run-time dependency --- .github/workflows/cibuildwheel.yml | 6 +++--- setup.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml index 9ee39d0c7841..462be6d5a5b7 100644 --- a/.github/workflows/cibuildwheel.yml +++ b/.github/workflows/cibuildwheel.yml @@ -42,7 +42,7 @@ jobs: CIBW_SKIP: "cp35-* cp36-*" CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_MANYLINUX_I686_IMAGE: manylinux1 - CIBW_BEFORE_BUILD: pip install numpy==1.15 + CIBW_BEFORE_BUILD: pip install certifi numpy==1.15 MPL_DISABLE_FH4: "yes" - name: Build wheels for CPython 3.6 @@ -52,7 +52,7 @@ jobs: CIBW_BUILD: "cp36-*" CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_MANYLINUX_I686_IMAGE: manylinux1 - CIBW_BEFORE_BUILD: pip install numpy==1.15 + CIBW_BEFORE_BUILD: pip install certifi numpy==1.15 MPL_DISABLE_FH4: "yes" if: > startsWith(github.ref, 'refs/heads/v3.3') || @@ -63,7 +63,7 @@ jobs: python -m cibuildwheel --output-dir dist env: CIBW_BUILD: "pp3?-*" - CIBW_BEFORE_BUILD: pip install numpy==1.15 + CIBW_BEFORE_BUILD: pip install certifi numpy==1.15 if: > runner.os != 'Windows' && ( startsWith(github.ref, 'refs/heads/v3.3') || diff --git a/setup.py b/setup.py index 81eae826373d..6e1d19d4b85c 100644 --- a/setup.py +++ b/setup.py @@ -287,7 +287,6 @@ def build_extensions(self): "numpy>=1.15", ], install_requires=[ - "certifi>=2020.06.20", "cycler>=0.10", "kiwisolver>=1.0.1", "numpy>=1.15", From 29139a16158e4ab7815dacabbd6ecbd57ce787b1 Mon Sep 17 00:00:00 2001 From: Ryan May Date: Mon, 5 Oct 2020 14:17:15 -0600 Subject: [PATCH 08/50] Backport PR #18639: nbagg: Don't close figures for bubbled events. --- lib/matplotlib/backends/web_backend/js/nbagg_mpl.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/web_backend/js/nbagg_mpl.js b/lib/matplotlib/backends/web_backend/js/nbagg_mpl.js index 0f538979d19d..688e1953ebe1 100644 --- a/lib/matplotlib/backends/web_backend/js/nbagg_mpl.js +++ b/lib/matplotlib/backends/web_backend/js/nbagg_mpl.js @@ -48,7 +48,7 @@ mpl.mpl_figure_comm = function (comm, msg) { console.error('Failed to find cell for figure', id, fig); return; } - fig.cell_info[0].output_area.element.one( + fig.cell_info[0].output_area.element.on( 'cleared', { fig: fig }, fig._remove_fig_handler @@ -181,6 +181,10 @@ mpl.figure.prototype._init_toolbar = function () { mpl.figure.prototype._remove_fig_handler = function (event) { var fig = event.data.fig; + if (event.target !== this) { + // Ignore bubbled events from children. + return; + } fig.close_ws(fig, {}); }; From 64f1e53411beec78bb6cb5de37a34a47ac2a4c00 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Tue, 6 Oct 2020 19:44:19 -0400 Subject: [PATCH 09/50] Backport PR #18670: MNT: make certifi actually optional --- lib/matplotlib/__init__.py | 13 +++++++++++-- lib/matplotlib/image.py | 8 ++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 340eaeb83910..1c47973f1505 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -762,7 +762,11 @@ def is_url(filename): @functools.lru_cache() def _get_ssl_context(): - import certifi + try: + import certifi + except ImportError: + _log.debug("Could not import certifi.") + return None import ssl return ssl.create_default_context(cafile=certifi.where()) @@ -771,7 +775,12 @@ def _get_ssl_context(): def _open_file_or_url(fname): if not isinstance(fname, Path) and is_url(fname): import urllib.request - with urllib.request.urlopen(fname, context=_get_ssl_context()) as f: + ssl_ctx = _get_ssl_context() + if ssl_ctx is None: + _log.debug( + "Could not get certifi ssl context, https may not work." + ) + with urllib.request.urlopen(fname, context=ssl_ctx) as f: yield (line.decode('utf-8') for line in f) else: fname = os.path.expanduser(fname) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index ac5706ae7cf7..7d15e9f1c396 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1481,8 +1481,12 @@ def imread(fname, format=None): if len(parsed.scheme) > 1: # Pillow doesn't handle URLs directly. # hide imports to speed initial import on systems with slow linkers from urllib import request - with request.urlopen(fname, - context=mpl._get_ssl_context()) as response: + ssl_ctx = mpl._get_ssl_context() + if ssl_ctx is None: + _log.debug( + "Could not get certifi ssl context, https may not work." + ) + with request.urlopen(fname, context=ssl_ctx) as response: import io try: response.seek(0) From c5506744d3f1c68f38a8469b6e78558eb878a1cf Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sat, 26 Sep 2020 17:22:24 -0700 Subject: [PATCH 10/50] Backport PR #18584: Fix setting 0-timeout timer with Tornado. --- lib/matplotlib/backends/backend_webagg_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py index 2155381fbd77..5377f3dc266b 100644 --- a/lib/matplotlib/backends/backend_webagg_core.py +++ b/lib/matplotlib/backends/backend_webagg_core.py @@ -517,7 +517,7 @@ def _timer_start(self): else: self._timer = tornado.ioloop.PeriodicCallback( self._on_timer, - self.interval) + max(self.interval, 1e-6)) self._timer.start() def _timer_stop(self): From 6818007f7620a1c22ed1c65ca83ba2c4208c565f Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Mon, 21 Sep 2020 17:38:03 -0400 Subject: [PATCH 11/50] Backport PR #18533: Correctly remove support for `\stackrel`. --- doc/api/prev_api_changes/api_changes_3.1.0.rst | 2 +- lib/matplotlib/mathtext.py | 8 -------- lib/matplotlib/tests/test_mathtext.py | 4 ---- tutorials/text/mathtext.py | 2 +- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/doc/api/prev_api_changes/api_changes_3.1.0.rst b/doc/api/prev_api_changes/api_changes_3.1.0.rst index 2c0f629729db..b6e3ff8c4733 100644 --- a/doc/api/prev_api_changes/api_changes_3.1.0.rst +++ b/doc/api/prev_api_changes/api_changes_3.1.0.rst @@ -727,7 +727,7 @@ Mathtext changes Deprecations ~~~~~~~~~~~~ -- The ``\stackrel`` mathtext command hsa been deprecated (it behaved differently +- The ``\stackrel`` mathtext command has been deprecated (it behaved differently from LaTeX's ``\stackrel``. To stack two mathtext expressions, use ``\genfrac{left-delim}{right-delim}{fraction-bar-thickness}{}{top}{bottom}``. - The ``\mathcircled`` mathtext command (which is not a real TeX command) diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index 1b46fc6dcd7d..d174aaf556f3 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -2396,7 +2396,6 @@ def __init__(self): p.accentprefixed = Forward() p.space = Forward() p.sqrt = Forward() - p.stackrel = Forward() p.start_group = Forward() p.subsuper = Forward() p.subsuperop = Forward() @@ -2481,12 +2480,6 @@ def __init__(self): | Error(r"Expected \dfrac{num}{den}")) ) - p.stackrel <<= Group( - Suppress(Literal(r"\stackrel")) - - ((p.required_group + p.required_group) - | Error(r"Expected \stackrel{num}{den}")) - ) - p.binom <<= Group( Suppress(Literal(r"\binom")) - ((p.required_group + p.required_group) @@ -2543,7 +2536,6 @@ def __init__(self): | p.group | p.frac | p.dfrac - | p.stackrel | p.binom | p.genfrac | p.sqrt diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py index 6bc84b19f1eb..91a72a648441 100644 --- a/lib/matplotlib/tests/test_mathtext.py +++ b/lib/matplotlib/tests/test_mathtext.py @@ -214,8 +214,6 @@ def test_fontinfo(): (r'$\hspace{foo}$', r'Expected \hspace{n}'), (r'$\frac$', r'Expected \frac{num}{den}'), (r'$\frac{}{}$', r'Expected \frac{num}{den}'), - (r'$\stackrel$', r'Expected \stackrel{num}{den}'), - (r'$\stackrel{}{}$', r'Expected \stackrel{num}{den}'), (r'$\binom$', r'Expected \binom{num}{den}'), (r'$\binom{}{}$', r'Expected \binom{num}{den}'), (r'$\genfrac$', @@ -238,8 +236,6 @@ def test_fontinfo(): 'hspace with invalid value', 'frac without parameters', 'frac with empty parameters', - 'stackrel without parameters', - 'stackrel with empty parameters', 'binom without parameters', 'binom with empty parameters', 'genfrac without parameters', diff --git a/tutorials/text/mathtext.py b/tutorials/text/mathtext.py index 7b5b078b4fa2..709f1df4956b 100644 --- a/tutorials/text/mathtext.py +++ b/tutorials/text/mathtext.py @@ -97,7 +97,7 @@ .. math:: - \frac{3}{4} \binom{3}{4} \stackrel{}{}{0}{}{3}{4} + \frac{3}{4} \binom{3}{4} \genfrac{}{}{0}{}{3}{4} Fractions can be arbitrarily nested:: From b627608807d1e2c52d1cfa0aa2b8ba9985d2a447 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 16 Oct 2020 19:02:47 -0400 Subject: [PATCH 12/50] Backport PR #18734: Fix deprecation warning in GitHub Actions. --- .github/workflows/reviewdog.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index ba142edd6aed..9ec0abf942ba 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -18,11 +18,11 @@ jobs: - name: Set up reviewdog run: | - mkdir -p $HOME/bin + mkdir -p "$HOME/bin" curl -sfL \ https://github.com/reviewdog/reviewdog/raw/master/install.sh | \ - sh -s -- -b $HOME/bin - echo ::add-path::$HOME/bin + sh -s -- -b "$HOME/bin" + echo "$HOME/bin" >> $GITHUB_PATH - name: Run flake8 env: From ba13e4cf1b782d03c12668d5dbad72d79b0d8d96 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Tue, 20 Oct 2020 11:28:52 -0700 Subject: [PATCH 13/50] Backport PR #18773: Update to latest cibuildwheel release. --- .github/workflows/cibuildwheel.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml index 462be6d5a5b7..0ff85ef57bf4 100644 --- a/.github/workflows/cibuildwheel.yml +++ b/.github/workflows/cibuildwheel.yml @@ -28,7 +28,7 @@ jobs: - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==1.5.5 + python -m pip install cibuildwheel==1.6.3 - name: Copy setup.cfg to configure wheel run: | @@ -39,7 +39,7 @@ jobs: python -m cibuildwheel --output-dir dist env: CIBW_BUILD: "cp3?-*" - CIBW_SKIP: "cp35-* cp36-*" + CIBW_SKIP: "cp35-* cp36-* cp39-*" CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_MANYLINUX_I686_IMAGE: manylinux1 CIBW_BEFORE_BUILD: pip install certifi numpy==1.15 From 1c509c3db7d845844fabf682004b50113669acf0 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 21 Oct 2020 15:35:21 -0400 Subject: [PATCH 14/50] Backport PR #18754: FIX: make sure we have more than 1 tick with small log ranges --- lib/matplotlib/tests/test_ticker.py | 10 ++++++++++ lib/matplotlib/ticker.py | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/lib/matplotlib/tests/test_ticker.py b/lib/matplotlib/tests/test_ticker.py index 611b5cf968d8..9033e30d4858 100644 --- a/lib/matplotlib/tests/test_ticker.py +++ b/lib/matplotlib/tests/test_ticker.py @@ -1347,3 +1347,13 @@ def test_bad_locator_subs(sub): ll = mticker.LogLocator() with pytest.raises(ValueError): ll.subs(sub) + + +@pytest.mark.parametrize('numticks', [1, 2, 3, 9]) +@pytest.mark.style('default') +def test_small_range_loglocator(numticks): + ll = mticker.LogLocator() + ll.set_params(numticks=numticks) + for top in [5, 7, 9, 11, 15, 50, 100, 1000]: + ticks = ll.tick_values(.5, top) + assert (np.diff(np.log10(ll.tick_values(6, 150))) == 1).all() diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index ced002157637..67931617423f 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -2500,6 +2500,13 @@ def tick_values(self, vmin, vmax): if mpl.rcParams['_internal.classic_mode'] else (numdec + 1) // numticks + 1) + # if we have decided that the stride is as big or bigger than + # the range, clip the stride back to the available range - 1 + # with a floor of 1. This prevents getting axis with only 1 tick + # visible. + if stride >= numdec: + stride = max(1, numdec - 1) + # Does subs include anything other than 1? Essentially a hack to know # whether we're a major or a minor locator. have_subs = len(subs) > 1 or (len(subs) == 1 and subs[0] != 1.0) From bf9e17d095217d92d400b795487ecfc024d30708 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Tue, 20 Oct 2020 17:16:13 -0400 Subject: [PATCH 15/50] Backport PR #18769: Support `ax.grid(visible=)`. --- lib/matplotlib/axes/_base.py | 2 -- lib/matplotlib/axis.py | 43 +++++++++++----------- lib/matplotlib/tests/test_axes.py | 45 ++++++++++++++---------- lib/mpl_toolkits/axisartist/axislines.py | 18 +++++----- 4 files changed, 59 insertions(+), 49 deletions(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 62dee0983fdb..278dab735e6f 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -2885,8 +2885,6 @@ def grid(self, b=None, which='major', axis='both', **kwargs): use `.set_axisbelow` or, for more control, call the `~.Artist.set_zorder` method of each axis. """ - if len(kwargs): - b = True cbook._check_in_list(['x', 'y', 'both'], axis=axis) if axis in ['x', 'both']: self.xaxis.grid(b, which=which, **kwargs) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index f970a4452660..10d132f03694 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -778,10 +778,10 @@ def cla(self): self.callbacks = cbook.CallbackRegistry() # whether the grids are on - self._gridOnMajor = ( + self._major_tick_kw['gridOn'] = ( mpl.rcParams['axes.grid'] and mpl.rcParams['axes.grid.which'] in ('both', 'major')) - self._gridOnMinor = ( + self._minor_tick_kw['gridOn'] = ( mpl.rcParams['axes.grid'] and mpl.rcParams['axes.grid.which'] in ('both', 'minor')) @@ -1381,7 +1381,6 @@ def get_major_ticks(self, numticks=None): # Update the new tick label properties from the old. tick = self._get_tick(major=True) self.majorTicks.append(tick) - tick.gridline.set_visible(self._gridOnMajor) self._copy_tick_props(self.majorTicks[0], tick) return self.majorTicks[:numticks] @@ -1395,7 +1394,6 @@ def get_minor_ticks(self, numticks=None): # Update the new tick label properties from the old. tick = self._get_tick(major=False) self.minorTicks.append(tick) - tick.gridline.set_visible(self._gridOnMinor) self._copy_tick_props(self.minorTicks[0], tick) return self.minorTicks[:numticks] @@ -1420,32 +1418,37 @@ def grid(self, b=None, which='major', **kwargs): Define the line properties of the grid, e.g.:: grid(color='r', linestyle='-', linewidth=2) - """ - if len(kwargs): - if not b and b is not None: # something false-like but not None + if b is not None: + if 'visible' in kwargs and bool(b) != bool(kwargs['visible']): + raise ValueError( + "'b' and 'visible' specify inconsistent grid visibilities") + if kwargs and not b: # something false-like but not None cbook._warn_external('First parameter to grid() is false, ' 'but line properties are supplied. The ' 'grid will be enabled.') - b = True + b = True which = which.lower() cbook._check_in_list(['major', 'minor', 'both'], which=which) gridkw = {'grid_' + item[0]: item[1] for item in kwargs.items()} + if 'grid_visible' in gridkw: + forced_visibility = True + gridkw['gridOn'] = gridkw.pop('grid_visible') + else: + forced_visibility = False if which in ['minor', 'both']: - if b is None: - self._gridOnMinor = not self._gridOnMinor - else: - self._gridOnMinor = b - self.set_tick_params(which='minor', gridOn=self._gridOnMinor, - **gridkw) + if b is None and not forced_visibility: + gridkw['gridOn'] = not self._minor_tick_kw['gridOn'] + elif b is not None: + gridkw['gridOn'] = b + self.set_tick_params(which='minor', **gridkw) if which in ['major', 'both']: - if b is None: - self._gridOnMajor = not self._gridOnMajor - else: - self._gridOnMajor = b - self.set_tick_params(which='major', gridOn=self._gridOnMajor, - **gridkw) + if b is None and not forced_visibility: + gridkw['gridOn'] = not self._major_tick_kw['gridOn'] + elif b is not None: + gridkw['gridOn'] = b + self.set_tick_params(which='major', **gridkw) self.stale = True def update_units(self, data): diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index b31ebc945fac..57beec025aa8 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -4310,26 +4310,35 @@ def test_twin_spines_on_top(): ax2.fill_between("i", "j", color='#7FC97F', alpha=.5, data=data) -def test_rcparam_grid_minor(): - orig_grid = matplotlib.rcParams['axes.grid'] - orig_locator = matplotlib.rcParams['axes.grid.which'] - - matplotlib.rcParams['axes.grid'] = True - - values = ( - (('both'), (True, True)), - (('major'), (True, False)), - (('minor'), (False, True)) - ) +@pytest.mark.parametrize("grid_which, major_visible, minor_visible", [ + ("both", True, True), + ("major", True, False), + ("minor", False, True), +]) +def test_rcparam_grid_minor(grid_which, major_visible, minor_visible): + mpl.rcParams.update({"axes.grid": True, "axes.grid.which": grid_which}) + fig, ax = plt.subplots() + fig.canvas.draw() + assert all(tick.gridline.get_visible() == major_visible + for tick in ax.xaxis.majorTicks) + assert all(tick.gridline.get_visible() == minor_visible + for tick in ax.xaxis.minorTicks) - for locator, result in values: - matplotlib.rcParams['axes.grid.which'] = locator - fig = plt.figure() - ax = fig.add_subplot(1, 1, 1) - assert (ax.xaxis._gridOnMajor, ax.xaxis._gridOnMinor) == result - matplotlib.rcParams['axes.grid'] = orig_grid - matplotlib.rcParams['axes.grid.which'] = orig_locator +def test_grid(): + fig, ax = plt.subplots() + ax.grid() + fig.canvas.draw() + assert ax.xaxis.majorTicks[0].gridline.get_visible() + ax.grid(visible=False) + fig.canvas.draw() + assert not ax.xaxis.majorTicks[0].gridline.get_visible() + ax.grid(visible=True) + fig.canvas.draw() + assert ax.xaxis.majorTicks[0].gridline.get_visible() + ax.grid() + fig.canvas.draw() + assert not ax.xaxis.majorTicks[0].gridline.get_visible() def test_vline_limit(): diff --git a/lib/mpl_toolkits/axisartist/axislines.py b/lib/mpl_toolkits/axisartist/axislines.py index db89bd434eb8..d3e32477adf2 100644 --- a/lib/mpl_toolkits/axisartist/axislines.py +++ b/lib/mpl_toolkits/axisartist/axislines.py @@ -439,9 +439,9 @@ def get_gridlines(self, which="major", axis="both"): if axis in ["both", "y"]: x1, x2 = self.axes.get_xlim() locs = [] - if self.axes.yaxis._gridOnMajor: + if self.axes.yaxis._major_tick_kw["gridOn"]: locs.extend(self.axes.yaxis.major.locator()) - if self.axes.yaxis._gridOnMinor: + if self.axes.yaxis._minor_tick_kw["gridOn"]: locs.extend(self.axes.yaxis.minor.locator()) for y in locs: @@ -533,17 +533,17 @@ def grid(self, b=None, which='major', axis="both", **kwargs): """ Toggle the gridlines, and optionally set the properties of the lines. """ - # their are some discrepancy between the behavior of grid in - # axes_grid and the original mpl's grid, because axes_grid - # explicitly set the visibility of the gridlines. + # There are some discrepancies in the behavior of grid() between + # axes_grid and Matplotlib, because axes_grid explicitly sets the + # visibility of the gridlines. super().grid(b, which=which, axis=axis, **kwargs) if not self._axisline_on: return if b is None: - b = (self.axes.xaxis._gridOnMinor - or self.axes.xaxis._gridOnMajor - or self.axes.yaxis._gridOnMinor - or self.axes.yaxis._gridOnMajor) + b = (self.axes.xaxis._minor_tick_kw["gridOn"] + or self.axes.xaxis._major_tick_kw["gridOn"] + or self.axes.yaxis._minor_tick_kw["gridOn"] + or self.axes.yaxis._major_tick_kw["gridOn"]) self.gridlines.set(which=which, axis=axis, visible=b) self.gridlines.set(**kwargs) From be16bb4fb26723e20e4f9103b14aaf29c16de9cd Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 29 Oct 2020 17:28:55 -0400 Subject: [PATCH 16/50] Backport PR #18756: FIX: improve date performance regression --- lib/matplotlib/dates.py | 50 +++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index 4b56f07b9525..4a2e7374efec 100644 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -285,25 +285,6 @@ def get_epoch(): return _epoch -def _to_ordinalf(dt): - """ - Convert :mod:`datetime` or :mod:`date` to the Gregorian date as UTC float - days, preserving hours, minutes, seconds and microseconds. Return value - is a `float`. - """ - # Convert to UTC - tzi = getattr(dt, 'tzinfo', None) - if tzi is not None: - dt = dt.astimezone(UTC) - dt = dt.replace(tzinfo=None) - dt64 = np.datetime64(dt) - return _dt64_to_ordinalf(dt64) - - -# a version of _to_ordinalf that can operate on numpy arrays -_to_ordinalf_np_vectorized = np.vectorize(_to_ordinalf) - - def _dt64_to_ordinalf(d): """ Convert `numpy.datetime64` or an ndarray of those types to Gregorian @@ -428,20 +409,29 @@ def date2num(d): if hasattr(d, "values"): # this unpacks pandas series or dataframes... d = d.values - if not np.iterable(d): - if (isinstance(d, np.datetime64) or - (isinstance(d, np.ndarray) and - np.issubdtype(d.dtype, np.datetime64))): - return _dt64_to_ordinalf(d) - return _to_ordinalf(d) - else: - d = np.asarray(d) - if np.issubdtype(d.dtype, np.datetime64): - return _dt64_to_ordinalf(d) + # make an iterable, but save state to unpack later: + iterable = np.iterable(d) + if not iterable: + d = [d] + + d = np.asarray(d) + # convert to datetime64 arrays, if not already: + if not np.issubdtype(d.dtype, np.datetime64): + # datetime arrays if not d.size: + # deals with an empty array... return d - return _to_ordinalf_np_vectorized(d) + tzi = getattr(d[0], 'tzinfo', None) + if tzi is not None: + # make datetime naive: + d = [dt.astimezone(UTC).replace(tzinfo=None) for dt in d] + d = np.asarray(d) + d = d.astype('datetime64[us]') + + d = _dt64_to_ordinalf(d) + + return d if iterable else d[0] def julian2num(j): From c8324eea84c762842c29fe8193e87ac89129e96b Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Fri, 30 Oct 2020 03:18:28 +0100 Subject: [PATCH 17/50] Backport PR #18839: MNT: make sure we do not mutate input in Text.update --- lib/matplotlib/tests/test_text.py | 12 ++++++++++++ lib/matplotlib/text.py | 2 ++ 2 files changed, 14 insertions(+) diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index 70855e6d879f..8d91b1318d88 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -8,9 +8,11 @@ import matplotlib as mpl from matplotlib.backend_bases import MouseEvent +from matplotlib.font_manager import FontProperties import matplotlib.patches as mpatches import matplotlib.pyplot as plt from matplotlib.testing.decorators import check_figures_equal, image_comparison +from matplotlib.text import Text needs_usetex = pytest.mark.skipif( @@ -689,3 +691,13 @@ def test_fontproperties_kwarg_precedence(): text2 = plt.ylabel("counts", size=40.0, fontproperties='Times New Roman') assert text1.get_size() == 40.0 assert text2.get_size() == 40.0 + + +def test_update_mutate_input(): + inp = dict(fontproperties=FontProperties(weight="bold"), + bbox=None) + cache = dict(inp) + t = Text() + t.update(inp) + assert inp['fontproperties'] == cache['fontproperties'] + assert inp['bbox'] == cache['bbox'] diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 3b30a4cfb502..efe4450f4fba 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -167,6 +167,8 @@ def __init__(self, def update(self, kwargs): # docstring inherited + # make a copy so we do not mutate user input! + kwargs = dict(kwargs) sentinel = object() # bbox can be None, so use another sentinel. # Update fontproperties first, as it has lowest priority. fontproperties = kwargs.pop("fontproperties", sentinel) From 56fd5b8f18086ea234132a304d54ec45f591f05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jouni=20K=2E=20Sepp=C3=A4nen?= Date: Sun, 2 Aug 2020 12:18:57 +0300 Subject: [PATCH 18/50] Backport PR #18134: Build on xcode9 --- .travis.yml | 22 +++++------------- ci/osx-deps | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 16 deletions(-) create mode 100755 ci/osx-deps diff --git a/.travis.yml b/.travis.yml index d3b9780d8105..92579db8a2c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,6 +87,7 @@ matrix: env: - PRE=--pre - os: osx + osx_image: xcode9 language: generic # https://github.com/travis-ci/travis-ci/issues/2312 only: master cache: @@ -101,26 +102,15 @@ matrix: allow_failures: - python: "nightly" -before_install: | +before_install: +- | + # Install OS dependencies and set up ccache case "$TRAVIS_OS_NAME" in linux) export PATH=/usr/lib/ccache:$PATH ;; osx) - set -e - ci/silence brew update - brew uninstall numpy gdal postgis - brew unlink python@2 - brew install python || brew upgrade python - brew install ffmpeg imagemagick mplayer ccache - hash -r - which python - python --version - set +e - # We could install ghostscript and inkscape here to test svg and pdf - # but this makes the test time really long. - # brew install ghostscript inkscape - export PATH=/usr/local/opt/python/libexec/bin:/usr/local/opt/ccache/libexec:$PATH + ci/osx-deps ;; esac @@ -169,7 +159,7 @@ install: export CPPFLAGS=--coverage fi - | - python -mpip install -ve . # Install Matplotlib. + python -mpip install -e . # Install Matplotlib. - | if [[ $TRAVIS_OS_NAME != 'osx' ]]; then unset CPPFLAGS diff --git a/ci/osx-deps b/ci/osx-deps new file mode 100755 index 000000000000..2f00bb9ffa67 --- /dev/null +++ b/ci/osx-deps @@ -0,0 +1,65 @@ +#!/bin/bash + +set -euo pipefail +cache="$HOME"/.cache/matplotlib + +fold_start() { + key=$1 + title=$2 + echo -e "travis_fold:start:$key\e[2K" + echo -e "travis_time:start:$key\e[2K" + tick="$(date +%s)" + echo "$title" +} + +fold_end() { + key=$1 + tock="$(date +%s)" + nano=000000000 + echo -e "travis_time:end:$key:start=$tick$nano,finish=$tock$nano,duration=$((tock - tick))$nano\e[2K" + echo -e "travis_fold:end:$key\e[2K" +} + +cached_download() { + file=$1 + url=$2 + shasum=$3 + path="$cache/$file" + if [[ ! -f "$path" + || "$(shasum -a 256 "$path" | awk '{print $1}')" != "$shasum" ]] + then + curl -L -o "$path" "$url" + fi +} + +fold_start Python "Install Python 3.8 from python.org" +cached_download python-3.8.5-macosx10.9.pkg \ + https://www.python.org/ftp/python/3.8.5/python-3.8.5-macosx10.9.pkg \ + e27c5a510c10f830084fb9c60b9e9aa8719d92e4537a80e6b4252c02396f0d29 +sudo installer -package "$cache"/python-3.8.5-macosx10.9.pkg -target / +sudo ln -s /usr/local/bin/python3 /usr/local/bin/python +hash -r +fold_end Python + +fold_start ccache 'Install ccache (compile it ourselves)' +cached_download ccache-3.7.11.tar.xz \ + https://github.com/ccache/ccache/releases/download/v3.7.11/ccache-3.7.11.tar.xz \ + 8d450208099a4d202bd7df87caaec81baee20ce9dd62da91e9ea7b95a9072f68 +tar xf "$cache"/ccache-3.7.11.tar.xz +pushd ccache-3.7.11 +./configure --prefix=/usr/local +make -j2 +make install +popd +for compiler in clang clang++ cc gcc c++ g++; do + ln -sf ccache /usr/local/bin/$compiler +done +fold_end ccache + +fold_start freetype 'Install freetype (just unpack into the build directory)' +cached_download freetype-2.6.1.tar.gz \ + https://download.savannah.gnu.org/releases/freetype/freetype-2.6.1.tar.gz \ + 0a3c7dfbda6da1e8fce29232e8e96d987ababbbf71ebc8c75659e4132c367014 +mkdir -p build +tar -x -C build -f "$cache"/freetype-2.6.1.tar.gz +fold_end freetype From 4ca9f0f914dc8232e50d2969e33731f1fa948d87 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 14 Sep 2020 11:55:22 -0400 Subject: [PATCH 19/50] CI: skip qt, cairo, gobject related installs on OSX on travis On 2020-09-12 pyqt5 replaced their wheels to have a minimum OSX version of 10.13 which caused us to fallback to trying to build pyqt5 from the tar.gz. This in turn failed (because we do not have any of the qt development libraries installed and even if we did it would take a while). We have always been installing pyside2 from wheels, but an older version (5.13.2) that has a fatal-to-us bug. However the previously published pyqt5 wheels were, despite being labeled as 10.12 actually complied against 10.13 and failed to import. This cause our test suite to decide that we did not have a valid qt binding and skip the qt tests. Now that pyqt5 is (correctly) not installing we are falling back to pyside2 and hitting the bug in pyside2 (it is reported to fixed in the next release 5.14.0 but that only has wheels for 10.13). PyGObject, pycairo, and cariocffi also do not install on OSX 10.12 This skips trying to install pycairo, pygobjoct, pyqt5, and pyside2 on OSX on travis because they all fail to install on OSX 10.12. It will make our CI marginally faster and does not move the status quo of what we were actually testing. --- .travis.yml | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 92579db8a2c2..59e6f5b3fb5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -133,19 +133,28 @@ install: # install was successful by trying to import the toolkit (sometimes, the # install appears to be successful but shared libraries cannot be loaded at # runtime, so an actual import is a better check). - python -mpip install --upgrade pycairo cairocffi>=0.8 - python -mpip install --upgrade PyGObject && - python -c 'import gi; gi.require_version("Gtk", "3.0"); from gi.repository import Gtk' && - echo 'PyGObject is available' || - echo 'PyGObject is not available' - python -mpip install --upgrade pyqt5 && - python -c 'import PyQt5.QtCore' && - echo 'PyQt5 is available' || - echo 'PyQt5 is not available' - python -mpip install --upgrade pyside2 && - python -c 'import PySide2.QtCore' && - echo 'PySide2 is available' || - echo 'PySide2 is not available' + + # PyGObject, pycairo, and cariocffi do not install on OSX 10.12 + + # There are not functioning wheels available for OSX 10.12 (as of + # Sept 2020) for either pyqt5 (there are only wheels for 10.13+) + # or pyside2 (the latest version (5.13.2) with 10.12 wheels has a + # fatal to us bug, it was fixed in 5.14.0 which has 10.13 wheels) + if [[ $TRAVIS_OS_NAME != 'osx' ]]; then + python -mpip install --upgrade pycairo cairocffi>=0.8 + python -mpip install --upgrade PyGObject && + python -c 'import gi; gi.require_version("Gtk", "3.0"); from gi.repository import Gtk' && + echo 'PyGObject is available' || + echo 'PyGObject is not available' + python -mpip install --upgrade pyqt5 && + python -c 'import PyQt5.QtCore' && + echo 'PyQt5 is available' || + echo 'PyQt5 is not available' + python -mpip install --upgrade pyside2 && + python -c 'import PySide2.QtCore' && + echo 'PySide2 is available' || + echo 'PySide2 is not available' + fi python -mpip install --upgrade \ -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-16.04 \ wxPython && From 8988155bc5b97743da0e416a403c765b065398b8 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Tue, 3 Nov 2020 14:04:36 -0800 Subject: [PATCH 20/50] Backport: manual --- lib/matplotlib/colorbar.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 0dc84edc2acc..4b2f86003eaa 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -788,6 +788,9 @@ def _add_solids(self, X, Y, C): Draw the colors using `~.axes.Axes.pcolormesh`; optionally add separators. """ + if C.shape[0] == Y.shape[0]: + # trim the last one to be compatible with old behavior. + C = C[:-1] if self.orientation == 'vertical': args = (X, Y, C) else: From 7ff0fbc6eac747d0580b64a13bc542a5e0435fd6 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 9 Nov 2020 22:17:04 -0500 Subject: [PATCH 21/50] Backport PR #18732: Add a ponyfill for ResizeObserver on older browsers. --- LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER | 108 ++++++++++++++++++ lib/matplotlib/backends/web_backend/js/mpl.js | 18 ++- .../backends/web_backend/js/nbagg_mpl.js | 1 + .../backends/web_backend/package.json | 3 + tools/embed_js.py | 102 +++++++++++++++++ 5 files changed, 230 insertions(+), 2 deletions(-) create mode 100644 LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER create mode 100644 tools/embed_js.py diff --git a/LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER b/LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER new file mode 100644 index 000000000000..0bc1fa7060b7 --- /dev/null +++ b/LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER @@ -0,0 +1,108 @@ +# CC0 1.0 Universal + +## Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an “owner”) of an original work of +authorship and/or a database (each, a “Work”). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific works +(“Commons”) that the public can reliably and without fear of later claims of +infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute +to the Commons to promote the ideal of a free culture and the further +production of creative, cultural and scientific works, or to gain reputation or +greater distribution for their Work in part through the use and efforts of +others. + +For these and/or other purposes and motivations, and without any expectation of +additional consideration or compensation, the person associating CC0 with a +Work (the “Affirmer”), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and +publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights (“Copyright and + Related Rights”). Copyright and Related Rights include, but are not limited + to, the following: + 1. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + 2. moral rights retained by the original author(s) and/or performer(s); + 3. publicity and privacy rights pertaining to a person’s image or likeness + depicted in a Work; + 4. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(i), below; + 5. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + 6. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + 7. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the “Waiver”). Affirmer + makes the Waiver for the benefit of each member of the public at large and + to the detriment of Affirmer’s heirs and successors, fully intending that + such Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer’s express + Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer’s express Statement of Purpose. In addition, to the extent the + Waiver is so judged Affirmer hereby grants to each affected person a + royalty-free, non transferable, non sublicensable, non exclusive, + irrevocable and unconditional license to exercise Affirmer’s Copyright and + Related Rights in the Work (i) in all territories worldwide, (ii) for the + maximum duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the “License”). The License + shall be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally + invalid or ineffective under applicable law, such partial invalidity or + ineffectiveness shall not invalidate the remainder of the License, and in + such case Affirmer hereby affirms that he or she will not (i) exercise any + of his or her remaining Copyright and Related Rights in the Work or (ii) + assert any associated claims and causes of action with respect to the Work, + in either case contrary to Affirmer’s express Statement of Purpose. + +4. Limitations and Disclaimers. + 1. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + 2. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or + otherwise, including without limitation warranties of title, + merchantability, fitness for a particular purpose, non infringement, or + the absence of latent or other defects, accuracy, or the present or + absence of errors, whether or not discoverable, all to the greatest + extent permissible under applicable law. + 3. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person’s Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the Work. + 4. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see +http://creativecommons.org/publicdomain/zero/1.0/. diff --git a/lib/matplotlib/backends/web_backend/js/mpl.js b/lib/matplotlib/backends/web_backend/js/mpl.js index 9e7959ec30e2..a3a8f7abc54b 100644 --- a/lib/matplotlib/backends/web_backend/js/mpl.js +++ b/lib/matplotlib/backends/web_backend/js/mpl.js @@ -169,7 +169,17 @@ mpl.figure.prototype._init_canvas = function () { 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;' ); - var resizeObserver = new ResizeObserver(function (entries) { + // Apply a ponyfill if ResizeObserver is not implemented by browser. + if (this.ResizeObserver === undefined) { + if (window.ResizeObserver !== undefined) { + this.ResizeObserver = window.ResizeObserver; + } else { + var obs = _JSXTOOLS_RESIZE_OBSERVER({}); + this.ResizeObserver = obs.ResizeObserver; + } + } + + this.resizeObserverInstance = new this.ResizeObserver(function (entries) { var nentries = entries.length; for (var i = 0; i < nentries; i++) { var entry = entries[i]; @@ -222,7 +232,7 @@ mpl.figure.prototype._init_canvas = function () { } } }); - resizeObserver.observe(canvas_div); + this.resizeObserverInstance.observe(canvas_div); function on_mouse_event_closure(name) { return function (event) { @@ -669,3 +679,7 @@ mpl.figure.prototype.toolbar_button_onclick = function (name) { mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) { this.message.textContent = tooltip; }; + +///////////////// REMAINING CONTENT GENERATED BY embed_js.py ///////////////// +// prettier-ignore +var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError("Constructor requires 'new' operator");i.set(this,e)}function h(){throw new TypeError("Function is not a constructor")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line diff --git a/lib/matplotlib/backends/web_backend/js/nbagg_mpl.js b/lib/matplotlib/backends/web_backend/js/nbagg_mpl.js index 688e1953ebe1..9c4ff87b5f7d 100644 --- a/lib/matplotlib/backends/web_backend/js/nbagg_mpl.js +++ b/lib/matplotlib/backends/web_backend/js/nbagg_mpl.js @@ -61,6 +61,7 @@ mpl.figure.prototype.handle_close = function (fig, msg) { 'cleared', fig._remove_fig_handler ); + fig.resizeObserverInstance.unobserve(fig.canvas_div); // Update the output cell to use the data from the current canvas. fig.push_to_output(); diff --git a/lib/matplotlib/backends/web_backend/package.json b/lib/matplotlib/backends/web_backend/package.json index e2a4009a971b..95bd8fdf54e6 100644 --- a/lib/matplotlib/backends/web_backend/package.json +++ b/lib/matplotlib/backends/web_backend/package.json @@ -11,5 +11,8 @@ "lint:check": "npm run prettier:check && npm run eslint:check", "prettier": "prettier --write \"**/*{.ts,.tsx,.js,.jsx,.css,.json}\"", "prettier:check": "prettier --check \"**/*{.ts,.tsx,.js,.jsx,.css,.json}\"" + }, + "dependencies": { + "@jsxtools/resize-observer": "^1.0.4" } } diff --git a/tools/embed_js.py b/tools/embed_js.py new file mode 100644 index 000000000000..571bf80238e9 --- /dev/null +++ b/tools/embed_js.py @@ -0,0 +1,102 @@ +""" +Script to embed JavaScript dependencies in mpl.js. +""" + +from collections import namedtuple +from pathlib import Path +import re +import shutil +import subprocess +import sys + + +Package = namedtuple('Package', [ + # The package to embed, in some form that `npm install` can use. + 'name', + # The path to the source file within the package to embed. + 'source', + # The path to the license file within the package to embed. + 'license']) +# The list of packages to embed, in some form that `npm install` can use. +JAVASCRIPT_PACKAGES = [ + # Polyfill/ponyfill for ResizeObserver. + Package('@jsxtools/resize-observer', 'index.js', 'LICENSE.md'), +] +# This is the magic line that must exist in mpl.js, after which the embedded +# JavaScript will be appended. +MPLJS_MAGIC_HEADER = ( + "///////////////// REMAINING CONTENT GENERATED BY embed_js.py " + "/////////////////\n") + + +def safe_name(name): + """ + Make *name* safe to use as a JavaScript variable name. + """ + return '_'.join(re.split(r'[@/-]', name)).upper() + + +def prep_package(web_backend_path, pkg): + source = web_backend_path / 'node_modules' / pkg.name / pkg.source + license = web_backend_path / 'node_modules' / pkg.name / pkg.license + if not source.exists(): + # Exact version should already be saved in package.json, so we use + # --no-save here. + try: + subprocess.run(['npm', 'install', '--no-save', pkg.name], + cwd=web_backend_path) + except FileNotFoundError as err: + raise ValueError( + f'npm must be installed to fetch {pkg.name}') from err + if not source.exists(): + raise ValueError( + f'{pkg.name} package is missing source in {pkg.source}') + elif not license.exists(): + raise ValueError( + f'{pkg.name} package is missing license in {pkg.license}') + + return source, license + + +def gen_embedded_lines(pkg, source): + name = safe_name(pkg.name) + print('Embedding', source, 'as', name) + yield '// prettier-ignore\n' + for line in source.read_text().splitlines(): + yield (line.replace('module.exports=function', f'var {name}=function') + + ' // eslint-disable-line\n') + + +def build_mpljs(web_backend_path, license_path): + mpljs_path = web_backend_path / "js/mpl.js" + mpljs_orig = mpljs_path.read_text().splitlines(keepends=True) + try: + mpljs_orig = mpljs_orig[:mpljs_orig.index(MPLJS_MAGIC_HEADER) + 1] + except IndexError as err: + raise ValueError( + f'The mpl.js file *must* have the exact line: {MPLJS_MAGIC_HEADER}' + ) from err + + with mpljs_path.open('w') as mpljs: + mpljs.writelines(mpljs_orig) + + for pkg in JAVASCRIPT_PACKAGES: + source, license = prep_package(web_backend_path, pkg) + mpljs.writelines(gen_embedded_lines(pkg, source)) + + shutil.copy(license, + license_path / f'LICENSE{safe_name(pkg.name)}') + + +if __name__ == '__main__': + # Write the mpl.js file. + if len(sys.argv) > 1: + web_backend_path = Path(sys.argv[1]) + else: + web_backend_path = (Path(__file__).parent.parent / + "lib/matplotlib/backends/web_backend") + if len(sys.argv) > 2: + license_path = Path(sys.argv[2]) + else: + license_path = Path(__file__).parent.parent / "LICENSE" + build_mpljs(web_backend_path, license_path) From 48f49dfbbe924ba4572d7cd54ed11be681abd82a Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 10 Nov 2020 15:15:26 -0500 Subject: [PATCH 22/50] Backport PR #18842: Add CPython 3.9 wheels. --- .github/workflows/cibuildwheel.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml index 0ff85ef57bf4..b567c015dc2c 100644 --- a/.github/workflows/cibuildwheel.yml +++ b/.github/workflows/cibuildwheel.yml @@ -34,6 +34,16 @@ jobs: run: | cp setup.cfg.template setup.cfg + - name: Build wheels for CPython 3.9 + run: | + python -m cibuildwheel --output-dir dist + env: + CIBW_BUILD: "cp39-*" + CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 + CIBW_MANYLINUX_I686_IMAGE: manylinux1 + CIBW_BEFORE_BUILD: pip install certifi numpy==1.19.3 + MPL_DISABLE_FH4: "yes" + - name: Build wheels for CPython run: | python -m cibuildwheel --output-dir dist From f679026f3979fa11f89adaae7d9808c75df4493d Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 11 Nov 2020 15:42:27 -0500 Subject: [PATCH 23/50] Backport PR #18929: FIX: make sure scalarmappable updates are handled correctly in 3D --- lib/mpl_toolkits/mplot3d/art3d.py | 105 +++++++++++++++++++++---- lib/mpl_toolkits/tests/test_mplot3d.py | 24 +++++- 2 files changed, 113 insertions(+), 16 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 02a310bd92bb..1c6f9d0ba72d 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -264,6 +264,8 @@ def do_3d_projection(self, renderer): """ Project the points according to renderer matrix. """ + # see _update_scalarmappable docstring for why this must be here + _update_scalarmappable(self) xyslist = [ proj3d.proj_trans_points(points, renderer.M) for points in self._segments3d] @@ -418,6 +420,8 @@ def set_3d_properties(self, zs, zdir): self.stale = True def do_3d_projection(self, renderer): + # see _update_scalarmappable docstring for why this must be here + _update_scalarmappable(self) xs, ys, zs = self._offsets3d vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M) @@ -486,6 +490,8 @@ def set_3d_properties(self, zs, zdir): self.stale = True def do_3d_projection(self, renderer): + # see _update_scalarmappable docstring for why this must be here + _update_scalarmappable(self) xs, ys, zs = self._offsets3d vxs, vys, vzs, vis = proj3d.proj_transform_clip(xs, ys, zs, renderer.M) @@ -528,6 +534,77 @@ def do_3d_projection(self, renderer): return np.min(vzs) if vzs.size else np.nan +def _update_scalarmappable(sm): + """ + Update a 3D ScalarMappable. + + With ScalarMappable objects if the data, colormap, or norm are + changed, we need to update the computed colors. This is handled + by the base class method update_scalarmappable. This method works + by, detecting if work needs to be done, and if so stashing it on + the ``self._facecolors`` attribute. + + With 3D collections we internally sort the components so that + things that should be "in front" are rendered later to simulate + having a z-buffer (in addition to doing the projections). This is + handled in the ``do_3d_projection`` methods which are called from the + draw method of the 3D Axes. These methods: + + - do the projection from 3D -> 2D + - internally sort based on depth + - stash the results of the above in the 2D analogs of state + - return the z-depth of the whole artist + + the last step is so that we can, at the Axes level, sort the children by + depth. + + The base `draw` method of the 2D artists unconditionally calls + update_scalarmappable and rely on the method's internal caching logic to + lazily evaluate. + + These things together mean you can have the sequence of events: + + - we create the artist, do the color mapping and stash the results + in a 3D specific state. + - change something about the ScalarMappable that marks it as in + need of an update (`ScalarMappable.changed` and friends). + - We call do_3d_projection and shuffle the stashed colors into the + 2D version of face colors + - the draw method calls the update_scalarmappable method which + overwrites our shuffled colors + - we get a render that is wrong + - if we re-render (either with a second save or implicitly via + tight_layout / constrained_layout / bbox_inches='tight' (ex via + inline's defaults)) we again shuffle the 3D colors + - because the CM is not marked as changed update_scalarmappable is + a no-op and we get a correct looking render. + + This function is an internal helper to: + + - sort out if we need to do the color mapping at all (has data!) + - sort out if update_scalarmappable is going to be a no-op + - copy the data over from the 2D -> 3D version + + This must be called first thing in do_3d_projection to make sure that + the correct colors get shuffled. + + Parameters + ---------- + sm : ScalarMappable + The ScalarMappable to update and stash the 3D data from + + """ + if sm._A is None: + return + copy_state = sm._update_dict['array'] + ret = sm.update_scalarmappable() + if copy_state: + if sm._is_filled: + sm._facecolor3d = sm._facecolors + elif sm._is_stroked: + sm._edgecolor3d = sm._edgecolors + + def patch_collection_2d_to_3d(col, zs=0, zdir='z', depthshade=True): """ Convert a :class:`~matplotlib.collections.PatchCollection` into a @@ -650,8 +727,8 @@ def set_3d_properties(self): self.update_scalarmappable() self._sort_zpos = None self.set_zsort('average') - self._facecolors3d = PolyCollection.get_facecolor(self) - self._edgecolors3d = PolyCollection.get_edgecolor(self) + self._facecolor3d = PolyCollection.get_facecolor(self) + self._edgecolor3d = PolyCollection.get_edgecolor(self) self._alpha3d = PolyCollection.get_alpha(self) self.stale = True @@ -664,17 +741,15 @@ def do_3d_projection(self, renderer): """ Perform the 3D projection for this object. """ - # FIXME: This may no longer be needed? - if self._A is not None: - self.update_scalarmappable() - self._facecolors3d = self._facecolors + # see _update_scalarmappable docstring for why this must be here + _update_scalarmappable(self) txs, tys, tzs = proj3d._proj_transform_vec(self._vec, renderer.M) xyzlist = [(txs[sl], tys[sl], tzs[sl]) for sl in self._segslices] # This extra fuss is to re-order face / edge colors - cface = self._facecolors3d - cedge = self._edgecolors3d + cface = self._facecolor3d + cedge = self._edgecolor3d if len(cface) != len(xyzlist): cface = cface.repeat(len(xyzlist), axis=0) if len(cedge) != len(xyzlist): @@ -699,8 +774,8 @@ def do_3d_projection(self, renderer): else: PolyCollection.set_verts(self, segments_2d, self._closed) - if len(self._edgecolors3d) != len(cface): - self._edgecolors2d = self._edgecolors3d + if len(self._edgecolor3d) != len(cface): + self._edgecolors2d = self._edgecolor3d # Return zorder value if self._sort_zpos is not None: @@ -717,23 +792,23 @@ def do_3d_projection(self, renderer): def set_facecolor(self, colors): PolyCollection.set_facecolor(self, colors) - self._facecolors3d = PolyCollection.get_facecolor(self) + self._facecolor3d = PolyCollection.get_facecolor(self) def set_edgecolor(self, colors): PolyCollection.set_edgecolor(self, colors) - self._edgecolors3d = PolyCollection.get_edgecolor(self) + self._edgecolor3d = PolyCollection.get_edgecolor(self) def set_alpha(self, alpha): # docstring inherited artist.Artist.set_alpha(self, alpha) try: - self._facecolors3d = mcolors.to_rgba_array( - self._facecolors3d, self._alpha) + self._facecolor3d = mcolors.to_rgba_array( + self._facecolor3d, self._alpha) except (AttributeError, TypeError, IndexError): pass try: self._edgecolors = mcolors.to_rgba_array( - self._edgecolors3d, self._alpha) + self._edgecolor3d, self._alpha) except (AttributeError, TypeError, IndexError): pass self.stale = True diff --git a/lib/mpl_toolkits/tests/test_mplot3d.py b/lib/mpl_toolkits/tests/test_mplot3d.py index 7d4d9d3e1c77..999dafdc92a9 100644 --- a/lib/mpl_toolkits/tests/test_mplot3d.py +++ b/lib/mpl_toolkits/tests/test_mplot3d.py @@ -106,7 +106,7 @@ def test_bar3d_lightsource(): # the top facecolors compared to the default, and that those colors are # precisely the colors from the colormap, due to the illumination parallel # to the z-axis. - np.testing.assert_array_equal(color, collection._facecolors3d[1::6]) + np.testing.assert_array_equal(color, collection._facecolor3d[1::6]) @mpl3d_image_comparison(['contour3d.png']) @@ -1087,3 +1087,25 @@ def test_colorbar_pos(): fig.canvas.draw() # check that actually on the bottom assert cbar.ax.get_position().extents[1] < 0.2 + + +@pytest.mark.style('default') +@check_figures_equal(extensions=["png"]) +def test_scalarmap_update(fig_test, fig_ref): + + x, y, z = np.array((list(itertools.product(*[np.arange(0, 5, 1), + np.arange(0, 5, 1), + np.arange(0, 5, 1)])))).T + c = x + y + + # test + ax_test = fig_test.add_subplot(111, projection='3d') + sc_test = ax_test.scatter(x, y, z, c=c, s=40, cmap='viridis') + # force a draw + fig_test.canvas.draw() + # mark it as "stale" + sc_test.changed() + + # ref + ax_ref = fig_ref.add_subplot(111, projection='3d') + sc_ref = ax_ref.scatter(x, y, z, c=c, s=40, cmap='viridis') From 1158688fd5e03af8ed2e8028bae106095204125a Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 11 Nov 2020 21:20:17 -0500 Subject: [PATCH 24/50] DOC: Update GitHub stats for 3.3.3. --- doc/users/github_stats.rst | 141 +++++++++--------- .../prev_whats_new/github_stats_3.3.2.rst | 89 +++++++++++ 2 files changed, 161 insertions(+), 69 deletions(-) create mode 100644 doc/users/prev_whats_new/github_stats_3.3.2.rst diff --git a/doc/users/github_stats.rst b/doc/users/github_stats.rst index 7ef8dd1111b6..ab8f8384b8aa 100644 --- a/doc/users/github_stats.rst +++ b/doc/users/github_stats.rst @@ -3,91 +3,94 @@ GitHub Stats ============ -GitHub stats for 2020/08/14 - 2020/09/15 (tag: v3.3.1) +GitHub stats for 2020/09/15 - 2020/11/11 (tag: v3.3.2) These lists are automatically generated, and may be incomplete or contain duplicates. -We closed 15 issues and merged 39 pull requests. -The full list can be seen `on GitHub `__ +We closed 14 issues and merged 46 pull requests. +The full list can be seen `on GitHub `__ -The following 14 authors contributed 61 commits. +The following 11 authors contributed 73 commits. * Antony Lee -* Bruno Beltran * David Stansby -* David Young * Elliott Sales de Andrade -* Greg Lucas +* Eric Larson * Jody Klymak -* johnthagen * Jouni K. Seppänen -* Richard Sheridan -* richardsheridan * Ryan May +* shevawen +* Stephen Sinclair * Thomas A Caswell * Tim Hoffmann GitHub issues and pull requests: -Pull Requests (39): - -* :ghpull:`18488`: Backport PR #18483 on branch v3.3.x (DOC: reword non-monotonic cell center warning) -* :ghpull:`18483`: DOC: reword non-monotonic cell center warning -* :ghpull:`18485`: Backport PR #18475 on branch v3.3.x (BF: ensure exception caught if no kpeswitch) -* :ghpull:`18482`: Backport PR #18398 on branch v3.3.x (Warn on non-increasing/decreasing pcolor coords) -* :ghpull:`18484`: Backport PR #18458: Fix huge imshow range -* :ghpull:`18475`: BF: ensure exception caught if no kpeswitch -* :ghpull:`18458`: Fix huge imshow range -* :ghpull:`18398`: Warn on non-increasing/decreasing pcolor coords -* :ghpull:`18479`: Nbagg backports -* :ghpull:`18454`: nbagg: Use OutputArea event to trigger figure close. -* :ghpull:`18469`: Backport PR #18464 on branch v3.3.x (Remove extra stickies in barstacked histogram.) -* :ghpull:`18464`: Remove extra stickies in barstacked histogram. -* :ghpull:`18459`: Backport PR #18393 on branch v3.3.x (Fix Axis scale on twinned Axes.) -* :ghpull:`18393`: Fix Axis scale on twinned Axes. -* :ghpull:`18441`: Backport PR #18395: TkAgg bugfix: deselect buttons that are not the current _Mode -* :ghpull:`18395`: TkAgg bugfix: deselect buttons that are not the current _Mode -* :ghpull:`18380`: Backport PR #18374 on branch v3.3.x (FIX: make _reshape_2D accept pandas df with string indices) -* :ghpull:`18374`: FIX: make _reshape_2D accept pandas df with string indices -* :ghpull:`18376`: Backport PR #18298 on branch v3.3.x (Include license files in built distribution) -* :ghpull:`18375`: Backport PR #18293 on branch v3.3.x (Fix scatter3d color/linewidth re-projection) -* :ghpull:`18298`: Include license files in built distribution -* :ghpull:`18293`: Fix scatter3d color/linewidth re-projection -* :ghpull:`18361`: nbagg: Store DPI ratio on figure instead of window. -* :ghpull:`18354`: Backport PR #18352 on branch v3.3.x (Avoid triggering backend resolution during qt initial import.) -* :ghpull:`18352`: Avoid triggering backend resolution during qt initial import. -* :ghpull:`18335`: Backport PR #18322 on branch v3.3.x (Disable FH4 so that we don't require VCRUNTIME140_1.dll.) -* :ghpull:`18322`: Disable FH4 so that we don't require VCRUNTIME140_1.dll. -* :ghpull:`18333`: Backport PR #18328 on branch v3.3.x (Add missing check for None in Qt toolmanager.) -* :ghpull:`18328`: Add missing check for None in Qt toolmanager. -* :ghpull:`18309`: Backport PR #18304 on branch v3.3.x (Fix canvas redraws during motion in figures with a Button or TextBox) -* :ghpull:`18304`: Fix canvas redraws during motion in figures with a Button or TextBox -* :ghpull:`18297`: Backport PR #18288 on branch v3.3.x (FIX: check if axes is off page before repositioning title) -* :ghpull:`18288`: FIX: check if axes is off page before repositioning title -* :ghpull:`18269`: Backport PR #18266 on branch v3.3.x (Fix Path.get_extents for empty paths.) -* :ghpull:`18266`: Fix Path.get_extents for empty paths. -* :ghpull:`18263`: Backport PR #18260 on branch v3.3.x (Add parent widget to IntVar) -* :ghpull:`18260`: Add parent widget to IntVar -* :ghpull:`18253`: Backport PR #18245 on branch v3.3.x -* :ghpull:`18245`: MNT: do a better job guessing the GUI framework in use - -Issues (15): - -* :ghissue:`18415`: imshow with LogNorm crashes with certain inputs -* :ghissue:`18447`: nbagg: Closing a figure from the notebook does not close the python figure -* :ghissue:`18470`: interactive plots slow with matplotlib 3.3.1 -* :ghissue:`18457`: Incorrect log y-scale for histogram with partitioned and barstacked data -* :ghissue:`18385`: twinx not respecting log-scale -* :ghissue:`18371`: Plotting a pandas DataFrame with string MultiIndex -* :ghissue:`18296`: LICENSE file(s) not included in published PyPI package -* :ghissue:`18287`: scatter3D assigns wrong color to points for some plot orientations -* :ghissue:`18292`: ImportError: DLL load failed with Matplotlib 3.3.1 on Windows -* :ghissue:`18327`: Tool Manager: adding buttons to toolbar fails with matplotlib version 3.3.1 using Qt backend -* :ghissue:`18324`: Poor UI responsiveness of 3.3.1 compared with 3.2.2 for interactive mode UI using widgets -* :ghissue:`18303`: Canvas redraws during any motion when Button is present -* :ghissue:`18283`: Automatic title placement wrong if parent axes is off the page -* :ghissue:`18254`: scatter(..., marker='') raises on drawing with mpl3.3.1 -* :ghissue:`18259`: New IntVar needs a parent widget +Pull Requests (46): + +* :ghpull:`18936`: Backport PR #18929 on branch v3.3.x +* :ghpull:`18929`: FIX: make sure scalarmappable updates are handled correctly in 3D +* :ghpull:`18928`: Backport PR #18842 on branch v3.3.x (Add CPython 3.9 wheels.) +* :ghpull:`18842`: Add CPython 3.9 wheels. +* :ghpull:`18921`: Backport PR #18732 on branch v3.3.x (Add a ponyfill for ResizeObserver on older browsers.) +* :ghpull:`18732`: Add a ponyfill for ResizeObserver on older browsers. +* :ghpull:`18886`: Backport #18860 on branch v3.3.x +* :ghpull:`18860`: FIX: stop deprecation message colorbar +* :ghpull:`18845`: Backport PR #18839 on branch v3.3.x +* :ghpull:`18843`: Backport PR #18756 on branch v3.3.x (FIX: improve date performance regression) +* :ghpull:`18850`: Backport CI fixes to v3.3.x +* :ghpull:`18839`: MNT: make sure we do not mutate input in Text.update +* :ghpull:`18838`: Fix ax.set_xticklabels(fontproperties=fp) +* :ghpull:`18756`: FIX: improve date performance regression +* :ghpull:`18787`: Backport PR #18769 on branch v3.3.x +* :ghpull:`18786`: Backport PR #18754 on branch v3.3.x (FIX: make sure we have more than 1 tick with small log ranges) +* :ghpull:`18754`: FIX: make sure we have more than 1 tick with small log ranges +* :ghpull:`18769`: Support ``ax.grid(visible=)``. +* :ghpull:`18778`: Backport PR #18773 on branch v3.3.x (Update to latest cibuildwheel release.) +* :ghpull:`18773`: Update to latest cibuildwheel release. +* :ghpull:`18755`: Backport PR #18734 on branch v3.3.x (Fix deprecation warning in GitHub Actions.) +* :ghpull:`18734`: Fix deprecation warning in GitHub Actions. +* :ghpull:`18725`: Backport PR #18533 on branch v3.3.x +* :ghpull:`18723`: Backport PR #18584 on branch v3.3.x (Fix setting 0-timeout timer with Tornado.) +* :ghpull:`18676`: Backport PR #18670 on branch v3.3.x (MNT: make certifi actually optional) +* :ghpull:`18670`: MNT: make certifi actually optional +* :ghpull:`18665`: Backport PR #18639 on branch v3.3.x (nbagg: Don't close figures for bubbled events.) +* :ghpull:`18639`: nbagg: Don't close figures for bubbled events. +* :ghpull:`18640`: Backport PR #18636 on branch v3.3.x (BLD: certifi is not a run-time dependency) +* :ghpull:`18636`: BLD: certifi is not a run-time dependency +* :ghpull:`18629`: Backport PR #18621 on branch v3.3.x (Fix singleshot timers in wx.) +* :ghpull:`18621`: Fix singleshot timers in wx. +* :ghpull:`18607`: Backport PR #18604 on branch v3.3.x (Update test image to fix Ghostscript 9.53.) +* :ghpull:`18604`: Update test image to fix Ghostscript 9.53. +* :ghpull:`18584`: Fix setting 0-timeout timer with Tornado. +* :ghpull:`18550`: backport pr 18549 +* :ghpull:`18545`: Backport PR #18540 on branch v3.3.x (Call to ExitStack.push should have been ExitStack.callback.) +* :ghpull:`18549`: FIX: unit-convert pcolorargs before interpolating +* :ghpull:`18540`: Call to ExitStack.push should have been ExitStack.callback. +* :ghpull:`18533`: Correctly remove support for \stackrel. +* :ghpull:`18509`: Backport PR #18505 on branch v3.3.x (Fix depth shading when edge/facecolor is none.) +* :ghpull:`18505`: Fix depth shading when edge/facecolor is none. +* :ghpull:`18504`: Backport PR #18500 on branch v3.3.x (BUG: Fix all-masked imshow) +* :ghpull:`18500`: BUG: Fix all-masked imshow +* :ghpull:`18476`: CI: skip qt, cairo, pygobject related installs on OSX on travis +* :ghpull:`18134`: Build on xcode9 + +Issues (14): + +* :ghissue:`18885`: 3D Scatter Plot with Colorbar is not saved correctly with savefig +* :ghissue:`18922`: pyplot.xticks(): Font property specification is not effective except 1st tick label. +* :ghissue:`18481`: "%matplotlib notebook" not working in firefox with matplotlib 3.3.1 +* :ghissue:`18595`: Getting internal "MatplotlibDeprecationWarning: shading='flat' ..." +* :ghissue:`18743`: from mpl 3.2.2 to 3.3.0 enormous increase in creation time +* :ghissue:`18317`: pcolormesh: shading='nearest' and non-monotonic coordinates +* :ghissue:`18758`: Using Axis.grid(visible=True) results in TypeError for multiple values for keyword argument +* :ghissue:`18638`: ``matplotlib>=3.3.2`` breaks ``ipywidgets.interact`` +* :ghissue:`18337`: Error installing matplotlib-3.3.1 using pip due to old version of certifi on conda environment +* :ghissue:`18620`: wx backend assertion error with fig.canvas.timer.start() +* :ghissue:`18551`: test_transparent_markers[pdf] is broken on v3.3.x Travis macOS +* :ghissue:`18580`: Animation freezes in Jupyter notebook +* :ghissue:`18547`: pcolormesh x-axis with datetime broken for nearest shading +* :ghissue:`18539`: Error in Axes.redraw_in_frame in use of ExitStack: push() takes 2 positional arguments but 3 were given Previous GitHub Stats diff --git a/doc/users/prev_whats_new/github_stats_3.3.2.rst b/doc/users/prev_whats_new/github_stats_3.3.2.rst new file mode 100644 index 000000000000..8f9bb9a6eceb --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.3.2.rst @@ -0,0 +1,89 @@ +.. _github-stats-3-3-2: + +GitHub Stats for Matplotlib 3.3.2 +================================= + +GitHub stats for 2020/08/14 - 2020/09/15 (tag: v3.3.1) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 15 issues and merged 39 pull requests. +The full list can be seen `on GitHub `__ + +The following 13 authors contributed 61 commits. + +* Antony Lee +* Bruno Beltran +* David Stansby +* David Young +* Elliott Sales de Andrade +* Greg Lucas +* Jody Klymak +* johnthagen +* Jouni K. Seppänen +* Richard Sheridan +* Ryan May +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (39): + +* :ghpull:`18488`: Backport PR #18483 on branch v3.3.x (DOC: reword non-monotonic cell center warning) +* :ghpull:`18483`: DOC: reword non-monotonic cell center warning +* :ghpull:`18485`: Backport PR #18475 on branch v3.3.x (BF: ensure exception caught if no kpeswitch) +* :ghpull:`18482`: Backport PR #18398 on branch v3.3.x (Warn on non-increasing/decreasing pcolor coords) +* :ghpull:`18484`: Backport PR #18458: Fix huge imshow range +* :ghpull:`18475`: BF: ensure exception caught if no kpeswitch +* :ghpull:`18458`: Fix huge imshow range +* :ghpull:`18398`: Warn on non-increasing/decreasing pcolor coords +* :ghpull:`18479`: Nbagg backports +* :ghpull:`18454`: nbagg: Use OutputArea event to trigger figure close. +* :ghpull:`18469`: Backport PR #18464 on branch v3.3.x (Remove extra stickies in barstacked histogram.) +* :ghpull:`18464`: Remove extra stickies in barstacked histogram. +* :ghpull:`18459`: Backport PR #18393 on branch v3.3.x (Fix Axis scale on twinned Axes.) +* :ghpull:`18393`: Fix Axis scale on twinned Axes. +* :ghpull:`18441`: Backport PR #18395: TkAgg bugfix: deselect buttons that are not the current _Mode +* :ghpull:`18395`: TkAgg bugfix: deselect buttons that are not the current _Mode +* :ghpull:`18380`: Backport PR #18374 on branch v3.3.x (FIX: make _reshape_2D accept pandas df with string indices) +* :ghpull:`18374`: FIX: make _reshape_2D accept pandas df with string indices +* :ghpull:`18376`: Backport PR #18298 on branch v3.3.x (Include license files in built distribution) +* :ghpull:`18375`: Backport PR #18293 on branch v3.3.x (Fix scatter3d color/linewidth re-projection) +* :ghpull:`18298`: Include license files in built distribution +* :ghpull:`18293`: Fix scatter3d color/linewidth re-projection +* :ghpull:`18361`: nbagg: Store DPI ratio on figure instead of window. +* :ghpull:`18354`: Backport PR #18352 on branch v3.3.x (Avoid triggering backend resolution during qt initial import.) +* :ghpull:`18352`: Avoid triggering backend resolution during qt initial import. +* :ghpull:`18335`: Backport PR #18322 on branch v3.3.x (Disable FH4 so that we don't require VCRUNTIME140_1.dll.) +* :ghpull:`18322`: Disable FH4 so that we don't require VCRUNTIME140_1.dll. +* :ghpull:`18333`: Backport PR #18328 on branch v3.3.x (Add missing check for None in Qt toolmanager.) +* :ghpull:`18328`: Add missing check for None in Qt toolmanager. +* :ghpull:`18309`: Backport PR #18304 on branch v3.3.x (Fix canvas redraws during motion in figures with a Button or TextBox) +* :ghpull:`18304`: Fix canvas redraws during motion in figures with a Button or TextBox +* :ghpull:`18297`: Backport PR #18288 on branch v3.3.x (FIX: check if axes is off page before repositioning title) +* :ghpull:`18288`: FIX: check if axes is off page before repositioning title +* :ghpull:`18269`: Backport PR #18266 on branch v3.3.x (Fix Path.get_extents for empty paths.) +* :ghpull:`18266`: Fix Path.get_extents for empty paths. +* :ghpull:`18263`: Backport PR #18260 on branch v3.3.x (Add parent widget to IntVar) +* :ghpull:`18260`: Add parent widget to IntVar +* :ghpull:`18253`: Backport PR #18245 on branch v3.3.x +* :ghpull:`18245`: MNT: do a better job guessing the GUI framework in use + +Issues (15): + +* :ghissue:`18415`: imshow with LogNorm crashes with certain inputs +* :ghissue:`18447`: nbagg: Closing a figure from the notebook does not close the python figure +* :ghissue:`18470`: interactive plots slow with matplotlib 3.3.1 +* :ghissue:`18457`: Incorrect log y-scale for histogram with partitioned and barstacked data +* :ghissue:`18385`: twinx not respecting log-scale +* :ghissue:`18371`: Plotting a pandas DataFrame with string MultiIndex +* :ghissue:`18296`: LICENSE file(s) not included in published PyPI package +* :ghissue:`18287`: scatter3D assigns wrong color to points for some plot orientations +* :ghissue:`18292`: ImportError: DLL load failed with Matplotlib 3.3.1 on Windows +* :ghissue:`18327`: Tool Manager: adding buttons to toolbar fails with matplotlib version 3.3.1 using Qt backend +* :ghissue:`18324`: Poor UI responsiveness of 3.3.1 compared with 3.2.2 for interactive mode UI using widgets +* :ghissue:`18303`: Canvas redraws during any motion when Button is present +* :ghissue:`18283`: Automatic title placement wrong if parent axes is off the page +* :ghissue:`18254`: scatter(..., marker='') raises on drawing with mpl3.3.1 +* :ghissue:`18259`: New IntVar needs a parent widget From 5a4f1b675da3d17df2d77d03bceab331afcc21db Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 11 Nov 2020 22:12:59 -0500 Subject: [PATCH 25/50] REL: v3.3.3 This is the third bugfix release of the 3.3.x series. This release contains several critical bug-fixes: * Fix calls to `Axis.grid` with argument `visible=True`. * Fix fully masked `imshow`. * Fix inconsistent color mapping in scatter for 3D plots. * Fix notebook/nbAgg figures when used with ipywidgets in the same cell. * Fix notebook/nbAgg/WebAgg on older (e.g., Firefox ESR) browsers. * Fix pcolormesh with `datetime` coordinates. * Fix performance regression with `datetime`s. * Fix singular ticks with small log ranges. * Fix timers/animations on wx and notebook backends. * Remove certifi as a hard runtime dependency. From 1b41d199d764ce5a28da2675c310c64b7d2f2575 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 11 Nov 2020 22:55:25 -0500 Subject: [PATCH 26/50] BLD: bump branch away from tag So the tarballs from GitHub are stable. From 447bdbbf58e148d0da65d53353a4a548e706463e Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 11 Nov 2020 23:27:40 -0500 Subject: [PATCH 27/50] DOC: Add Zenodo DOI for 3.3.3. --- doc/_static/zenodo_cache/4268928.svg | 35 ++++++++++++++++++++++++++++ doc/citing.rst | 3 +++ tools/cache_zenodo_svg.py | 1 + 3 files changed, 39 insertions(+) create mode 100644 doc/_static/zenodo_cache/4268928.svg diff --git a/doc/_static/zenodo_cache/4268928.svg b/doc/_static/zenodo_cache/4268928.svg new file mode 100644 index 000000000000..e7d632a40e54 --- /dev/null +++ b/doc/_static/zenodo_cache/4268928.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4268928 + + + 10.5281/zenodo.4268928 + + + \ No newline at end of file diff --git a/doc/citing.rst b/doc/citing.rst index cdc4c60fcbd0..2afc55d3fa20 100644 --- a/doc/citing.rst +++ b/doc/citing.rst @@ -39,6 +39,9 @@ By version .. START OF AUTOGENERATED +v3.3.3 + .. image:: _static/zenodo_cache/4268928.svg + :target: https://doi.org/10.5281/zenodo.4268928 v3.3.2 .. image:: _static/zenodo_cache/4030140.svg :target: https://doi.org/10.5281/zenodo.4030140 diff --git a/tools/cache_zenodo_svg.py b/tools/cache_zenodo_svg.py index 27d707ae36b7..b2d36a2c87c3 100644 --- a/tools/cache_zenodo_svg.py +++ b/tools/cache_zenodo_svg.py @@ -62,6 +62,7 @@ def _get_xdg_cache_dir(): if __name__ == "__main__": data = { + "v3.3.3": "4268928", "v3.3.2": "4030140", "v3.3.1": "3984190", "v3.3.0": "3948793", From 5f7c694e9497cb3d71cf8e5f03b24b5378d89a97 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 3 Dec 2020 14:53:14 -0500 Subject: [PATCH 28/50] Backport PR #19036: Start testing using GitHub Actions --- .github/workflows/tests.yml | 226 ++++++++++++++++++++++++ .travis.yml | 2 +- requirements/testing/minver.txt | 8 + requirements/testing/travis36minver.txt | 6 - 4 files changed, 235 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/tests.yml create mode 100644 requirements/testing/minver.txt delete mode 100644 requirements/testing/travis36minver.txt diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000000..255301842385 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,226 @@ +name: Tests + +on: + push: + branches-ignore: + - auto-backport-of-pr-[0-9]+ + - v[0-9]+.[0-9]+.[0-9x]+-doc + pull_request: + +env: + NO_AT_BRIDGE: 1 # Necessary for GTK3 interactive test. + OPENBLAS_NUM_THREADS: 1 + PYTHONFAULTHANDLER: 1 + +jobs: + test: + name: "Python ${{ matrix.python-version }} on ${{ matrix.os }} ${{ matrix.name-suffix }}" + runs-on: ${{ matrix.os }} + + strategy: + matrix: + include: + - name-suffix: "(Minimum Versions)" + os: ubuntu-16.04 + python-version: 3.6 + extra-requirements: '-c requirements/testing/minver.txt' + delete-font-cache: true + XVFB_RUN: xvfb-run -a + - os: ubuntu-16.04 + python-version: 3.7 + extra-requirements: '-r requirements/testing/travis_extra.txt' + XVFB_RUN: xvfb-run -a + - os: ubuntu-16.04 + python-version: 3.8 + extra-requirements: '-r requirements/testing/travis_extra.txt' + XVFB_RUN: xvfb-run -a + - os: macos-latest + python-version: 3.8 + XVFB_RUN: "" + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install OS dependencies + run: | + case "${{ runner.os }}" in + Linux) + sudo apt-get update -yy + sudo apt-get install -yy \ + ccache \ + cm-super \ + dvipng \ + ffmpeg \ + gdb \ + gir1.2-gtk-3.0 \ + graphviz \ + inkscape \ + lcov \ + libcairo2 \ + libcairo2-dev \ + libffi-dev \ + libgeos-dev \ + libgirepository1.0-dev \ + libsdl2-2.0-0 \ + libxkbcommon-x11-0 \ + libxcb-icccm4 \ + libxcb-image0 \ + libxcb-keysyms1 \ + libxcb-randr0 \ + libxcb-render-util0 \ + libxcb-xinerama0 \ + lmodern \ + fonts-freefont-otf \ + texlive-pictures \ + pkg-config \ + qtbase5-dev \ + texlive-fonts-recommended \ + texlive-latex-base \ + texlive-latex-extra \ + texlive-latex-recommended \ + texlive-luatex \ + texlive-xetex \ + ttf-wqy-zenhei + ;; + macOS) + brew update + brew install ccache + ;; + esac + + - name: Cache pip + uses: actions/cache@v2 + if: startsWith(runner.os, 'Linux') + with: + path: ~/.cache/pip + key: ${{ runner.os }}-py${{ matrix.python-version }}-pip-${{ hashFiles('requirements/*/*.txt') }} + restore-keys: | + ${{ runner.os }}-py${{ matrix.python-version }}-pip- + - name: Cache pip + uses: actions/cache@v2 + if: startsWith(runner.os, 'macOS') + with: + path: ~/Library/Caches/pip + key: ${{ runner.os }}-py${{ matrix.python-version }}-pip-${{ hashFiles('requirements/*/*.txt') }} + restore-keys: | + ${{ runner.os }}-py${{ matrix.python-version }}-pip- + - name: Cache ccache + uses: actions/cache@v2 + with: + path: | + ~/.ccache + key: ${{ runner.os }}-py${{ matrix.python-version }}-ccache-${{ hashFiles('src/*') }} + restore-keys: | + ${{ runner.os }}-py${{ matrix.python-version }}-ccache- + - name: Cache Matplotlib + uses: actions/cache@v2 + with: + path: | + ~/.cache/matplotlib + !~/.cache/matplotlib/tex.cache + !~/.cache/matplotlib/test_cache + key: ${{ runner.os }}-py${{ matrix.python-version }}-mpl-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-py${{ matrix.python-version }}-mpl-${{ github.ref }}- + ${{ runner.os }}-py${{ matrix.python-version }}-mpl- + + - name: Install Python dependencies + run: | + # Upgrade pip and setuptools and wheel to get as clean an install as + # possible. + python -mpip install --upgrade pip setuptools wheel + + # Install dependencies from PyPI. + python -mpip install --upgrade $PRE \ + cycler kiwisolver numpy pillow pyparsing python-dateutil \ + -r requirements/testing/travis_all.txt \ + ${{ matrix.extra-requirements }} + + # Install optional dependencies from PyPI. + # Sphinx is needed to run sphinxext tests + python -mpip install --upgrade sphinx + + # GUI toolkits are pip-installable only for some versions of Python + # so don't fail if we can't install them. Make it easier to check + # whether the install was successful by trying to import the toolkit + # (sometimes, the install appears to be successful but shared + # libraries cannot be loaded at runtime, so an actual import is a + # better check). + if [[ "${{ runner.os }}" != 'macOS' ]]; then + # PyGObject, pycairo, and cariocffi do not install on OSX 10.12; + # pycairo 1.20+ requires a new version of Cairo, unavailable on + # Ubuntu 16.04, so PyGObject must be installed without build + # isolation in order to pick up the lower pre-installed version. + python -mpip install --upgrade 'pycairo<1.20.0' 'cairocffi>=0.8' && + python -mpip install --upgrade --no-build-isolation PyGObject && + python -c 'import gi; gi.require_version("Gtk", "3.0"); from gi.repository import Gtk' && + echo 'PyGObject is available' || + echo 'PyGObject is not available' + + # There are no functioning wheels available for OSX 10.12 (as of + # Sept 2020) for either pyqt5 (there are only wheels for 10.13+) or + # pyside2 (the latest version (5.13.2) with 10.12 wheels has a + # fatal to us bug, it was fixed in 5.14.0 which has 10.13 wheels) + python -mpip install --upgrade pyqt5 && + python -c 'import PyQt5.QtCore' && + echo 'PyQt5 is available' || + echo 'PyQt5 is not available' + python -mpip install --upgrade pyside2 && + python -c 'import PySide2.QtCore' && + echo 'PySide2 is available' || + echo 'PySide2 is not available' + fi + python -mpip install --upgrade \ + -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-16.04 \ + wxPython && + python -c 'import wx' && + echo 'wxPython is available' || + echo 'wxPython is not available' + + - name: Install Matplotlib + run: | + ccache -s + git describe + + # Set flag in a delayed manner to avoid issues with installing other + # packages + if [[ "${{ runner.os }}" != 'macOS' ]]; then + export CPPFLAGS=--coverage + fi + + # All dependencies must have been pre-installed, so that the minver + # constraints are held. + python -mpip install --no-deps -e . + + if [[ "${{ runner.os }}" != 'macOS' ]]; then + unset CPPFLAGS + fi + + - name: Clear font cache + run: | + rm -rf ~/.cache/matplotlib + if: matrix.delete-font-cache + + - name: Run pytest + run: | + ${{ matrix.XVFB_RUN }} python -mpytest -raR -n auto \ + --maxfail=50 --timeout=300 --durations=25 \ + --cov-report= --cov=lib --log-level=DEBUG + + - name: Filter C coverage + run: | + lcov --capture --directory . --output-file coverage.info + lcov --output-file coverage.info \ + --extract coverage.info $PWD/src/'*' $PWD/lib/'*' + lcov --list coverage.info + find . -name '*.gc*' -delete + if: ${{ runner.os != 'macOS' }} + - name: Upload code coverage + uses: codecov/codecov-action@v1 diff --git a/.travis.yml b/.travis.yml index 59e6f5b3fb5f..0c42c0db2e34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,7 +75,7 @@ matrix: include: - python: 3.6 env: - - PINNEDVERS='-c requirements/testing/travis36minver.txt' + - PINNEDVERS='-c requirements/testing/minver.txt' - DELETE_FONT_CACHE=1 - python: 3.7 env: diff --git a/requirements/testing/minver.txt b/requirements/testing/minver.txt new file mode 100644 index 000000000000..c13164a1ee65 --- /dev/null +++ b/requirements/testing/minver.txt @@ -0,0 +1,8 @@ +# Extra pip requirements for the minimum-version CI run + +cycler==0.10 +kiwisolver==1.0.1 +numpy==1.15.0 +pillow==6.2.0 +pyparsing==2.0.3 +python-dateutil==2.1 diff --git a/requirements/testing/travis36minver.txt b/requirements/testing/travis36minver.txt deleted file mode 100644 index 2b012c01a6ce..000000000000 --- a/requirements/testing/travis36minver.txt +++ /dev/null @@ -1,6 +0,0 @@ -# Extra pip requirements for the first travis python 3.6 build - -cycler==0.10 -python-dateutil==2.1 -numpy==1.15.0 -pyparsing==2.0.3 From cb7c722fb8f7e9555031b2d2074ea3e6528192c0 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Mon, 14 Dec 2020 03:02:20 +0100 Subject: [PATCH 29/50] Backport PR #19108: Fix failing animation test with pytest 6.2. --- lib/matplotlib/tests/test_image.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 6ffb2e2d0554..71c7f8e16d01 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -718,7 +718,8 @@ def test_load_from_url(): + ('///' if sys.platform == 'win32' else '') + path.resolve().as_posix()) plt.imread(url) - plt.imread(urllib.request.urlopen(url)) + with urllib.request.urlopen(url) as file: + plt.imread(file) @image_comparison(['log_scale_image'], remove_text=True) From 400ea30016ba24bc98d36f228e4461bcc2449a5c Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 16 Dec 2020 16:26:11 -0500 Subject: [PATCH 30/50] FIX: Explicitly clean up temporary files in HTMLWriter - HTMLWriter inherits from FileMovieWriter. - FileMovieWriter create a non-context manager TemporayDirectory on init. - The TemporayDirectory is cleaned up in the cleaup method of FileMovieWriter. - However this method (and its call chain through finish) try to either call a subprocess to merge a bunch of single-frame files into a movie (not relevant) or to clean up such a process (not relevant). - The least disruptive fix is to duplicate the file clean up code. --- lib/matplotlib/animation.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 2568d455de39..472de0f8dc5b 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -891,6 +891,22 @@ def finish(self): interval=interval, **mode_dict)) + # duplicate the temporary file clean up logic from + # FileMovieWriter.cleanup. We can not call the inherited + # versions of finished or cleanup because both assume that + # there is a subprocess that we either need to call to merge + # many frames together or that there is a subprocess call that + # we need to clean up. + if self._tmpdir: + _log.debug('MovieWriter: clearing temporary path=%s', self._tmpdir) + self._tmpdir.cleanup() + else: + if self._clear_temp: + _log.debug('MovieWriter: clearing temporary paths=%s', + self._temp_paths) + for path in self._temp_paths: + path.unlink() + class Animation: """ From c7c05d35d9dcbce0c45a5c75db4f85784d687628 Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 5 Dec 2019 10:00:27 +0100 Subject: [PATCH 31/50] Closes #15796: latex_elements defined twice in doc/conf.py This commit reactivates original latex_elements['preamble'] key which was shadowed by the bug about latex_elements being defined twice in the conf.py. It removes from this latex preamble the loading of amsmath, amssymb, amsfonts as this is already added by Sphinx, and of txfonts because this is not compatible with fontspec and the already executed command \setmainfont{DejaVu Serif}. Memo: expdlist package breaks PDF build if a description list ends up in a table cell, as happens actually with Matplotlib.tex file. But, by luck, the enumitem LaTeX package modifications of LaTeX description lists masks the expdlist potential breakage. --- doc/conf.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 00eca945f82d..768dbd75700e 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -320,7 +320,19 @@ def _check_dependencies(): # the title page. latex_logo = None +# Use Unicode aware LaTeX engine +latex_engine = 'xelatex' # or 'lualatex' + latex_elements = {} + +# Keep babel usage also with xelatex (Sphinx default is polyglossia) +# If this key is removed or changed, latex build directory must be cleaned +latex_elements['babel'] = r'\usepackage{babel}' + +# Font configuration +# Sphinx default since 2.x is GNU FreeFont +latex_elements['fontpkg'] = r'\setmainfont{DejaVu Serif}' + # Additional stuff for the LaTeX preamble. latex_elements['preamble'] = r""" % One line per author on title page @@ -333,11 +345,6 @@ def _check_dependencies(): \let\latexdescription=\description \def\description{\latexdescription{}{} \breaklabel} - \usepackage{amsmath} - \usepackage{amsfonts} - \usepackage{amssymb} - \usepackage{txfonts} - % The enumitem package provides unlimited nesting of lists and % enums. Sphinx may use this in the future, in which case this can % be removed. See @@ -371,13 +378,6 @@ def _check_dependencies(): numpydoc_show_class_members = False -latex_engine = 'xelatex' # or 'lualatex' - -latex_elements = { - 'babel': r'\usepackage{babel}', - 'fontpkg': r'\setmainfont{DejaVu Serif}', -} - html4_writer = True inheritance_node_attrs = dict(fontsize=16) From 25ce38c53a8b14c003d51de20b661b748ad2d99e Mon Sep 17 00:00:00 2001 From: jfbu Date: Thu, 5 Dec 2019 10:19:06 +0100 Subject: [PATCH 32/50] LaTeX: resolve "Too deeply nested" error without enumitem package But removing enumitem package reveals a bug in expdlist. Import the fix from the SciPy and NumPy projects. https://github.com/numpy/numpy/pull/15028 https://github.com/scipy/scipy/commit/c881fdea7a7ef7c518b7898cfd53b2880af06778 --- doc/conf.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 768dbd75700e..174c8935761b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -338,20 +338,31 @@ def _check_dependencies(): % One line per author on title page \DeclareRobustCommand{\and}% {\end{tabular}\kern-\tabcolsep\\\begin{tabular}[t]{c}}% - % In the parameters section, place a newline after the Parameters - % header. (This is stolen directly from Numpy's conf.py, since it - % affects Numpy-style docstrings). \usepackage{expdlist} \let\latexdescription=\description \def\description{\latexdescription{}{} \breaklabel} - - % The enumitem package provides unlimited nesting of lists and - % enums. Sphinx may use this in the future, in which case this can - % be removed. See - % https://bitbucket.org/birkenfeld/sphinx/issue/777/latex-output-too-deeply-nested - \usepackage{enumitem} - \setlistdepth{2048} + % But expdlist old LaTeX package requires fixes: + % 1) remove extra space + \usepackage{etoolbox} + \makeatletter + \patchcmd\@item{{\@breaklabel} }{{\@breaklabel}}{}{} + \makeatother + % 2) fix bug in expdlist's way of breaking the line after long item label + \makeatletter + \def\breaklabel{% + \def\@breaklabel{% + \leavevmode\par + % now a hack because Sphinx inserts \leavevmode after term node + \def\leavevmode{\def\leavevmode{\unhbox\voidb@x}}% + }% + } + \makeatother """ +# Sphinx 1.5 provides this to avoid "too deeply nested" LaTeX error +# and usage of "enumitem" LaTeX package is unneeded. +# Value can be increased but do not set it to something such as 2048 +# which needlessly would trigger creation of thousands of TeX macros +latex_elements['maxlistdepth'] = '10' latex_elements['pointsize'] = '11pt' # Documents to append as an appendix to all manuals. From 8d5a575337a7752343de175f1f53cc6c7e53d69d Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 13 Nov 2020 00:35:56 -0500 Subject: [PATCH 33/50] Add missing dimension in genfrac LaTeX example. This appears unnecessary in mathtext, but LaTeX requires the dimension. --- tutorials/text/mathtext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/text/mathtext.py b/tutorials/text/mathtext.py index 709f1df4956b..655ceec6bbf1 100644 --- a/tutorials/text/mathtext.py +++ b/tutorials/text/mathtext.py @@ -97,7 +97,7 @@ .. math:: - \frac{3}{4} \binom{3}{4} \genfrac{}{}{0}{}{3}{4} + \frac{3}{4} \binom{3}{4} \genfrac{}{}{0pt}{}{3}{4} Fractions can be arbitrarily nested:: From dd88dfe3c002e7f77c3ddb418269759ad0c858e7 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 16 Dec 2020 20:16:11 -0500 Subject: [PATCH 34/50] Backport PR #19002: DOC: Add note about locators at top of ticker docs --- lib/matplotlib/ticker.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 67931617423f..749d5d99eaec 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -81,6 +81,19 @@ The default minor locator is `NullLocator`, i.e., no minor ticks on by default. +.. note:: + `Locator` instances should not be used with more than one + `~matplotlib.axis.Axis` or `~matplotlib.axes.Axes`. So instead of:: + + locator = MultipleLocator(5) + ax.xaxis.set_major_locator(locator) + ax2.xaxis.set_major_locator(locator) + + do the following instead:: + + ax.xaxis.set_major_locator(MultipleLocator(5)) + ax2.xaxis.set_major_locator(MultipleLocator(5)) + Tick formatting --------------- From 1c9518b14d560cec4624132e68b6cfa1020424dd Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 8 Oct 2020 21:53:04 +0200 Subject: [PATCH 35/50] Merge pull request #18679 from anntzer/pgftmpdir Further simplify pgf tmpdir cleanup. Backports #18679 but drops the deprecation steps. --- lib/matplotlib/backends/backend_pgf.py | 67 +++++++++----------------- 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 8da4abca6bba..55e1b44b8501 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -11,6 +11,7 @@ import subprocess import sys import tempfile +from tempfile import TemporaryDirectory import weakref from PIL import Image @@ -208,7 +209,6 @@ class LatexManager: determining the metrics of text elements. The LaTeX environment can be modified by setting fonts and/or a custom preamble in `.rcParams`. """ - _unclean_instances = weakref.WeakSet() @staticmethod def _build_latex_header(): @@ -245,12 +245,6 @@ def _get_cached_or_new(cls): def _get_cached_or_new_impl(cls, header): # Helper for _get_cached_or_new. return cls() - @staticmethod - def _cleanup_remaining_instances(): - unclean_instances = list(LatexManager._unclean_instances) - for latex_manager in unclean_instances: - latex_manager._cleanup() - def _stdin_writeln(self, s): if self.latex is None: self._setup_latex_process() @@ -276,13 +270,10 @@ def _expect_prompt(self): return self._expect("\n*") def __init__(self): - # store references for __del__ - self._os_path = os.path - self._shutil = shutil - - # create a tmp directory for running latex, remember to cleanup - self.tmpdir = tempfile.mkdtemp(prefix="mpl_pgf_lm_") - LatexManager._unclean_instances.add(self) + # create a tmp directory for running latex, register it for deletion + self._tmpdir = TemporaryDirectory() + self.tmpdir = self._tmpdir.name + self._finalize_tmpdir = weakref.finalize(self, self._tmpdir.cleanup) # test the LaTeX setup to ensure a clean startup of the subprocess self.texcommand = mpl.rcParams["pgf.texsystem"] @@ -311,11 +302,21 @@ def __init__(self): self.str_cache = {} # cache for strings already processed def _setup_latex_process(self): - # open LaTeX process for real work + # Open LaTeX process for real work; register it for deletion. On + # Windows, we must ensure that the subprocess has quit before being + # able to delete the tmpdir in which it runs; in order to do so, we + # must first `kill()` it, and then `communicate()` with it. self.latex = subprocess.Popen( [self.texcommand, "-halt-on-error"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, encoding="utf-8", cwd=self.tmpdir) + + def finalize_latex(latex): + latex.kill() + latex.communicate() + + self._finalize_latex = weakref.finalize( + self, finalize_latex, self.latex) # write header with 'pgf_backend_query_start' token self._stdin_writeln(self._build_latex_header()) # read all lines until our 'pgf_backend_query_start' token appears @@ -326,23 +327,6 @@ def _setup_latex_process(self): def latex_stdin_utf8(self): return self.latex.stdin - def _cleanup(self): - if not self._os_path.isdir(self.tmpdir): - return - try: - self.latex.communicate() - except Exception: - pass - try: - self._shutil.rmtree(self.tmpdir) - LatexManager._unclean_instances.discard(self) - except Exception: - sys.stderr.write("error deleting tmp directory %s\n" % self.tmpdir) - - def __del__(self): - _log.debug("deleting LatexManager") - self._cleanup() - def get_width_height_descent(self, text, prop): """ Get the width, total height and descent for a text typeset by the @@ -779,15 +763,20 @@ class GraphicsContextPgf(GraphicsContextBase): class TmpDirCleaner: - remaining_tmpdirs = set() + _remaining_tmpdirs = set() + + @cbook._classproperty + def remaining_tmpdirs(cls): + return cls._remaining_tmpdirs @staticmethod def add(tmpdir): - TmpDirCleaner.remaining_tmpdirs.add(tmpdir) + TmpDirCleaner._remaining_tmpdirs.add(tmpdir) @staticmethod + @atexit.register def cleanup_remaining_tmpdirs(): - for tmpdir in TmpDirCleaner.remaining_tmpdirs: + for tmpdir in TmpDirCleaner._remaining_tmpdirs: error_message = "error deleting tmp directory {}".format(tmpdir) shutil.rmtree( tmpdir, @@ -979,14 +968,6 @@ class _BackendPgf(_Backend): FigureCanvas = FigureCanvasPgf -def _cleanup_all(): - LatexManager._cleanup_remaining_instances() - TmpDirCleaner.cleanup_remaining_tmpdirs() - - -atexit.register(_cleanup_all) - - class PdfPages: """ A multi-page PDF file using the pgf backend From b3ad2b9535bff52b4bb18585aedf3668b7fb4401 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 21 Dec 2020 21:44:02 -0500 Subject: [PATCH 36/50] MNT: backout a deprecation related rename --- lib/matplotlib/backends/backend_pgf.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 55e1b44b8501..fc30e6a7b909 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -763,20 +763,16 @@ class GraphicsContextPgf(GraphicsContextBase): class TmpDirCleaner: - _remaining_tmpdirs = set() - - @cbook._classproperty - def remaining_tmpdirs(cls): - return cls._remaining_tmpdirs + remaining_tmpdirs = set() @staticmethod def add(tmpdir): - TmpDirCleaner._remaining_tmpdirs.add(tmpdir) + TmpDirCleaner.remaining_tmpdirs.add(tmpdir) @staticmethod @atexit.register def cleanup_remaining_tmpdirs(): - for tmpdir in TmpDirCleaner._remaining_tmpdirs: + for tmpdir in TmpDirCleaner.remaining_tmpdirs: error_message = "error deleting tmp directory {}".format(tmpdir) shutil.rmtree( tmpdir, From 7b31a0eb1ebb3531553609bc7ff39a197f22fe8a Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Tue, 22 Dec 2020 10:42:45 +0100 Subject: [PATCH 37/50] Backport PR #19163: Ignore missing _FancyAxislineStyle doc targets. --- doc/missing-references.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/missing-references.json b/doc/missing-references.json index 77244902b2f1..47ca99fe8137 100644 --- a/doc/missing-references.json +++ b/doc/missing-references.json @@ -397,6 +397,12 @@ "mpl_toolkits.axisartist.axisline_style.AxislineStyle._Base": [ "lib/mpl_toolkits/axisartist/axisline_style.py:docstring of mpl_toolkits.axisartist.axisline_style.AxislineStyle.SimpleArrow:1" ], + "mpl_toolkits.axisartist.axisline_style._FancyAxislineStyle.FilledArrow": [ + ":1" + ], + "mpl_toolkits.axisartist.axisline_style._FancyAxislineStyle.SimpleArrow": [ + ":1" + ], "mpl_toolkits.axisartist.axislines.AxisArtistHelper._Base": [ "lib/mpl_toolkits/axisartist/axislines.py:docstring of mpl_toolkits.axisartist.axislines.AxisArtistHelper.Fixed:1", "lib/mpl_toolkits/axisartist/axislines.py:docstring of mpl_toolkits.axisartist.axislines.AxisArtistHelper.Floating:1" From df7f639ad447449ec98c405d6afdbe87760281dd Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 17 Dec 2020 10:03:43 -0500 Subject: [PATCH 38/50] Backport PR #19131: Fix WebAgg initialization --- lib/matplotlib/backends/web_backend/js/mpl.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/matplotlib/backends/web_backend/js/mpl.js b/lib/matplotlib/backends/web_backend/js/mpl.js index a3a8f7abc54b..5d27a5835942 100644 --- a/lib/matplotlib/backends/web_backend/js/mpl.js +++ b/lib/matplotlib/backends/web_backend/js/mpl.js @@ -157,9 +157,6 @@ mpl.figure.prototype._init_canvas = function () { 1; this.ratio = (window.devicePixelRatio || 1) / backingStore; - if (this.ratio !== 1) { - fig.send_message('set_dpi_ratio', { dpi_ratio: this.ratio }); - } var rubberband_canvas = (this.rubberband_canvas = document.createElement( 'canvas' @@ -227,7 +224,7 @@ mpl.figure.prototype._init_canvas = function () { // And update the size in Python. We ignore the initial 0/0 size // that occurs as the element is placed into the DOM, which should // otherwise not happen due to the minimum size styling. - if (width != 0 && height != 0) { + if (fig.ws.readyState == 1 && width != 0 && height != 0) { fig.request_resize(width, height); } } From 51351f7003d7c2883d39339d8e09ec41ab837b4f Mon Sep 17 00:00:00 2001 From: Mark Harfouche Date: Wed, 6 Jan 2021 21:12:06 -0500 Subject: [PATCH 39/50] Backport PR #19245: handle usecase where QT_API is specified with some capitals --- lib/matplotlib/backends/qt_compat.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/backends/qt_compat.py b/lib/matplotlib/backends/qt_compat.py index e2c6e1f44215..39f8050e70e3 100644 --- a/lib/matplotlib/backends/qt_compat.py +++ b/lib/matplotlib/backends/qt_compat.py @@ -26,6 +26,8 @@ QT_API_PYSIDE = "PySide" QT_API_PYQT = "PyQt4" # Use the old sip v1 API (Py3 defaults to v2). QT_API_ENV = os.environ.get("QT_API") +if QT_API_ENV is not None: + QT_API_ENV = QT_API_ENV.lower() # Mapping of QT_API_ENV to requested binding. ETS does not support PyQt4v1. # (https://github.com/enthought/pyface/blob/master/pyface/qt/__init__.py) _ETS = {"pyqt5": QT_API_PYQT5, "pyside2": QT_API_PYSIDE2, From 5dc874e8dd643f1279cbd5345e9b285bb895a0f0 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sat, 9 Jan 2021 09:32:21 -0800 Subject: [PATCH 40/50] Backport PR #19266: Don't update homebrew on GitHub Actions --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 255301842385..132bd70949d5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,6 +18,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: include: - name-suffix: "(Minimum Versions)" @@ -90,7 +91,6 @@ jobs: ttf-wqy-zenhei ;; macOS) - brew update brew install ccache ;; esac From 6b93fbd17860f35b942636031dc73471c744b2eb Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Tue, 22 Dec 2020 10:42:45 +0100 Subject: [PATCH 41/50] Backport PR #19163: Ignore missing _FancyAxislineStyle doc targets. --- doc/missing-references.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/missing-references.json b/doc/missing-references.json index 77244902b2f1..47ca99fe8137 100644 --- a/doc/missing-references.json +++ b/doc/missing-references.json @@ -397,6 +397,12 @@ "mpl_toolkits.axisartist.axisline_style.AxislineStyle._Base": [ "lib/mpl_toolkits/axisartist/axisline_style.py:docstring of mpl_toolkits.axisartist.axisline_style.AxislineStyle.SimpleArrow:1" ], + "mpl_toolkits.axisartist.axisline_style._FancyAxislineStyle.FilledArrow": [ + ":1" + ], + "mpl_toolkits.axisartist.axisline_style._FancyAxislineStyle.SimpleArrow": [ + ":1" + ], "mpl_toolkits.axisartist.axislines.AxisArtistHelper._Base": [ "lib/mpl_toolkits/axisartist/axislines.py:docstring of mpl_toolkits.axisartist.axislines.AxisArtistHelper.Fixed:1", "lib/mpl_toolkits/axisartist/axislines.py:docstring of mpl_toolkits.axisartist.axislines.AxisArtistHelper.Floating:1" From 6c38462c814ada3be61f7e955fe4a0b9e4cbb9d9 Mon Sep 17 00:00:00 2001 From: hannah Date: Tue, 12 Jan 2021 01:30:24 -0500 Subject: [PATCH 42/50] Backport PR #19279: Fix sphinx search --- doc/_templates/search.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/_templates/search.html b/doc/_templates/search.html index 54f1d3338e0c..6e285090cc40 100644 --- a/doc/_templates/search.html +++ b/doc/_templates/search.html @@ -3,6 +3,7 @@ {%- block scripts %} {{ super() }} + {%- endblock %} {% block body %}

{{ _('Search') }}

From be3be0429db0393f92e987fcbd806737ecd28a60 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 14 Jan 2021 19:45:44 -0500 Subject: [PATCH 43/50] Backport PR #19301: Fix several CI issues --- .appveyor.yml | 1 + azure-pipelines.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 668c5391de65..4321e1806dcb 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -18,6 +18,7 @@ environment: PYTHONIOENCODING: UTF-8 PYTEST_ARGS: -raR --numprocesses=auto --timeout=300 --durations=25 --cov-report= --cov=lib --log-level=DEBUG + PINNEDVERS: "pyzmq!=21.0.0" matrix: # In theory we could use a single CONDA_INSTALL_LOCN because we construct diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 91e510d27b52..e9af9c73850b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -81,7 +81,7 @@ steps: texlive-xetex texlive-luatex ;; darwin) - brew cask install xquartz + brew install --cask xquartz brew install pkg-config ffmpeg imagemagick mplayer ccache ;; win32) From 638165699d98a6c74f27c94df62a8a799ba5d859 Mon Sep 17 00:00:00 2001 From: David Stansby Date: Wed, 27 Jan 2021 14:37:35 +0000 Subject: [PATCH 44/50] Backport PR #19371: Fix specgram test on NumPy 1.20. --- lib/matplotlib/tests/test_axes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 57beec025aa8..e0b340da1ee8 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -4152,7 +4152,7 @@ def test_specgram_angle(): def test_specgram_fs_none(): """Test axes.specgram when Fs is None, should not throw error.""" - spec, freqs, t, im = plt.specgram(np.ones(300), Fs=None) + spec, freqs, t, im = plt.specgram(np.ones(300), Fs=None, scale='linear') xmin, xmax, freq0, freq1 = im.get_extent() assert xmin == 32 and xmax == 96 From 491c95773ff7091ef176a2050fcab251d0cc7361 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 16 Dec 2020 14:44:23 -0500 Subject: [PATCH 45/50] Backport PR #19052: Always pass integers to wx.Size. --- lib/matplotlib/backends/backend_wx.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 0b94f2116ada..9711e65e17aa 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -922,7 +922,8 @@ def __init__(self, num, fig): _set_frame_icon(self) self.canvas = self.get_canvas(fig) - self.canvas.SetInitialSize(wx.Size(fig.bbox.width, fig.bbox.height)) + w, h = map(math.ceil, fig.bbox.size) + self.canvas.SetInitialSize(wx.Size(w, h)) self.canvas.SetFocus() self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND) @@ -1070,7 +1071,8 @@ def set_window_title(self, title): def resize(self, width, height): # docstring inherited - self.canvas.SetInitialSize(wx.Size(width, height)) + self.canvas.SetInitialSize( + wx.Size(math.ceil(width), math.ceil(height))) self.window.GetSizer().Fit(self.window) From 81305b4d1e9accbf3deafd8e127fefc467cfc99d Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 27 Jan 2021 21:01:42 -0500 Subject: [PATCH 46/50] Backport PR #19238: Fix build with LTO disabled in environment --- .github/workflows/tests.yml | 1 + setup.py | 38 +++++++++++++++++++++++++------------ setupext.py | 1 - src/_tkagg.cpp | 8 +++++++- src/py_converters.cpp | 7 ------- src/py_converters.h | 1 - 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 132bd70949d5..253f0e8f9fb0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,6 +31,7 @@ jobs: python-version: 3.7 extra-requirements: '-r requirements/testing/travis_extra.txt' XVFB_RUN: xvfb-run -a + CFLAGS: "-fno-lto" # Ensure that disabling LTO works. - os: ubuntu-16.04 python-version: 3.8 extra-requirements: '-r requirements/testing/travis_extra.txt' diff --git a/setup.py b/setup.py index 6e1d19d4b85c..56bf9de2c71e 100644 --- a/setup.py +++ b/setup.py @@ -103,20 +103,34 @@ def add_optimization_flags(self): """ env = os.environ.copy() - if not setupext.config.getboolean('libs', 'enable_lto', fallback=True): - return env if sys.platform == 'win32': return env - - cppflags = [] - if 'CPPFLAGS' in os.environ: - cppflags.append(os.environ['CPPFLAGS']) - cxxflags = [] - if 'CXXFLAGS' in os.environ: - cxxflags.append(os.environ['CXXFLAGS']) - ldflags = [] - if 'LDFLAGS' in os.environ: - ldflags.append(os.environ['LDFLAGS']) + enable_lto = setupext.config.getboolean('libs', 'enable_lto', + fallback=None) + + def prepare_flags(name, enable_lto): + """ + Prepare *FLAGS from the environment. + + If set, return them, and also check whether LTO is disabled in each + one, raising an error if Matplotlib config explicitly enabled LTO. + """ + if name in os.environ: + if '-fno-lto' in os.environ[name]: + if enable_lto is True: + raise ValueError('Configuration enable_lto=True, but ' + '{0} contains -fno-lto'.format(name)) + enable_lto = False + return [os.environ[name]], enable_lto + return [], enable_lto + + _, enable_lto = prepare_flags('CFLAGS', enable_lto) # Only check lto. + cppflags, enable_lto = prepare_flags('CPPFLAGS', enable_lto) + cxxflags, enable_lto = prepare_flags('CXXFLAGS', enable_lto) + ldflags, enable_lto = prepare_flags('LDFLAGS', enable_lto) + + if enable_lto is False: + return env if has_flag(self.compiler, '-fvisibility=hidden'): for ext in self.extensions: diff --git a/setupext.py b/setupext.py index fda44ed7db3b..dfa004d7f09e 100644 --- a/setupext.py +++ b/setupext.py @@ -399,7 +399,6 @@ def get_extensions(self): ext = Extension( "matplotlib.backends._tkagg", [ "src/_tkagg.cpp", - "src/py_converters.cpp", ], include_dirs=["src"], # psapi library needed for finding Tcl/Tk at run time. diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index b87d118a7167..68907d0d6d16 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -37,7 +37,13 @@ // Include our own excerpts from the Tcl / Tk headers #include "_tkmini.h" -#include "py_converters.h" + +static int convert_voidptr(PyObject *obj, void *p) +{ + void **val = (void **)p; + *val = PyLong_AsVoidPtr(obj); + return *val != NULL ? 1 : !PyErr_Occurred(); +} // Global vars for Tk functions. We load these symbols from the tkinter // extension module or loaded Tk libraries at run-time. diff --git a/src/py_converters.cpp b/src/py_converters.cpp index ace8332dda76..a4c0b1909940 100644 --- a/src/py_converters.cpp +++ b/src/py_converters.cpp @@ -94,13 +94,6 @@ int convert_from_attr(PyObject *obj, const char *name, converter func, void *p) return 1; } -int convert_voidptr(PyObject *obj, void *p) -{ - void **val = (void **)p; - *val = PyLong_AsVoidPtr(obj); - return *val != NULL ? 1 : !PyErr_Occurred(); -} - int convert_double(PyObject *obj, void *p) { double *val = (double *)p; diff --git a/src/py_converters.h b/src/py_converters.h index 33af43a474e8..2c19acdaaf80 100644 --- a/src/py_converters.h +++ b/src/py_converters.h @@ -22,7 +22,6 @@ typedef int (*converter)(PyObject *, void *); int convert_from_attr(PyObject *obj, const char *name, converter func, void *p); int convert_from_method(PyObject *obj, const char *name, converter func, void *p); -int convert_voidptr(PyObject *obj, void *p); int convert_double(PyObject *obj, void *p); int convert_bool(PyObject *obj, void *p); int convert_cap(PyObject *capobj, void *capp); From 6adafceb03ccadbdb77c921bd4dd0ebe3615269f Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 28 Jan 2021 01:52:14 -0500 Subject: [PATCH 47/50] DOC: Update GitHub stats for 3.3.3. --- doc/users/github_stats.rst | 106 ++++++------------ .../prev_whats_new/github_stats_3.3.3.rst | 93 +++++++++++++++ 2 files changed, 125 insertions(+), 74 deletions(-) create mode 100644 doc/users/prev_whats_new/github_stats_3.3.3.rst diff --git a/doc/users/github_stats.rst b/doc/users/github_stats.rst index ab8f8384b8aa..739ca5c5eb36 100644 --- a/doc/users/github_stats.rst +++ b/doc/users/github_stats.rst @@ -3,94 +3,52 @@ GitHub Stats ============ -GitHub stats for 2020/09/15 - 2020/11/11 (tag: v3.3.2) +GitHub stats for 2020/11/12 - 2021/01/28 (tag: v3.3.3) These lists are automatically generated, and may be incomplete or contain duplicates. -We closed 14 issues and merged 46 pull requests. -The full list can be seen `on GitHub `__ +We closed 2 issues and merged 20 pull requests. +The full list can be seen `on GitHub `__ -The following 11 authors contributed 73 commits. +The following 7 authors contributed 43 commits. * Antony Lee * David Stansby * Elliott Sales de Andrade -* Eric Larson * Jody Klymak -* Jouni K. Seppänen -* Ryan May -* shevawen -* Stephen Sinclair +* Mark Harfouche * Thomas A Caswell * Tim Hoffmann GitHub issues and pull requests: -Pull Requests (46): - -* :ghpull:`18936`: Backport PR #18929 on branch v3.3.x -* :ghpull:`18929`: FIX: make sure scalarmappable updates are handled correctly in 3D -* :ghpull:`18928`: Backport PR #18842 on branch v3.3.x (Add CPython 3.9 wheels.) -* :ghpull:`18842`: Add CPython 3.9 wheels. -* :ghpull:`18921`: Backport PR #18732 on branch v3.3.x (Add a ponyfill for ResizeObserver on older browsers.) -* :ghpull:`18732`: Add a ponyfill for ResizeObserver on older browsers. -* :ghpull:`18886`: Backport #18860 on branch v3.3.x -* :ghpull:`18860`: FIX: stop deprecation message colorbar -* :ghpull:`18845`: Backport PR #18839 on branch v3.3.x -* :ghpull:`18843`: Backport PR #18756 on branch v3.3.x (FIX: improve date performance regression) -* :ghpull:`18850`: Backport CI fixes to v3.3.x -* :ghpull:`18839`: MNT: make sure we do not mutate input in Text.update -* :ghpull:`18838`: Fix ax.set_xticklabels(fontproperties=fp) -* :ghpull:`18756`: FIX: improve date performance regression -* :ghpull:`18787`: Backport PR #18769 on branch v3.3.x -* :ghpull:`18786`: Backport PR #18754 on branch v3.3.x (FIX: make sure we have more than 1 tick with small log ranges) -* :ghpull:`18754`: FIX: make sure we have more than 1 tick with small log ranges -* :ghpull:`18769`: Support ``ax.grid(visible=)``. -* :ghpull:`18778`: Backport PR #18773 on branch v3.3.x (Update to latest cibuildwheel release.) -* :ghpull:`18773`: Update to latest cibuildwheel release. -* :ghpull:`18755`: Backport PR #18734 on branch v3.3.x (Fix deprecation warning in GitHub Actions.) -* :ghpull:`18734`: Fix deprecation warning in GitHub Actions. -* :ghpull:`18725`: Backport PR #18533 on branch v3.3.x -* :ghpull:`18723`: Backport PR #18584 on branch v3.3.x (Fix setting 0-timeout timer with Tornado.) -* :ghpull:`18676`: Backport PR #18670 on branch v3.3.x (MNT: make certifi actually optional) -* :ghpull:`18670`: MNT: make certifi actually optional -* :ghpull:`18665`: Backport PR #18639 on branch v3.3.x (nbagg: Don't close figures for bubbled events.) -* :ghpull:`18639`: nbagg: Don't close figures for bubbled events. -* :ghpull:`18640`: Backport PR #18636 on branch v3.3.x (BLD: certifi is not a run-time dependency) -* :ghpull:`18636`: BLD: certifi is not a run-time dependency -* :ghpull:`18629`: Backport PR #18621 on branch v3.3.x (Fix singleshot timers in wx.) -* :ghpull:`18621`: Fix singleshot timers in wx. -* :ghpull:`18607`: Backport PR #18604 on branch v3.3.x (Update test image to fix Ghostscript 9.53.) -* :ghpull:`18604`: Update test image to fix Ghostscript 9.53. -* :ghpull:`18584`: Fix setting 0-timeout timer with Tornado. -* :ghpull:`18550`: backport pr 18549 -* :ghpull:`18545`: Backport PR #18540 on branch v3.3.x (Call to ExitStack.push should have been ExitStack.callback.) -* :ghpull:`18549`: FIX: unit-convert pcolorargs before interpolating -* :ghpull:`18540`: Call to ExitStack.push should have been ExitStack.callback. -* :ghpull:`18533`: Correctly remove support for \stackrel. -* :ghpull:`18509`: Backport PR #18505 on branch v3.3.x (Fix depth shading when edge/facecolor is none.) -* :ghpull:`18505`: Fix depth shading when edge/facecolor is none. -* :ghpull:`18504`: Backport PR #18500 on branch v3.3.x (BUG: Fix all-masked imshow) -* :ghpull:`18500`: BUG: Fix all-masked imshow -* :ghpull:`18476`: CI: skip qt, cairo, pygobject related installs on OSX on travis -* :ghpull:`18134`: Build on xcode9 - -Issues (14): - -* :ghissue:`18885`: 3D Scatter Plot with Colorbar is not saved correctly with savefig -* :ghissue:`18922`: pyplot.xticks(): Font property specification is not effective except 1st tick label. -* :ghissue:`18481`: "%matplotlib notebook" not working in firefox with matplotlib 3.3.1 -* :ghissue:`18595`: Getting internal "MatplotlibDeprecationWarning: shading='flat' ..." -* :ghissue:`18743`: from mpl 3.2.2 to 3.3.0 enormous increase in creation time -* :ghissue:`18317`: pcolormesh: shading='nearest' and non-monotonic coordinates -* :ghissue:`18758`: Using Axis.grid(visible=True) results in TypeError for multiple values for keyword argument -* :ghissue:`18638`: ``matplotlib>=3.3.2`` breaks ``ipywidgets.interact`` -* :ghissue:`18337`: Error installing matplotlib-3.3.1 using pip due to old version of certifi on conda environment -* :ghissue:`18620`: wx backend assertion error with fig.canvas.timer.start() -* :ghissue:`18551`: test_transparent_markers[pdf] is broken on v3.3.x Travis macOS -* :ghissue:`18580`: Animation freezes in Jupyter notebook -* :ghissue:`18547`: pcolormesh x-axis with datetime broken for nearest shading -* :ghissue:`18539`: Error in Axes.redraw_in_frame in use of ExitStack: push() takes 2 positional arguments but 3 were given +Pull Requests (20): + +* :ghpull:`19386`: Backport PR #19238 on branch v3.3.x (Fix build with LTO disabled in environment) +* :ghpull:`19238`: Fix build with LTO disabled in environment +* :ghpull:`19382`: Backport PR #19052 on branch v3.3.x (Always pass integers to wx.Size.) +* :ghpull:`19377`: Backport PR #19371 on branch v3.3.x (Fix specgram test on NumPy 1.20.) +* :ghpull:`19371`: Fix specgram test on NumPy 1.20. +* :ghpull:`19305`: Backport PR #19301 on branch v3.3.x +* :ghpull:`19301`: Fix several CI issues +* :ghpull:`19269`: Backport PR #19266 on branch v3.3.x (Don't update homebrew on GitHub Actions) +* :ghpull:`19266`: Don't update homebrew on GitHub Actions +* :ghpull:`19252`: Backport PR #19245 on branch v3.3.x (handle usecase where QT_API is specified with some capitals) +* :ghpull:`19245`: handle usecase where QT_API is specified with some capitals +* :ghpull:`19143`: Backport PR #19131 on branch v3.3.x (Fix WebAgg initialization) +* :ghpull:`19115`: Backport PR #19108 on branch v3.3.x +* :ghpull:`19165`: Backport PR #19163 on branch v3.3.x (Ignore missing _FancyAxislineStyle doc targets.) +* :ghpull:`19163`: Ignore missing _FancyAxislineStyle doc targets. +* :ghpull:`19131`: Fix WebAgg initialization +* :ghpull:`19052`: Always pass integers to wx.Size. +* :ghpull:`19108`: Fix failing animation test with pytest 6.2. +* :ghpull:`19062`: Backport PR #19036 on branch v3.3.x +* :ghpull:`19036`: Start testing using GitHub Actions + +Issues (2): + +* :ghissue:`19227`: Matplotlib generates invalid ft2font if -fno-lto gcc CFLAGS used +* :ghissue:`19129`: webAgg example broken - maybe mpl.js broken? Previous GitHub Stats diff --git a/doc/users/prev_whats_new/github_stats_3.3.3.rst b/doc/users/prev_whats_new/github_stats_3.3.3.rst new file mode 100644 index 000000000000..d7ba592d7339 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.3.3.rst @@ -0,0 +1,93 @@ +.. _github-stats-3-3-3: + +GitHub Stats for Matplotlib 3.3.3 +================================= + +GitHub stats for 2020/09/15 - 2020/11/11 (tag: v3.3.2) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 14 issues and merged 46 pull requests. +The full list can be seen `on GitHub `__ + +The following 11 authors contributed 73 commits. + +* Antony Lee +* David Stansby +* Elliott Sales de Andrade +* Eric Larson +* Jody Klymak +* Jouni K. Seppänen +* Ryan May +* shevawen +* Stephen Sinclair +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (46): + +* :ghpull:`18936`: Backport PR #18929 on branch v3.3.x +* :ghpull:`18929`: FIX: make sure scalarmappable updates are handled correctly in 3D +* :ghpull:`18928`: Backport PR #18842 on branch v3.3.x (Add CPython 3.9 wheels.) +* :ghpull:`18842`: Add CPython 3.9 wheels. +* :ghpull:`18921`: Backport PR #18732 on branch v3.3.x (Add a ponyfill for ResizeObserver on older browsers.) +* :ghpull:`18732`: Add a ponyfill for ResizeObserver on older browsers. +* :ghpull:`18886`: Backport #18860 on branch v3.3.x +* :ghpull:`18860`: FIX: stop deprecation message colorbar +* :ghpull:`18845`: Backport PR #18839 on branch v3.3.x +* :ghpull:`18843`: Backport PR #18756 on branch v3.3.x (FIX: improve date performance regression) +* :ghpull:`18850`: Backport CI fixes to v3.3.x +* :ghpull:`18839`: MNT: make sure we do not mutate input in Text.update +* :ghpull:`18838`: Fix ax.set_xticklabels(fontproperties=fp) +* :ghpull:`18756`: FIX: improve date performance regression +* :ghpull:`18787`: Backport PR #18769 on branch v3.3.x +* :ghpull:`18786`: Backport PR #18754 on branch v3.3.x (FIX: make sure we have more than 1 tick with small log ranges) +* :ghpull:`18754`: FIX: make sure we have more than 1 tick with small log ranges +* :ghpull:`18769`: Support ``ax.grid(visible=)``. +* :ghpull:`18778`: Backport PR #18773 on branch v3.3.x (Update to latest cibuildwheel release.) +* :ghpull:`18773`: Update to latest cibuildwheel release. +* :ghpull:`18755`: Backport PR #18734 on branch v3.3.x (Fix deprecation warning in GitHub Actions.) +* :ghpull:`18734`: Fix deprecation warning in GitHub Actions. +* :ghpull:`18725`: Backport PR #18533 on branch v3.3.x +* :ghpull:`18723`: Backport PR #18584 on branch v3.3.x (Fix setting 0-timeout timer with Tornado.) +* :ghpull:`18676`: Backport PR #18670 on branch v3.3.x (MNT: make certifi actually optional) +* :ghpull:`18670`: MNT: make certifi actually optional +* :ghpull:`18665`: Backport PR #18639 on branch v3.3.x (nbagg: Don't close figures for bubbled events.) +* :ghpull:`18639`: nbagg: Don't close figures for bubbled events. +* :ghpull:`18640`: Backport PR #18636 on branch v3.3.x (BLD: certifi is not a run-time dependency) +* :ghpull:`18636`: BLD: certifi is not a run-time dependency +* :ghpull:`18629`: Backport PR #18621 on branch v3.3.x (Fix singleshot timers in wx.) +* :ghpull:`18621`: Fix singleshot timers in wx. +* :ghpull:`18607`: Backport PR #18604 on branch v3.3.x (Update test image to fix Ghostscript 9.53.) +* :ghpull:`18604`: Update test image to fix Ghostscript 9.53. +* :ghpull:`18584`: Fix setting 0-timeout timer with Tornado. +* :ghpull:`18550`: backport pr 18549 +* :ghpull:`18545`: Backport PR #18540 on branch v3.3.x (Call to ExitStack.push should have been ExitStack.callback.) +* :ghpull:`18549`: FIX: unit-convert pcolorargs before interpolating +* :ghpull:`18540`: Call to ExitStack.push should have been ExitStack.callback. +* :ghpull:`18533`: Correctly remove support for \stackrel. +* :ghpull:`18509`: Backport PR #18505 on branch v3.3.x (Fix depth shading when edge/facecolor is none.) +* :ghpull:`18505`: Fix depth shading when edge/facecolor is none. +* :ghpull:`18504`: Backport PR #18500 on branch v3.3.x (BUG: Fix all-masked imshow) +* :ghpull:`18500`: BUG: Fix all-masked imshow +* :ghpull:`18476`: CI: skip qt, cairo, pygobject related installs on OSX on travis +* :ghpull:`18134`: Build on xcode9 + +Issues (14): + +* :ghissue:`18885`: 3D Scatter Plot with Colorbar is not saved correctly with savefig +* :ghissue:`18922`: pyplot.xticks(): Font property specification is not effective except 1st tick label. +* :ghissue:`18481`: "%matplotlib notebook" not working in firefox with matplotlib 3.3.1 +* :ghissue:`18595`: Getting internal "MatplotlibDeprecationWarning: shading='flat' ..." +* :ghissue:`18743`: from mpl 3.2.2 to 3.3.0 enormous increase in creation time +* :ghissue:`18317`: pcolormesh: shading='nearest' and non-monotonic coordinates +* :ghissue:`18758`: Using Axis.grid(visible=True) results in TypeError for multiple values for keyword argument +* :ghissue:`18638`: ``matplotlib>=3.3.2`` breaks ``ipywidgets.interact`` +* :ghissue:`18337`: Error installing matplotlib-3.3.1 using pip due to old version of certifi on conda environment +* :ghissue:`18620`: wx backend assertion error with fig.canvas.timer.start() +* :ghissue:`18551`: test_transparent_markers[pdf] is broken on v3.3.x Travis macOS +* :ghissue:`18580`: Animation freezes in Jupyter notebook +* :ghissue:`18547`: pcolormesh x-axis with datetime broken for nearest shading +* :ghissue:`18539`: Error in Axes.redraw_in_frame in use of ExitStack: push() takes 2 positional arguments but 3 were given From 396e8c72b132f9a659d6f86388da6b40275b9290 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 28 Jan 2021 02:20:18 -0500 Subject: [PATCH 48/50] REL: v3.3.4 This is the fourth bugfix release of the 3.3.x series. This release contains several critical bug-fixes: * Fix WebAgg initialization. * Fix parsing QT_API setting with mixed case. * Fix build with LTO disabled in environment. * Fix test compatibility with Python 3.10. * Fix test compatibility with NumPy 1.20. * Fix test compatibility with pytest 6.2. From 09c25b7da9fc32bd2db6d36d453617822c99c2fb Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 28 Jan 2021 02:29:15 -0500 Subject: [PATCH 49/50] BLD: bump branch away from tag So the tarballs from GitHub are stable. From 422e5374f04423bac416ec6c9b8afa2d619f5285 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 28 Jan 2021 03:58:21 -0500 Subject: [PATCH 50/50] DOC: Add Zenodo DOI for 3.3.4. --- doc/_static/zenodo_cache/4475376.svg | 35 ++++++++++++++++++++++++++++ doc/citing.rst | 3 +++ tools/cache_zenodo_svg.py | 1 + 3 files changed, 39 insertions(+) create mode 100644 doc/_static/zenodo_cache/4475376.svg diff --git a/doc/_static/zenodo_cache/4475376.svg b/doc/_static/zenodo_cache/4475376.svg new file mode 100644 index 000000000000..bf223b01ddc3 --- /dev/null +++ b/doc/_static/zenodo_cache/4475376.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4475376 + + + 10.5281/zenodo.4475376 + + + \ No newline at end of file diff --git a/doc/citing.rst b/doc/citing.rst index 2afc55d3fa20..2354f113e2e4 100644 --- a/doc/citing.rst +++ b/doc/citing.rst @@ -39,6 +39,9 @@ By version .. START OF AUTOGENERATED +v3.3.4 + .. image:: _static/zenodo_cache/4475376.svg + :target: https://doi.org/10.5281/zenodo.4475376 v3.3.3 .. image:: _static/zenodo_cache/4268928.svg :target: https://doi.org/10.5281/zenodo.4268928 diff --git a/tools/cache_zenodo_svg.py b/tools/cache_zenodo_svg.py index b2d36a2c87c3..6a334a3bbd1b 100644 --- a/tools/cache_zenodo_svg.py +++ b/tools/cache_zenodo_svg.py @@ -62,6 +62,7 @@ def _get_xdg_cache_dir(): if __name__ == "__main__": data = { + "v3.3.4": "4475376", "v3.3.3": "4268928", "v3.3.2": "4030140", "v3.3.1": "3984190",