Skip to content

Commit e086a5d

Browse files
committed
Merge remote-tracking branch 'matplotlib/v2.x'
Conflicts: examples/showcase/anatomy.py White space conflict
2 parents 4303c3c + 39c7d1e commit e086a5d

File tree

19 files changed

+126
-88
lines changed

19 files changed

+126
-88
lines changed

doc/faq/anatomy.png

-2.3 KB
Loading

doc/users/dflt_style_changes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,11 @@ The behavior of the PS and Agg backends was DPI dependent, thus::
625625

626626
There is no API level control of the hatch color or linewidth.
627627

628+
Hatching patterns are now rendered at a consistent density, regardless of DPI.
629+
Formerly, high DPI figures would be more dense than the default, and low DPI
630+
figures would be less dense. This old behavior cannot be directly restored,
631+
but the density may be increased by repeating the hatch specifier.
632+
628633

629634
.. _default_changes_font:
630635

examples/showcase/anatomy.py

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import numpy as np
44
import matplotlib.pyplot as plt
5-
from matplotlib.ticker import MultipleLocator, FuncFormatter
5+
from matplotlib.ticker import AutoMinorLocator, MultipleLocator, FuncFormatter
66

77
np.random.seed(19680801)
88

@@ -11,7 +11,7 @@
1111
Y2 = 1+np.cos(1+X/0.75)/2
1212
Y3 = np.random.uniform(Y1, Y2, len(X))
1313

14-
fig = plt.figure(figsize=(8, 8), facecolor="w")
14+
fig = plt.figure(figsize=(8, 8))
1515
ax = fig.add_subplot(1, 1, 1, aspect=1)
1616

1717

@@ -21,9 +21,9 @@ def minor_tick(x, pos):
2121
return "%.2f" % x
2222

2323
ax.xaxis.set_major_locator(MultipleLocator(1.000))
24-
ax.xaxis.set_minor_locator(MultipleLocator(0.250))
24+
ax.xaxis.set_minor_locator(AutoMinorLocator(4))
2525
ax.yaxis.set_major_locator(MultipleLocator(1.000))
26-
ax.yaxis.set_minor_locator(MultipleLocator(0.250))
26+
ax.yaxis.set_minor_locator(AutoMinorLocator(4))
2727
ax.xaxis.set_minor_formatter(FuncFormatter(minor_tick))
2828

2929
ax.set_xlim(0, 4)
@@ -38,13 +38,14 @@ def minor_tick(x, pos):
3838

3939
ax.plot(X, Y1, c=(0.25, 0.25, 1.00), lw=2, label="Blue signal", zorder=10)
4040
ax.plot(X, Y2, c=(1.00, 0.25, 0.25), lw=2, label="Red signal")
41-
ax.scatter(X, Y3, c='w')
41+
ax.plot(X, Y3, linewidth=0,
42+
marker='o', markerfacecolor='w', markeredgecolor='k')
4243

43-
ax.set_title("Anatomy of a figure", fontsize=20)
44+
ax.set_title("Anatomy of a figure", fontsize=20, verticalalignment='bottom')
4445
ax.set_xlabel("X axis label")
4546
ax.set_ylabel("Y axis label")
4647

47-
ax.legend(frameon=False)
48+
ax.legend()
4849

4950

5051
def circle(x, y, radius=0.15):
@@ -62,32 +63,32 @@ def text(x, y, text):
6263

6364

6465
# Minor tick
65-
circle(0.50, -.05)
66-
text(0.50, -0.25, "Minor tick label")
66+
circle(0.50, -0.10)
67+
text(0.50, -0.32, "Minor tick label")
6768

6869
# Major tick
69-
circle(4.00, 2.00)
70-
text(4.00, 1.80, "Major tick")
70+
circle(-0.03, 4.00)
71+
text(0.03, 3.80, "Major tick")
7172

7273
# Minor tick
73-
circle(0.25, 4.00)
74-
text(0.25, 3.80, "Minor tick")
74+
circle(0.00, 3.50)
75+
text(0.00, 3.30, "Minor tick")
7576

7677
# Major tick label
77-
circle(-0.05, 3.00)
78-
text(-0.05, 2.80, "Major tick label")
78+
circle(-0.15, 3.00)
79+
text(-0.15, 2.80, "Major tick label")
7980

8081
# X Label
81-
circle(1.80, -0.22)
82-
text(1.80, -0.4, "X axis label")
82+
circle(1.80, -0.27)
83+
text(1.80, -0.45, "X axis label")
8384

8485
# Y Label
85-
circle(-0.20, 1.80)
86-
text(-0.20, 1.6, "Y axis label")
86+
circle(-0.27, 1.80)
87+
text(-0.27, 1.6, "Y axis label")
8788

8889
# Title
89-
circle(1.60, 4.10)
90-
text(1.60, 3.9, "Title")
90+
circle(1.60, 4.13)
91+
text(1.60, 3.93, "Title")
9192

9293
# Blue plot
9394
circle(1.75, 2.80)
@@ -106,8 +107,8 @@ def text(x, y, text):
106107
text(3.00, 2.80, "Grid")
107108

108109
# Legend
109-
circle(3.70, 3.75)
110-
text(3.70, 3.55, "Legend")
110+
circle(3.70, 3.80)
111+
text(3.70, 3.60, "Legend")
111112

112113
# Axes
113114
circle(0.5, 0.5)

lib/matplotlib/axes/_base.py

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,6 +2173,10 @@ def autoscale(self, enable=True, axis='both', tight=None):
21732173
if axis in ['y', 'both']:
21742174
self._autoscaleYon = bool(enable)
21752175
scaley = self._autoscaleYon
2176+
if tight and scalex:
2177+
self._xmargin = 0
2178+
if tight and scaley:
2179+
self._ymargin = 0
21762180
self.autoscale_view(tight=tight, scalex=scalex, scaley=scaley)
21772181

