Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite0c6e1e

Browse files
story645anntzer
andcommitted
adds path.effects rcparam support for list of (funcname, {**kwargs})
adds new path.effects validationcreated xkcd.mplstyle and shimmed it into plt.xkcd()Co-authored-by: Antony Lee <anntzer.lee@gmail.com>
1 parentc16d7db commite0c6e1e

File tree

8 files changed

+163
-25
lines changed

8 files changed

+163
-25
lines changed

‎lib/matplotlib/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
fromcollectionsimportnamedtuple
138138
fromcollections.abcimportMutableMapping
139139
importcontextlib
140+
importcopy
140141
importfunctools
141142
importimportlib
142143
importinspect
@@ -163,7 +164,6 @@
163164
frommatplotlib._apiimportMatplotlibDeprecationWarning
164165
frommatplotlib.rcsetupimportvalidate_backend,cycler
165166

166-
167167
_log=logging.getLogger(__name__)
168168

169169
__bibtex__=r"""@Article{Hunter:2007,
@@ -764,6 +764,14 @@ def __getitem__(self, key):
764764
frommatplotlibimportpyplotasplt
765765
plt.switch_backend(rcsetup._auto_backend_sentinel)
766766

767+
elifkey=="path.effects"andselfisglobals().get("rcParams"):
768+
# defers loading of patheffects to avoid circular imports
769+
importmatplotlib.patheffectsaspath_effects
770+
771+
return [peifisinstance(pe,path_effects.AbstractPathEffect)
772+
elsegetattr(path_effects,pe[0])(**pe[1])
773+
forpeinself._get('path.effects')]
774+
767775
returnself._get(key)
768776

769777
def_get_backend_or_none(self):

‎lib/matplotlib/mpl-data/matplotlibrc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,10 @@
677677
# line (in pixels).
678678
# - *randomness* is the factor by which the length is
679679
# randomly scaled.
680-
#path.effects:
680+
#path.effects: # patheffects functions, args, and, kwargs, e.g
681+
# {'name': 'withStroke', 'linewidth': 4},
682+
# {'name': 'SimpleLineShadow'}
683+
681684

682685

683686
## ***************************************************************************
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
## default xkcd style
2+
3+
# line
4+
lines.linewidth : 2.0
5+
6+
# font
7+
font.family : xkcd, xkcd Script, Humor Sans, Comic Neue, Comic Sans MS
8+
font.size : 14.0
9+
10+
# axes
11+
axes.linewidth : 1.5
12+
axes.grid : False
13+
axes.unicode_minus: False
14+
axes.edgecolor: black
15+
16+
# ticks
17+
xtick.major.size : 8
18+
xtick.major.width: 3
19+
ytick.major.size : 8
20+
ytick.major.width: 3
21+
22+
# grids
23+
grid.linewidth: 0.0
24+
25+
# figure
26+
figure.facecolor: white
27+
28+
# path
29+
path.sketch : 1, 100, 2
30+
path.effects: ('withStroke', {'linewidth': 4, 'foreground': 'w' })

‎lib/matplotlib/pyplot.py

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -747,27 +747,8 @@ def xkcd(
747747
stack=ExitStack()
748748
stack.callback(dict.update,rcParams,rcParams.copy())# type: ignore
749749

750-
frommatplotlibimportpatheffects
751-
rcParams.update({
752-
'font.family': ['xkcd','xkcd Script','Humor Sans','Comic Neue',
753-
'Comic Sans MS'],
754-
'font.size':14.0,
755-
'path.sketch': (scale,length,randomness),
756-
'path.effects': [
757-
patheffects.withStroke(linewidth=4,foreground="w")],
758-
'axes.linewidth':1.5,
759-
'lines.linewidth':2.0,
760-
'figure.facecolor':'white',
761-
'grid.linewidth':0.0,
762-
'axes.grid':False,
763-
'axes.unicode_minus':False,
764-
'axes.edgecolor':'black',
765-
'xtick.major.size':8,
766-
'xtick.major.width':3,
767-
'ytick.major.size':8,
768-
'ytick.major.width':3,
769-
})
770-
750+
rcParams.update({**style.library["xkcd"],
751+
'path.sketch': (scale,length,randomness)})
771752
returnstack
772753

773754

‎lib/matplotlib/rcsetup.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,42 @@ def validate_sketch(s):
565565
raiseValueError("Expected a (scale, length, randomness) triplet")
566566

567567

568+
defvalidate_path_effects(s):
569+
ifnots:
570+
return []
571+
572+
ifisinstance(s,str)ands.strip().startswith("("):
573+
s=ast.literal_eval(s)
574+
575+
_validate_name=ValidateInStrings("path.effects.function",
576+
["Normal",
577+
"PathPatchEffect",
578+
"SimpleLineShadow",
579+
"SimplePatchShadow",
580+
"Stroke",
581+
"TickedStroke",
582+
"withSimplePatchShadow",
583+
"withStroke",
584+
"withTickedStroke"])
585+
586+
def_validate_dict(d):
587+
ifnotisinstance(d,dict):
588+
raiseValueError("Expected a dictionary of keyword arguments")
589+
returnd
590+
591+
try:
592+
# cast to list for the 1 tuple case
593+
s= [s]ifisinstance(s[0],str)elses
594+
return [peifgetattr(pe,'__module__',"")=='matplotlib.patheffects'
595+
else (_validate_name(pe[0].strip()),
596+
{}iflen(pe)<2else_validate_dict(pe[1]))
597+
forpeinvalidate_anylist(s)
598+
]
599+
exceptTypeErrorase:
600+
raiseValueError("Expected a list of patheffects functions"
601+
" or (funcname, {**kwargs}) tuples")
602+
603+
568604
def_validate_greaterthan_minushalf(s):
569605
s=validate_float(s)
570606
ifs>-0.5:
@@ -1290,7 +1326,7 @@ def _convert_validator_spec(key, conv):
12901326
"path.simplify_threshold":_validate_greaterequal0_lessequal1,
12911327
"path.snap":validate_bool,
12921328
"path.sketch":validate_sketch,
1293-
"path.effects":validate_anylist,
1329+
"path.effects":validate_path_effects,
12941330
"agg.path.chunksize":validate_int,# 0 to disable chunking
12951331

12961332
# key-mappings (multi-character mappings should be a list/tuple)

‎lib/matplotlib/rcsetup.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ from cycler import Cycler
22

33
fromcollections.abcimportCallable,Iterable
44
fromtypingimportAny,Literal,TypeVar
5+
frommatplotlib.patheffectsimportAbstractPathEffect
56
frommatplotlib.typingimportColorType,LineStyleType,MarkEveryType
67

78
interactive_bk:list[str]
@@ -140,6 +141,8 @@ def _validate_linestyle(s: Any) -> LineStyleType: ...
140141
defvalidate_markeverylist(s:Any)->list[MarkEveryType]: ...
141142
defvalidate_bbox(s:Any)->Literal["tight","standard"]|None: ...
142143
defvalidate_sketch(s:Any)->None|tuple[float,float,float]: ...
144+
defvalidate_path_effects(s:str|list[AbstractPathEffect,Tuple[str,dict]])
145+
->list[AbstractPathEffect| [Tuple[str,dict]]]: ...
143146
defvalidate_hatch(s:Any)->str: ...
144147
defvalidate_hatchlist(s:Any)->list[str]: ...
145148
defvalidate_dashlist(s:Any)->list[list[float]]: ...

‎lib/matplotlib/tests/test_rcparams.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
frommatplotlibimport_api,_c_internal_utils
1313
importmatplotlib.pyplotasplt
1414
importmatplotlib.colorsasmcolors
15+
importmatplotlib.patheffectsaspath_effects
16+
frommatplotlib.testing.decoratorsimportcheck_figures_equal
17+
1518
importnumpyasnp
1619
frommatplotlib.rcsetupimport (
1720
validate_bool,
@@ -27,8 +30,10 @@
2730
validate_int,
2831
validate_markevery,
2932
validate_stringlist,
33+
validate_path_effects,
3034
_validate_linestyle,
31-
_listify_validator)
35+
_listify_validator,
36+
)
3237

3338

3439
deftest_rcparams(tmpdir):
@@ -628,3 +633,62 @@ def test_rcparams_legend_loc_from_file(tmpdir, value):
628633

629634
withmpl.rc_context(fname=rc_path):
630635
assertmpl.rcParams["legend.loc"]==value
636+
637+
ped= [('Normal', {}),
638+
('Stroke', {'offset': (1,2)}),
639+
('withStroke', {'linewidth':4,'foreground':'w'})]
640+
641+
pel= [path_effects.Normal(),
642+
path_effects.Stroke((1,2)),
643+
path_effects.withStroke(linewidth=4,foreground='w')]
644+
645+
646+
@pytest.mark.parametrize("value", [pel,ped],ids=["func","dict"])
647+
deftest_path_effects(value):
648+
assertvalidate_path_effects(value)==value
649+
forvinvalue:
650+
assertvalidate_path_effects(value)==value
651+
652+
653+
deftest_path_effects_string():
654+
"""test list of dicts properly parsed"""
655+
pstr="('Normal', ), "
656+
pstr+="('Stroke', {'offset': (1, 2)}),"
657+
pstr+="('withStroke', {'linewidth': 4, 'foreground': 'w'})"
658+
assertvalidate_path_effects(pstr)==ped
659+
660+
661+
@pytest.mark.parametrize("fdict, flist",
662+
[([ped[0]], [pel[0]]),
663+
([ped[1]], [pel[1]]),
664+
([ped[2]], [ped[2]]),
665+
(ped,pel)],
666+
ids=['function','args','kwargs','all'])
667+
@check_figures_equal()
668+
deftest_path_effects_picture(fig_test,fig_ref,fdict,flist):
669+
withmpl.rc_context({'path.effects':fdict}):
670+
fig_test.subplots().plot([1,2,3])
671+
672+
withmpl.rc_context({'path.effects':flist}):
673+
fig_ref.subplots().plot([1,2,3])
674+
675+
676+
@pytest.mark.parametrize("s, msg", [
677+
([1,2,3],"Expected a list of patheffects .*"),
678+
(("Happy", ),r".* \'Happy\' is not a valid value for path\.effects\.function.*"),
679+
(("Normal", [1,2,3]),r"Expected a dictionary .*"),])
680+
deftest_path_effect_errors(s,msg):
681+
withpytest.raises(ValueError,match=msg):
682+
mpl.rcParams['path.effects']=s
683+
684+
685+
deftest_path_effects_from_file(tmpdir):
686+
# rcParams['legend.loc'] should be settable from matplotlibrc.
687+
# if any of these are not allowed, an exception will be raised.
688+
# test for gh issue #22338
689+
rc_path=tmpdir.join("matplotlibrc")
690+
rc_path.write("path.effects: ('Normal', {}), ('withStroke', {'linewidth': 2})")
691+
692+
withmpl.rc_context(fname=rc_path):
693+
assertisinstance(mpl.rcParams["path.effects"][0],path_effects.Normal)
694+
assertisinstance(mpl.rcParams["path.effects"][1],path_effects.withStroke)

‎lib/matplotlib/tests/test_style.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
importmatplotlibasmpl
1010
frommatplotlibimportpyplotasplt,style
11+
frommatplotlib.testing.decoratorsimportcheck_figures_equal
1112
frommatplotlib.style.coreimportUSER_LIBRARY_PATHS,STYLE_EXTENSION
1213

1314

@@ -177,6 +178,18 @@ def test_xkcd_cm():
177178
assertmpl.rcParams["path.sketch"]isNone
178179

179180

181+
@check_figures_equal()
182+
deftest_xkcd_style(fig_test,fig_ref):
183+
184+
withstyle.context('xkcd'):
185+
fig_test.subplots().plot([1,2,3])
186+
fig_test.text(.5,.5,"Hello World!")
187+
188+
withplt.xkcd():
189+
fig_ref.subplots().plot([1,2,3])
190+
fig_ref.text(.5,.5,"Hello World!")
191+
192+
180193
deftest_up_to_date_blacklist():
181194
assertmpl.style.core.STYLE_BLACKLIST<= {*mpl.rcsetup._validators}
182195

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp