diff --git a/doc/users/next_whats_new/2020-01-09-AL.rst b/doc/users/next_whats_new/2020-01-09-AL.rst new file mode 100644 index 000000000000..7a48465c1c0d --- /dev/null +++ b/doc/users/next_whats_new/2020-01-09-AL.rst @@ -0,0 +1,5 @@ +Contour plots now default to using ScalarFormatter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Pass ``fmt="%1.3f"`` to the contouring call to restore the old default label +format. diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index 6ce0a14f2fe6..d3df90d73972 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -17,9 +17,7 @@ import matplotlib.font_manager as font_manager import matplotlib.text as text import matplotlib.cbook as cbook -import matplotlib.mathtext as mathtext import matplotlib.patches as mpatches -import matplotlib.texmanager as texmanager import matplotlib.transforms as mtransforms # Import needed for adding manual selection capability to clabel @@ -51,7 +49,7 @@ class ContourLabeler: """Mixin to provide labelling capability to `.ContourSet`.""" def clabel(self, levels=None, *, - fontsize=None, inline=True, inline_spacing=5, fmt='%1.3f', + fontsize=None, inline=True, inline_spacing=5, fmt=None, colors=None, use_clabeltext=False, manual=False, rightside_up=True, zorder=None): """ @@ -92,14 +90,17 @@ def clabel(self, levels=None, *, This spacing will be exact for labels at locations where the contour is straight, less so for labels on curved contours. - fmt : str or dict, default: '%1.3f' - A format string for the label. + fmt : `.Formatter` or str or callable or dict, optional + How the levels are formatted: - Alternatively, this can be a dictionary matching contour levels - with arbitrary strings to use for each contour level (i.e., - fmt[level]=string), or it can be any callable, such as a - `.Formatter` instance, that returns a string when called with a - numeric contour level. + - If a `.Formatter`, it is used to format all levels at once, using + its `.Formatter.format_ticks` method. + - If a str, it is interpreted as a %-style format string. + - If a callable, it is called with one level at a time and should + return the corresponding label. + - If a dict, it should directly map levels to labels. + + The default is to use a standard `.ScalarFormatter`. manual : bool or iterable, default: False If ``True``, contour labels will be placed manually using @@ -144,6 +145,9 @@ def clabel(self, levels=None, *, # labels method (case of automatic label placement) or # `BlockingContourLabeler` (case of manual label placement). + if fmt is None: + fmt = ticker.ScalarFormatter(useOffset=False) + fmt.create_dummy_axis() self.labelFmt = fmt self._use_clabeltext = use_clabeltext # Detect if manual selection is desired and remove from argument list. @@ -243,20 +247,12 @@ def get_label_width(self, lev, fmt, fsize): """ if not isinstance(lev, str): lev = self.get_text(lev, fmt) - lev, ismath = text.Text()._preprocess_math(lev) - if ismath == 'TeX': - lw, _, _ = (texmanager.TexManager() - .get_text_width_height_descent(lev, fsize)) - elif ismath: - if not hasattr(self, '_mathtext_parser'): - self._mathtext_parser = mathtext.MathTextParser('agg') - _, _, _, _, _, img, _ = self._mathtext_parser.parse( - lev, dpi=72, prop=self.labelFontProps) - _, lw = np.shape(img) # at dpi=72, the units are PostScript points - else: - # width is much less than "font size" - lw = len(lev) * fsize * 0.6 - return lw + fig = self.axes.figure + width = (text.Text(0, 0, lev, figure=fig, + size=fsize, fontproperties=self.labelFontProps) + .get_window_extent(fig.canvas.get_renderer()).width) + width *= 72 / fig.dpi + return width def set_label_props(self, label, text, color): """Set the label properties - color, fontsize, text.""" @@ -269,13 +265,14 @@ def get_text(self, lev, fmt): """Get the text of the label.""" if isinstance(lev, str): return lev + elif isinstance(fmt, dict): + return fmt.get(lev, '%1.3f') + elif callable(getattr(fmt, "format_ticks", None)): + return fmt.format_ticks([*self.labelLevelList, lev])[-1] + elif callable(fmt): + return fmt(lev) else: - if isinstance(fmt, dict): - return fmt.get(lev, '%1.3f') - elif callable(fmt): - return fmt(lev) - else: - return fmt % lev + return fmt % lev def locate_label(self, linecontour, labelwidth): """ @@ -564,23 +561,14 @@ def labels(self, inline, inline_spacing): paths = con.get_paths() for segNum, linepath in enumerate(paths): lc = linepath.vertices # Line contour - slc0 = trans.transform(lc) # Line contour in screen coords - - # For closed polygons, add extra point to avoid division by - # zero in print_label and locate_label. Other than these - # functions, this is not necessary and should probably be - # eventually removed. - if _is_closed_polygon(lc): - slc = np.row_stack([slc0, slc0[1:2]]) - else: - slc = slc0 + slc = trans.transform(lc) # Line contour in screen coords # Check if long enough for a label if self.print_label(slc, lw): x, y, ind = self.locate_label(slc, lw) rotation, new = self.calc_label_rot_and_inline( - slc0, ind, lw, lc if inline else None, inline_spacing) + slc, ind, lw, lc if inline else None, inline_spacing) # Actually add the label add_label(x, y, rotation, lev, cvalue) diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf index 8e4a28a55362..f46eb90b46a2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf and b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.png index d6acf227567a..2b257bc152f1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.png and b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.svg b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.svg index 3fbf8b835e46..8a3952e2f846 100644 --- a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.svg +++ b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.svg @@ -1,12 +1,23 @@ - + + + + + 2020-11-06T19:00:48.952407 + image/svg+xml + + + Matplotlib v3.3.2.post1573+gcdb08ceb8, https://matplotlib.org/ + + + + + - + @@ -32,73 +43,73 @@ z +" id="mbc9e29bc37" style="stroke:#000000;stroke-width:0.8;"/> - + - + - + - + - + - + - + - + - + - + @@ -109,60 +120,61 @@ L 0 3.5 +" id="m8b888be400" style="stroke:#000000;stroke-width:0.8;"/> - + - + - + - + - + - - - - + - + - - + - - - - - - + + + + - + - + - - - - - - - +" id="DejaVuSans-30" transform="scale(0.015625)"/> + + + + - - - - + + + + - + - - - - - - - +" id="DejaVuSans-35" transform="scale(0.015625)"/> + + + + - - - - + + + + - - - - - - - +" id="DejaVuSans-36" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_test_label_transforms.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_test_label_transforms.png index 723e501ed287..08a321297e9d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_contour/contour_test_label_transforms.png and b/lib/matplotlib/tests/baseline_images/test_contour/contour_test_label_transforms.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf index d74333643910..5d3d519a0115 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf and b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.png b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.png index 07410efba929..8509477b1cdb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.png and b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg index 988cc34ebe56..1cf5236c05e9 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg @@ -1,12 +1,23 @@ - + + + + + 2020-11-06T19:00:52.592209 + image/svg+xml + + + Matplotlib v3.3.2.post1573+gcdb08ceb8, https://matplotlib.org/ + + + + + - + @@ -32,273 +43,276 @@ z +" id="m8e2d372e63" style="stroke:#000000;stroke-width:0.8;"/> - + - - - - + + + + - + - - - - - + + + + + - + - - - - - + + + + + - + - - - - - + + + + + - + - - - - - + + + + + - + - - - - - - + + + + + + - + - - - + + + - + - - - + + + @@ -309,72 +323,72 @@ z +" id="mabaf925b83" style="stroke:#000000;stroke-width:0.8;"/> - + - + - + - - + + - + - - + + - + - - + + - + - - + + @@ -382,7 +396,7 @@ L -3.5 0 - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - + + + - - - + + + - - - - - - - + - - - - + - - - + - - - - + + + - - - - - - + + + - - - - - - + + + - - - - - - + - - - - + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -4678,9888 +5008,6388 @@ L 414.72 41.472 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf index a8b20ed3ce98..8d0cc584e567 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf and b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.png b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.png index bc21b72c4f23..ebd8d95dc0ab 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.png and b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg index be0bbc4cbaad..e067b3ed266d 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg @@ -1,12 +1,23 @@ - + + + + + 2020-11-06T19:00:51.436188 + image/svg+xml + + + Matplotlib v3.3.2.post1573+gcdb08ceb8, https://matplotlib.org/ + + + + + - + @@ -26,9 +37,9 @@ L 103.104 41.472 z " style="fill:#ffffff;"/> - - + + @@ -36,38 +47,38 @@ iVBORw0KGgoAAAANSUhEUgAAAXIAAAFyCAYAAADoJFEJAAAABHNCSVQICAgIfAhkiAAABdNJREFUeJzt +" id="ma6b8906a8c" style="stroke:#000000;stroke-width:0.8;"/> - + - + - + - + - + @@ -78,179 +89,185 @@ L 0 3.5 +" id="ma7f3c1a8f9" style="stroke:#000000;stroke-width:0.8;"/> - + - + - + - + - + - + + + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + - - - - - + + - - - + - - - + - - - + - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - - - - + - + + + + + + + - - - - - diff --git a/lib/matplotlib/tests/test_contour.py b/lib/matplotlib/tests/test_contour.py index c5844d2da563..883431fe627a 100644 --- a/lib/matplotlib/tests/test_contour.py +++ b/lib/matplotlib/tests/test_contour.py @@ -109,29 +109,16 @@ def test_contour_uniform_z(): assert len(record) == 1 -@image_comparison(['contour_manual_labels'], - savefig_kwarg={'dpi': 200}, remove_text=True, style='mpl20') +@image_comparison(['contour_manual_labels'], remove_text=True, style='mpl20') def test_contour_manual_labels(): - x, y = np.meshgrid(np.arange(0, 10), np.arange(0, 10)) z = np.max(np.dstack([abs(x), abs(y)]), 2) plt.figure(figsize=(6, 2), dpi=200) cs = plt.contour(x, y, z) - pts = np.array([(1.5, 3.0), (1.5, 4.4), (1.5, 6.0)]) + pts = np.array([(1.0, 3.0), (1.0, 4.4), (1.0, 6.0)]) plt.clabel(cs, manual=pts) - - -@image_comparison(['contour_labels_size_color.png'], - remove_text=True, style='mpl20') -def test_contour_labels_size_color(): - - x, y = np.meshgrid(np.arange(0, 10), np.arange(0, 10)) - z = np.max(np.dstack([abs(x), abs(y)]), 2) - - plt.figure(figsize=(6, 2)) - cs = plt.contour(x, y, z) - pts = np.array([(1.5, 3.0), (1.5, 4.4), (1.5, 6.0)]) + pts = np.array([(2.0, 3.0), (2.0, 4.4), (2.0, 6.0)]) plt.clabel(cs, manual=pts, fontsize='small', colors=('r', 'g'))