21782182
def autoscale_view(self, tight=None, scalex=True, scaley=True):
@@ -2182,6 +2186,14 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True):
21822186
setting *scaley* to *False*. The autoscaling preserves any
21832187
axis direction reversal that has already been done.
21842188
2189+
If *tight* is *False*, the axis major locator will be used
2190+
to expand the view limits if rcParams['axes.autolimit_mode']
2191+
is 'round_numbers'. Note that any margins that are in effect
2192+
will be applied first, regardless of whether *tight* is
2193+
*True* or *False*. Specifying *tight* as *True* or *False*
2194+
saves the setting as a private attribute of the Axes; specifying
2195+
it as *None* (the default) applies the previously saved value.
2196+
21852197
The data limits are not updated automatically when artist data are
21862198
changed after the artist has been added to an Axes instance. In that
21872199
case, use :meth:`matplotlib.axes.Axes.relim` prior to calling
@@ -2234,52 +2246,56 @@ def autoscale_view(self, tight=None, scalex=True, scaley=True):
22342246
def handle_single_axis(scale, autoscaleon, shared_axes, interval,
22352247
minpos, axis, margin, do_lower_margin,
22362248
do_upper_margin, set_bound):
2237-
if scale and autoscaleon:
2238-
shared = shared_axes.get_siblings(self)
2239-
dl = [ax.dataLim for ax in shared]
2240-
# ignore non-finite data limits if good limits exist
2241-
finite_dl = [d for d in dl if np.isfinite(d).all()]
2242-
if len(finite_dl):
2243-
dl = finite_dl
2244-
2245-
bb = mtransforms.BboxBase.union(dl)
2246-
x0, x1 = getattr(bb, interval)
2247-
locator = axis.get_major_locator()
2248-
try:
2249-
# e.g., DateLocator has its own nonsingular()
2250-
x0, x1 = locator.nonsingular(x0, x1)
2251-
except AttributeError:
2252-
# Default nonsingular for, e.g., MaxNLocator
2253-
x0, x1 = mtransforms.nonsingular(
2254-
x0, x1, increasing=False, expander=0.05)
2255-
2256-
if margin > 0 and (do_lower_margin or do_upper_margin):
2257-
if axis.get_scale() == 'linear':
2258-
delta = (x1 - x0) * margin
2259-
if do_lower_margin:
2260-
x0 -= delta
2261-
if do_upper_margin:
2262-
x1 += delta
2263-
else:
2264-
# If we have a non-linear scale, we need to
2265-
# add the margin in figure space and then
2266-
# transform back
2267-
minpos = getattr(bb, minpos)
2268-
transform = axis.get_transform()
2269-
inverse_trans = transform.inverted()
2270-
x0, x1 = axis._scale.limit_range_for_scale(
2271-
x0, x1, minpos)
2272-
x0t, x1t = transform.transform([x0, x1])
2273-
delta = (x1t - x0t) * margin
2274-
if do_lower_margin:
2275-
x0t -= delta
2276-
if do_upper_margin:
2277-
x1t += delta
2278-
x0, x1 = inverse_trans.transform([x0t, x1t])
2279-
2280-
if not _tight:
2281-
x0, x1 = locator.view_limits(x0, x1)
2282-
set_bound(x0, x1)
2249+
2250+
if not (scale and autoscaleon):
2251+
return # nothing to do...
2252+
2253+
shared = shared_axes.get_siblings(self)
2254+
dl = [ax.dataLim for ax in shared]
2255+
# ignore non-finite data limits if good limits exist
2256+
finite_dl = [d for d in dl if np.isfinite(d).all()]
2257+
if len(finite_dl):
2258+
dl = finite_dl
2259+
2260+
bb = mtransforms.BboxBase.union(dl)
2261+
x0, x1 = getattr(bb, interval)
2262+
locator = axis.get_major_locator()
2263+
try:
2264+
# e.g., DateLocator has its own nonsingular()
2265+
x0, x1 = locator.nonsingular(x0, x1)
2266+
except AttributeError:
2267+
# Default nonsingular for, e.g., MaxNLocator
2268+
x0, x1 = mtransforms.nonsingular(
2269+
x0, x1, increasing=False, expander=0.05)
2270+
2271+
if margin > 0 and (do_lower_margin or do_upper_margin):
2272+
if axis.get_scale() == 'linear':
2273+
delta = (x1 - x0) * margin
2274+
if do_lower_margin:
2275+
x0 -= delta
2276+
if do_upper_margin:
2277+
x1 += delta
2278+
else:
2279+
# If we have a non-linear scale, we need to
2280+
# add the margin in figure space and then
2281+
# transform back
2282+
minpos = getattr(bb, minpos)
2283+
transform = axis.get_transform()
2284+
inverse_trans = transform.inverted()
2285+
x0, x1 = axis._scale.limit_range_for_scale(
2286+
x0, x1, minpos)
2287+
x0t, x1t = transform.transform([x0, x1])
2288+
delta = (x1t - x0t) * margin
2289+
if do_lower_margin:
2290+
x0t -= delta
2291+
if do_upper_margin:
2292+
x1t += delta
2293+
x0, x1 = inverse_trans.transform([x0t, x1t])
2294+
2295+
if not _tight:
2296+
x0, x1 = locator.view_limits(x0, x1)
2297+
set_bound(x0, x1)
2298+
# End of definition of internal function 'handle_single_axis'.
22832299

22842300
handle_single_axis(
22852301
scalex, self._autoscaleXon, self._shared_x_axes,

lib/matplotlib/backends/backend_pdf.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,12 +1152,12 @@ def alphaState(self, alpha):
11521152
def hatchPattern(self, hatch_style):
11531153
# The colors may come in as numpy arrays, which aren't hashable
11541154
if hatch_style is not None:
1155-
face, edge, hatch = hatch_style
1156-
if face is not None:
1157-
face = tuple(face)
1155+
edge, face, hatch = hatch_style
11581156
if edge is not None:
11591157
edge = tuple(edge)
1160-
hatch_style = (face, edge, hatch)
1158+
if face is not None:
1159+
face = tuple(face)
1160+
hatch_style = (edge, face, hatch)
11611161

11621162
pattern = self.hatchPatterns.get(hatch_style, None)
11631163
if pattern is not None:
@@ -1182,7 +1182,9 @@ def writeHatches(self):
11821182
'PatternType': 1, 'PaintType': 1, 'TilingType': 1,
11831183
'BBox': [0, 0, sidelen, sidelen],
11841184
'XStep': sidelen, 'YStep': sidelen,
1185-
'Resources': res})
1185+
'Resources': res,
1186+
# Change origin to match Agg at top-left.
1187+
'Matrix': [1, 0, 0, 1, 0, self.height * 72]})
11861188

