diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 53cbbb6d9d..b5e2f8ea9b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,22 +15,17 @@ jobs: fail-fast: false matrix: os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] - python-version: [2.7, 3.6, 3.7] - exclude: - - os: windows-latest - python-version: 2.7 - - os: macos-latest - python-version: 3.7 + python-version: [3.6, 3.7, 3.8] timeout-minutes: 60 defaults: run: - shell: bash -l {0} + shell: bash -l {0} env: DESC: "Python ${{ matrix.python-version }} tests" HV_REQUIREMENTS: "unit_tests" PYTHON_VERSION: ${{ matrix.python-version }} - CHANS_DEV: "-c pyviz/label/dev -c bokeh/label/dev" - CHANS: "-c pyviz" + CHANS_DEV: "-c pyviz/label/dev -c bokeh/label/dev -c conda-forge" + CHANS: "-c pyviz -c conda-forge" MPLBACKEND: "Agg" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -43,6 +38,7 @@ jobs: - uses: conda-incubator/setup-miniconda@v2 with: miniconda-version: "latest" + channels: conda-forge,defaults - name: Fetch unshallow run: git fetch --prune --tags --unshallow - name: conda setup @@ -62,26 +58,6 @@ jobs: git describe echo "======" conda list - - name: bokeh update - if: startsWith(matrix.python-version, 3.) - run: | - eval "$(conda shell.bash hook)" - conda activate test-environment - conda install -c pyviz "bokeh>=2.3" "panel>=0.11" - - name: datashader pin - if: startsWith(matrix.python-version, 2.) - run: | - eval "$(conda shell.bash hook)" - conda activate test-environment - conda install -c pyviz "datashader=0.11.1" - - name: matplotlib patch - if: startsWith(matrix.python-version, 3.) - run: | - eval "$(conda shell.bash hook)" - conda activate test-environment - conda uninstall matplotlib matplotlib-base --force - conda install matplotlib=3.0.3 --no-deps - python -c "import matplotlib; print(matplotlib.__version__);" - name: doit env_capture run: | eval "$(conda shell.bash hook)" @@ -105,7 +81,6 @@ jobs: - name: run coveralls env: github-token: ${{ secrets.GITHUB_TOKEN }} - if: startsWith(matrix.python-version, 3.) run: | eval "$(conda shell.bash hook)" conda activate test-environment diff --git a/holoviews/plotting/mpl/chart.py b/holoviews/plotting/mpl/chart.py index 366e0c705d..bc85916290 100644 --- a/holoviews/plotting/mpl/chart.py +++ b/holoviews/plotting/mpl/chart.py @@ -133,15 +133,17 @@ def init_artists(self, ax, plot_data, plot_kwargs): _, (bottoms, tops), verts = handles return {'bottoms': bottoms, 'tops': tops, 'verts': verts[0], 'artist': verts[0]} - def get_data(self, element, ranges, style): with abbreviated_exception(): style = self._apply_transforms(element, ranges, style) - color = style.get('color') + color = style.pop('color', None) if isinstance(color, np.ndarray): style['ecolor'] = color if 'edgecolor' in style: style['ecolor'] = style.pop('edgecolor') + if 'linewidth' in style: + # Raise ValueError if a numpy array, so needs to be a list. + style["elinewidth"] = np.asarray(style.pop('linewidth')).tolist() c = style.get('c') if isinstance(c, np.ndarray): with abbreviated_exception(): @@ -193,8 +195,8 @@ def update_handles(self, key, axis, element, ranges, style): tops.set_ydata(tys) if 'ecolor' in style: verts.set_edgecolors(style['ecolor']) - if 'linewidth' in style: - verts.set_linewidths(style['linewidth']) + if 'elinewidth' in style: + verts.set_linewidths(style['elinewidth']) return axis_kwargs diff --git a/holoviews/tests/plotting/matplotlib/testcurveplot.py b/holoviews/tests/plotting/matplotlib/testcurveplot.py index 2a76860529..b6ceb8a825 100644 --- a/holoviews/tests/plotting/matplotlib/testcurveplot.py +++ b/holoviews/tests/plotting/matplotlib/testcurveplot.py @@ -19,20 +19,20 @@ def test_curve_datetime64(self): dates = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)] curve = Curve((dates, np.random.rand(10))) plot = mpl_renderer.get_plot(curve) - self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735973.0)) + self.assertEqual(plot.handles['axis'].get_xlim(), (16801.0, 16810.0)) @pd_skip def test_curve_pandas_timestamps(self): dates = pd.date_range('2016-01-01', '2016-01-10', freq='D') curve = Curve((dates, np.random.rand(10))) plot = mpl_renderer.get_plot(curve) - self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735973.0)) + self.assertEqual(plot.handles['axis'].get_xlim(), (16801.0, 16810.0)) def test_curve_dt_datetime(self): dates = [dt.datetime(2016,1,i) for i in range(1, 11)] curve = Curve((dates, np.random.rand(10))) plot = mpl_renderer.get_plot(curve) - self.assertEqual(tuple(map(round, plot.handles['axis'].get_xlim())), (735964.0, 735973.0)) + self.assertEqual(tuple(map(round, plot.handles['axis'].get_xlim())), (16801.0, 16810.0)) def test_curve_heterogeneous_datetime_types_overlay(self): dates64 = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)] @@ -40,7 +40,7 @@ def test_curve_heterogeneous_datetime_types_overlay(self): curve_dt64 = Curve((dates64, np.random.rand(10))) curve_dt = Curve((dates, np.random.rand(10))) plot = mpl_renderer.get_plot(curve_dt*curve_dt64) - self.assertEqual(tuple(map(round, plot.handles['axis'].get_xlim())), (735964.0, 735974.0)) + self.assertEqual(tuple(map(round, plot.handles['axis'].get_xlim())), (16801.0, 16811.0)) @pd_skip def test_curve_heterogeneous_datetime_types_with_pd_overlay(self): @@ -51,7 +51,7 @@ def test_curve_heterogeneous_datetime_types_with_pd_overlay(self): curve_dt = Curve((dates, np.random.rand(10))) curve_pd = Curve((dates_pd, np.random.rand(10))) plot = mpl_renderer.get_plot(curve_dt*curve_dt64*curve_pd) - self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735976.0)) + self.assertEqual(plot.handles['axis'].get_xlim(), (16801.0, 16813.0)) def test_curve_padding_square(self): curve = Curve([1, 2, 3]).options(padding=0.1) @@ -131,8 +131,8 @@ def test_curve_padding_datetime_square(self): ) plot = mpl_renderer.get_plot(curve) x_range, y_range = plot.handles['axis'].get_xlim(), plot.handles['axis'].get_ylim() - self.assertEqual(x_range[0], 736054.80000000005) - self.assertEqual(x_range[1], 736057.19999999995) + self.assertEqual(x_range[0], 16891.8) + self.assertEqual(x_range[1], 16894.2) self.assertEqual(y_range[0], 0.8) self.assertEqual(y_range[1], 3.2) @@ -142,8 +142,8 @@ def test_curve_padding_datetime_nonsquare(self): ) plot = mpl_renderer.get_plot(curve) x_range, y_range = plot.handles['axis'].get_xlim(), plot.handles['axis'].get_ylim() - self.assertEqual(x_range[0], 736054.90000000002) - self.assertEqual(x_range[1], 736057.09999999998) + self.assertEqual(x_range[0], 16891.9) + self.assertEqual(x_range[1], 16894.1) self.assertEqual(y_range[0], 0.8) self.assertEqual(y_range[1], 3.2) diff --git a/holoviews/tests/plotting/matplotlib/testgraphplot.py b/holoviews/tests/plotting/matplotlib/testgraphplot.py index 52e090711f..7a73af0415 100644 --- a/holoviews/tests/plotting/matplotlib/testgraphplot.py +++ b/holoviews/tests/plotting/matplotlib/testgraphplot.py @@ -200,11 +200,21 @@ def get_graph(i): self.assertEqual(artist.get_linewidths(), [12, 3, 5]) def test_graph_op_node_alpha(self): + import matplotlib as mpl + from packaging.version import Version + edges = [(0, 1), (0, 2)] nodes = Nodes([(0, 0, 0, 0.2), (0, 1, 1, 0.6), (1, 1, 2, 1)], vdims='alpha') graph = Graph((edges, nodes)).options(node_alpha='alpha') - with self.assertRaises(Exception): - mpl_renderer.get_plot(graph) + + if Version(mpl.__version__) < Version("3.4.0"): + # Python 3.6 only support up to matplotlib 3.3 + with self.assertRaises(Exception): + mpl_renderer.get_plot(graph) + else: + plot = mpl_renderer.get_plot(graph) + artist = plot.handles['nodes'] + self.assertEqual(artist.get_alpha(), np.array([0.2, 0.6, 1])) def test_graph_op_edge_color(self): edges = [(0, 1, 'red'), (0, 2, 'green'), (1, 3, 'blue')] @@ -385,11 +395,21 @@ def test_trimesh_op_node_size(self): self.assertEqual(artist.get_sizes(), np.array([9, 4, 64, 16])) def test_trimesh_op_node_alpha(self): + import matplotlib as mpl + from packaging.version import Version + edges = [(0, 1, 2), (1, 2, 3)] nodes = [(-1, -1, 0, 0.2), (0, 0, 1, 0.6), (0, 1, 2, 1), (1, 0, 3, 0.3)] trimesh = TriMesh((edges, Nodes(nodes, vdims='alpha'))).options(node_alpha='alpha') - with self.assertRaises(Exception): - mpl_renderer.get_plot(trimesh) + + if Version(mpl.__version__) < Version("3.4.0"): + # Python 3.6 only support up to matplotlib 3.3 + with self.assertRaises(Exception): + mpl_renderer.get_plot(trimesh) + else: + plot = mpl_renderer.get_plot(trimesh) + artist = plot.handles['nodes'] + self.assertEqual(artist.get_alpha(), np.array([0.2, 0.6, 1, 0.3])) def test_trimesh_op_node_line_width(self): edges = [(0, 1, 2), (1, 2, 3)] diff --git a/holoviews/tests/plotting/matplotlib/testhistogramplot.py b/holoviews/tests/plotting/matplotlib/testhistogramplot.py index 8cbf181a69..1459f0802f 100644 --- a/holoviews/tests/plotting/matplotlib/testhistogramplot.py +++ b/holoviews/tests/plotting/matplotlib/testhistogramplot.py @@ -19,8 +19,8 @@ def test_histogram_datetime64_plot(self): plot = mpl_renderer.get_plot(hist) artist = plot.handles['artist'] ax = plot.handles['axis'] - self.assertEqual(ax.get_xlim(), (736330.0, 736333.0)) - bounds = [736330.0, 736330.75, 736331.5, 736332.25] + self.assertEqual(ax.get_xlim(), (17167.0, 17170.0)) + bounds = [17167.0, 17167.75, 17168.5, 17169.25] self.assertEqual([p.get_x() for p in artist.patches], bounds) def test_histogram_padding_square(self): @@ -84,8 +84,8 @@ def test_histogram_padding_datetime_square(self): ) plot = mpl_renderer.get_plot(histogram) x_range, y_range = plot.handles['axis'].get_xlim(), plot.handles['axis'].get_ylim() - self.assertEqual(x_range[0], 736054.19999999995) - self.assertEqual(x_range[1], 736057.80000000005) + self.assertEqual(x_range[0], 16891.2) + self.assertEqual(x_range[1], 16894.8) self.assertEqual(y_range[0], 0) self.assertEqual(y_range[1], 3.2) @@ -95,8 +95,8 @@ def test_histogram_padding_datetime_nonsquare(self): ) plot = mpl_renderer.get_plot(histogram) x_range, y_range = plot.handles['axis'].get_xlim(), plot.handles['axis'].get_ylim() - self.assertEqual(x_range[0], 736054.34999999998) - self.assertEqual(x_range[1], 736057.65000000002) + self.assertEqual(x_range[0], 16891.35) + self.assertEqual(x_range[1], 16894.65) self.assertEqual(y_range[0], 0) self.assertEqual(y_range[1], 3.2) @@ -124,12 +124,16 @@ def test_histogram_categorical_color_op(self): vdims=['y', 'color']).options(color='color') with self.assertRaises(Exception): mpl_renderer.get_plot(histogram) - + def test_histogram_line_color_op(self): histogram = Histogram([(0, 0, '#000'), (0, 1, '#F00'), (0, 2, '#0F0')], vdims=['y', 'color']).options(edgecolor='color') - with self.assertRaises(Exception): - mpl_renderer.get_plot(histogram) + plot = mpl_renderer.get_plot(histogram) + artist = plot.handles['artist'] + children = artist.get_children() + self.assertEqual(children[0].get_edgecolor(), (0, 0, 0, 1)) + self.assertEqual(children[1].get_edgecolor(), (1, 0, 0, 1)) + self.assertEqual(children[2].get_edgecolor(), (0, 1, 0, 1)) def test_histogram_alpha_op(self): histogram = Histogram([(0, 0, 0), (0, 1, 0.2), (0, 2, 0.7)], diff --git a/holoviews/tests/plotting/matplotlib/testpointplot.py b/holoviews/tests/plotting/matplotlib/testpointplot.py index f8caf80c0c..725e0508ae 100644 --- a/holoviews/tests/plotting/matplotlib/testpointplot.py +++ b/holoviews/tests/plotting/matplotlib/testpointplot.py @@ -137,8 +137,8 @@ def test_points_padding_datetime_square(self): ) plot = mpl_renderer.get_plot(points) x_range, y_range = plot.handles['axis'].get_xlim(), plot.handles['axis'].get_ylim() - self.assertEqual(x_range[0], 736054.80000000005) - self.assertEqual(x_range[1], 736057.19999999995) + self.assertEqual(x_range[0], 16891.8) + self.assertEqual(x_range[1], 16894.2) self.assertEqual(y_range[0], 0.8) self.assertEqual(y_range[1], 3.2) @@ -148,8 +148,8 @@ def test_points_padding_datetime_nonsquare(self): ) plot = mpl_renderer.get_plot(points) x_range, y_range = plot.handles['axis'].get_xlim(), plot.handles['axis'].get_ylim() - self.assertEqual(x_range[0], 736054.90000000002) - self.assertEqual(x_range[1], 736057.09999999998) + self.assertEqual(x_range[0], 16891.9) + self.assertEqual(x_range[1], 16894.1) self.assertEqual(y_range[0], 0.8) self.assertEqual(y_range[1], 3.2) diff --git a/holoviews/tests/plotting/matplotlib/testrenderer.py b/holoviews/tests/plotting/matplotlib/testrenderer.py index 30bfd3b2f0..3ac4119fd0 100644 --- a/holoviews/tests/plotting/matplotlib/testrenderer.py +++ b/holoviews/tests/plotting/matplotlib/testrenderer.py @@ -68,12 +68,12 @@ def test_get_size_single_plot(self): def test_get_size_row_plot(self): plot = self.renderer.get_plot(self.image1+self.image2) w, h = self.renderer.get_size(plot) - self.assertEqual((w, h), (576, 255)) + self.assertEqual((w, h), (576, 257)) def test_get_size_column_plot(self): plot = self.renderer.get_plot((self.image1+self.image2).cols(1)) w, h = self.renderer.get_size(plot) - self.assertEqual((w, h), (288, 505)) + self.assertEqual((w, h), (288, 509)) def test_get_size_grid_plot(self): grid = GridSpace({(i, j): self.image1 for i in range(3) for j in range(3)}) diff --git a/holoviews/tests/plotting/matplotlib/testspikeplot.py b/holoviews/tests/plotting/matplotlib/testspikeplot.py index fc9f06a4ea..5c7f7f505f 100644 --- a/holoviews/tests/plotting/matplotlib/testspikeplot.py +++ b/holoviews/tests/plotting/matplotlib/testspikeplot.py @@ -67,8 +67,8 @@ def test_spikes_padding_datetime_square(self): ) plot = mpl_renderer.get_plot(spikes) x_range = plot.handles['axis'].get_xlim() - self.assertEqual(x_range[0], 736054.80000000005) - self.assertEqual(x_range[1], 736057.19999999995) + self.assertEqual(x_range[0], 16891.8) + self.assertEqual(x_range[1], 16894.2) def test_spikes_padding_datetime_square_heights(self): spikes = Spikes([(np.datetime64('2016-04-0%d' % i), i) for i in range(1, 4)], vdims=['Height']).options( @@ -76,8 +76,8 @@ def test_spikes_padding_datetime_square_heights(self): ) plot = mpl_renderer.get_plot(spikes) x_range, y_range = plot.handles['axis'].get_xlim(), plot.handles['axis'].get_ylim() - self.assertEqual(x_range[0], 736054.80000000005) - self.assertEqual(x_range[1], 736057.19999999995) + self.assertEqual(x_range[0], 16891.8) + self.assertEqual(x_range[1], 16894.2) self.assertEqual(y_range[0], 0) self.assertEqual(y_range[1], 3.2) @@ -87,8 +87,8 @@ def test_spikes_padding_datetime_nonsquare(self): ) plot = mpl_renderer.get_plot(spikes) x_range = plot.handles['axis'].get_xlim() - self.assertEqual(x_range[0], 736054.90000000002) - self.assertEqual(x_range[1], 736057.09999999998) + self.assertEqual(x_range[0], 16891.9) + self.assertEqual(x_range[1], 16894.1) ########################### # Styling mapping # diff --git a/setup.py b/setup.py index 25f7c9b463..f09090c036 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ # IPython Notebook + pandas + matplotlib + bokeh extras_require["recommended"] = extras_require["notebook"] + [ - "matplotlib >=2.2", + "matplotlib >=3", "bokeh >=1.1.0", ] @@ -34,7 +34,7 @@ extras_require["examples"] = extras_require["recommended"] + [ "networkx", "pillow", - "xarray >=0.10.4,<0.17.0", + "xarray >=0.10.4", "plotly >=4.0", 'dash >=1.16', "streamz >=0.5.0", @@ -52,7 +52,7 @@ extras_require["examples"].extend( [ "spatialpandas", - "pyarrow <1.0", + "pyarrow", "ibis-framework >=1.3", ] # spatialpandas incompatibility ) @@ -66,10 +66,10 @@ extras_require['tests'] = [ 'nose', 'mock', - 'flake8 ==3.6.0', + 'flake8', 'coveralls', 'path.py', - 'matplotlib >=2.2,<3.1', + 'matplotlib >=3', 'nbsmoke >=0.2.0', 'nbconvert <6', 'twine', @@ -81,7 +81,7 @@ extras_require["basic_tests"] = ( extras_require["tests"] - + ["matplotlib >=2.1", "bokeh >=1.1.0", "pandas"] + + ["matplotlib >=3", "bokeh >=1.1.0", "pandas"] + extras_require["notebook"] ) @@ -110,7 +110,8 @@ "param >=1.7.0", "setuptools >=30.3.0", "pyct >=0.4.4", - "python <3.8", + "python <3.9", + "pip", ] # Everything for examples and nosetests diff --git a/tox.ini b/tox.ini index b3a2886024..9a804d2137 100644 --- a/tox.ini +++ b/tox.ini @@ -2,8 +2,8 @@ # tox config (works with tox alone). [tox] -# python version test group extra envs extra commands -envlist = {py27,py35,py36,py37}-{flakes,unit,examples,all_recommended,regression}-{default}-{dev,pkg} +# python version test group extra envs extra commands +envlist = {py36,py37,py38}-{flakes,unit,examples,all_recommended,regression}-{default}-{dev,pkg} [_flakes] description = Flake check python