diff --git a/doc/api/next_api_changes/behavior/23550-OG.rst b/doc/api/next_api_changes/behavior/23550-OG.rst new file mode 100644 index 000000000000..6f7420e431ff --- /dev/null +++ b/doc/api/next_api_changes/behavior/23550-OG.rst @@ -0,0 +1,10 @@ +Specified exception types in Grid +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In a few cases an `Exception` was thrown when an incorrect argument value +was set in the `mpl_toolkits.axes_grid1.axes_grid.Grid` +(= `mpl_toolkits.axisartist.axes_grid.Grid`) constructor. These are replaced +as follows: + +* Providing an incorrect value for *ngrids* now raises a `ValueError` +* Providing an incorrect type for *rect* now raises a `TypeError` diff --git a/lib/mpl_toolkits/axes_grid1/axes_divider.py b/lib/mpl_toolkits/axes_grid1/axes_divider.py index bf4a4d35dcdd..251fa44b14bf 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_divider.py +++ b/lib/mpl_toolkits/axes_grid1/axes_divider.py @@ -39,7 +39,8 @@ def __init__(self, fig, pos, horizontal, vertical, aspect : bool Whether overall rectangular area is reduced so that the relative part of the horizontal and vertical scales have the same scale. - anchor : {'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', 'NW', 'W'} + anchor : (float, float) or {'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', \ +'NW', 'W'} Placement of the reduced rectangle, when *aspect* is True. """ @@ -48,6 +49,7 @@ def __init__(self, fig, pos, horizontal, vertical, self._horizontal = horizontal self._vertical = vertical self._anchor = anchor + self.set_anchor(anchor) self._aspect = aspect self._xrefindex = 0 self._yrefindex = 0 @@ -106,7 +108,8 @@ def set_anchor(self, anchor): """ Parameters ---------- - anchor : (float, float) or {'C', 'SW', 'S', 'SE', 'E', 'NE', ...} + anchor : (float, float) or {'C', 'SW', 'S', 'SE', 'E', 'NE', 'N', \ +'NW', 'W'} Either an (*x*, *y*) pair of relative coordinates (0 is left or bottom, 1 is right or top), 'C' (center), or a cardinal direction ('SW', southwest, is bottom left, etc.). @@ -115,8 +118,10 @@ def set_anchor(self, anchor): -------- .Axes.set_anchor """ - if len(anchor) != 2: + if isinstance(anchor, str): _api.check_in_list(mtransforms.Bbox.coefs, anchor=anchor) + elif not isinstance(anchor, (tuple, list)) or len(anchor) != 2: + raise TypeError("anchor must be str or 2-tuple") self._anchor = anchor def get_anchor(self): @@ -250,6 +255,8 @@ def new_locator(self, nx, ny, nx1=None, ny1=None): ny1 if ny1 is not None else ny + 1) def append_size(self, position, size): + _api.check_in_list(["left", "right", "bottom", "top"], + position=position) if position == "left": self._horizontal.insert(0, size) self._xrefindex += 1 @@ -258,11 +265,8 @@ def append_size(self, position, size): elif position == "bottom": self._vertical.insert(0, size) self._yrefindex += 1 - elif position == "top": + else: # 'top' self._vertical.append(size) - else: - _api.check_in_list(["left", "right", "bottom", "top"], - position=position) def add_auto_adjustable_area(self, use_axes, pad=0.1, adjust_dirs=None): """ @@ -512,21 +516,14 @@ def append_axes(self, position, size, pad=None, add_to_figure=True, *, **kwargs All extra keywords arguments are passed to the created axes. """ - if position == "left": - ax = self.new_horizontal( - size, pad, pack_start=True, axes_class=axes_class, **kwargs) - elif position == "right": - ax = self.new_horizontal( - size, pad, pack_start=False, axes_class=axes_class, **kwargs) - elif position == "bottom": - ax = self.new_vertical( - size, pad, pack_start=True, axes_class=axes_class, **kwargs) - elif position == "top": - ax = self.new_vertical( - size, pad, pack_start=False, axes_class=axes_class, **kwargs) - else: - _api.check_in_list(["left", "right", "bottom", "top"], - position=position) + create_axes, pack_start = _api.check_getitem({ + "left": (self.new_horizontal, True), + "right": (self.new_horizontal, False), + "bottom": (self.new_vertical, True), + "top": (self.new_vertical, False), + }, position=position) + ax = create_axes( + size, pad, pack_start=pack_start, axes_class=axes_class, **kwargs) if add_to_figure: self._fig.add_axes(ax) return ax diff --git a/lib/mpl_toolkits/axes_grid1/axes_grid.py b/lib/mpl_toolkits/axes_grid1/axes_grid.py index 3198ab2b3bdf..ad97ec6a232b 100644 --- a/lib/mpl_toolkits/axes_grid1/axes_grid.py +++ b/lib/mpl_toolkits/axes_grid1/axes_grid.py @@ -123,7 +123,8 @@ def __init__(self, fig, ngrids = self._nrows * self._ncols else: if not 0 < ngrids <= self._nrows * self._ncols: - raise Exception("") + raise ValueError( + "ngrids must be positive and not larger than nrows*ncols") self.ngrids = ngrids @@ -147,7 +148,7 @@ def __init__(self, fig, elif len(rect) == 4: self._divider = Divider(fig, rect, **kw) else: - raise Exception("") + raise TypeError("Incorrect rect format") rect = self._divider.get_position() @@ -270,6 +271,7 @@ def set_label_mode(self, mode): - "1": Only the bottom left axes is labelled. - "all": all axes are labelled. """ + _api.check_in_list(["all", "L", "1"], mode=mode) if mode == "all": for ax in self.axes_all: _tick_only(ax, False, False) @@ -290,7 +292,7 @@ def set_label_mode(self, mode): ax = col[-1] _tick_only(ax, bottom_on=False, left_on=True) - elif mode == "1": + else: # "1" for ax in self.axes_all: _tick_only(ax, bottom_on=True, left_on=True) @@ -378,6 +380,10 @@ def __init__(self, fig, to associated *cbar_axes*. axes_class : subclass of `matplotlib.axes.Axes`, default: None """ + _api.check_in_list(["each", "single", "edge", None], + cbar_mode=cbar_mode) + _api.check_in_list(["left", "right", "bottom", "top"], + cbar_location=cbar_location) self._colorbar_mode = cbar_mode self._colorbar_location = cbar_location self._colorbar_pad = cbar_pad diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 857fa72b9d57..05df0c16f220 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -813,7 +813,7 @@ def set_proj_type(self, proj_type, focal_length=None): raise ValueError(f"focal_length = {focal_length} must be " "greater than 0") self._focal_length = focal_length - elif proj_type == 'ortho': + else: # 'ortho': if focal_length not in (None, np.inf): raise ValueError(f"focal_length = {focal_length} must be " f"None for proj_type = {proj_type}") diff --git a/lib/mpl_toolkits/tests/test_axes_grid1.py b/lib/mpl_toolkits/tests/test_axes_grid1.py index 24b492ea4e51..09779df91a7e 100644 --- a/lib/mpl_toolkits/tests/test_axes_grid1.py +++ b/lib/mpl_toolkits/tests/test_axes_grid1.py @@ -17,7 +17,7 @@ from mpl_toolkits.axes_grid1.anchored_artists import ( AnchoredSizeBar, AnchoredDirectionArrows) from mpl_toolkits.axes_grid1.axes_divider import ( - HBoxDivider, make_axes_area_auto_adjustable) + Divider, HBoxDivider, make_axes_area_auto_adjustable) from mpl_toolkits.axes_grid1.axes_rgb import RGBAxes from mpl_toolkits.axes_grid1.inset_locator import ( zoomed_inset_axes, mark_inset, inset_axes, BboxConnectorPatch) @@ -376,10 +376,9 @@ def test_image_grid(): fig = plt.figure(1, (4, 4)) grid = ImageGrid(fig, 111, nrows_ncols=(2, 2), axes_pad=0.1) - + assert grid.get_axes_pad() == (0.1, 0.1) for i in range(4): grid[i].imshow(im, interpolation='nearest') - grid[i].set_title('test {0}{0}'.format(i)) def test_gettightbbox(): @@ -492,6 +491,7 @@ def test_grid_axes_lists(): assert_array_equal(grid, grid.axes_all) assert_array_equal(grid.axes_row, np.transpose(grid.axes_column)) assert_array_equal(grid, np.ravel(grid.axes_row), "row") + assert grid.get_geometry() == (2, 3) grid = Grid(fig, 111, (2, 3), direction="column") assert_array_equal(grid, np.ravel(grid.axes_column), "column") @@ -507,6 +507,29 @@ def test_grid_axes_position(direction): assert loc[3]._nx == loc[1]._nx and loc[3]._ny == loc[2]._ny +@pytest.mark.parametrize('rect, ngrids, error, message', ( + ((1, 1), None, TypeError, "Incorrect rect format"), + (111, -1, ValueError, "ngrids must be positive"), + (111, 7, ValueError, "ngrids must be positive"), +)) +def test_grid_errors(rect, ngrids, error, message): + fig = plt.figure() + with pytest.raises(error, match=message): + Grid(fig, rect, (2, 3), ngrids=ngrids) + + +@pytest.mark.parametrize('anchor, error, message', ( + (None, TypeError, "anchor must be str"), + ("CC", ValueError, "'CC' is not a valid value for anchor"), + ((1, 1, 1), TypeError, "anchor must be str"), +)) +def test_divider_errors(anchor, error, message): + fig = plt.figure() + with pytest.raises(error, match=message): + Divider(fig, [0, 0, 1, 1], [Size.Fixed(1)], [Size.Fixed(1)], + anchor=anchor) + + @check_figures_equal(extensions=["png"]) def test_mark_inset_unstales_viewlim(fig_test, fig_ref): inset, full = fig_test.subplots(1, 2)