11871189
stroke_rgb, fill_rgb, path = hatch_style
11881190
self.output(stroke_rgb[0], stroke_rgb[1], stroke_rgb[2],
@@ -1195,13 +1197,11 @@ def writeHatches(self):
11951197

11961198
self.output(rcParams['hatch.linewidth'], Op.setlinewidth)
11971199

1198-
# TODO: We could make this dpi-dependent, but that would be
1199-
# an API change
12001200
self.output(*self.pathOperations(
12011201
Path.hatch(path),
12021202
Affine2D().scale(sidelen),
12031203
simplify=False))
1204-
self.output(Op.stroke)
1204+
self.output(Op.fill_stroke)
12051205

12061206
self.endStream()
12071207
self.writeObject(self.hatchObject, hatchDict)

lib/matplotlib/backends/backend_ps.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ def create_hatch(self, hatch):
298298
return self._hatches[hatch]
299299
name = 'H%d' % len(self._hatches)
300300
linewidth = rcParams['hatch.linewidth']
301+
pageheight = self.height * 72
301302
self._pswriter.write("""\
302303
<< /PatternType 1
303304
/PaintType 2
@@ -311,13 +312,15 @@ def create_hatch(self, hatch):
311312
%(linewidth)f setlinewidth
312313
""" % locals())
313314
self._pswriter.write(
314-
self._convert_path(Path.hatch(hatch), Affine2D().scale(72.0),
315+
self._convert_path(Path.hatch(hatch), Affine2D().scale(sidelen),
315316
simplify=False))
316317
self._pswriter.write("""\
317-
stroke
318+
fill
319+
stroke
318320
} bind
319321
>>
320322
matrix
323+
0.0 %(pageheight)f translate
321324
makepattern
322325
/%(name)s exch def
323326
""" % locals())
@@ -854,6 +857,7 @@ def _draw_ps(self, ps, gc, rgbFace, fill=True, stroke=True, command=None):
854857
stroke = stroke and mightstroke
855858
fill = (fill and rgbFace is not None and
856859
(len(rgbFace) <= 3 or rgbFace[3] != 0.0))
860+
hatch = gc.get_hatch()
857861

858862
if mightstroke:
859863
self.set_linewidth(gc.get_linewidth())
@@ -879,19 +883,18 @@ def _draw_ps(self, ps, gc, rgbFace, fill=True, stroke=True, command=None):
879883
write("\n")
880884

881885
if fill:
882-
if stroke:
886+
if stroke or hatch:
883887
write("gsave\n")
884888
self.set_color(store=0, *rgbFace[:3])
885889
write("fill\n")
886-
if stroke:
890+
if stroke or hatch:
887891
write("grestore\n")
888892

889-
hatch = gc.get_hatch()
890893
if hatch:
891894
hatch_name = self.create_hatch(hatch)
892895
write("gsave\n")
893-
write("[/Pattern [/DeviceRGB]] setcolorspace %f %f %f " % gc.get_hatch_color()[:3])
894-
write("%s setcolor fill grestore\n" % hatch_name)
896+
write("%f %f %f " % gc.get_hatch_color()[:3])
897+
write("%s setpattern fill grestore\n" % hatch_name)
895898

896899
if stroke:
897900
write("stroke\n")
6.6 KB
Loading
Binary file not shown.
2.21 KB
Loading
-1.76 KB
Loading

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy