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

Commit4a3537b

Browse files
oscargusjvcsir
authored andcommitted
Merge pull request#24194 from timhoffm/doc-plot-directive
DOC: Improve plot_directive documentation
2 parents40cd821 +a5553e2 commit4a3537b

File tree

3 files changed

+260
-18
lines changed

3 files changed

+260
-18
lines changed
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
"""
2+
===================================
3+
Angle annotations on bracket arrows
4+
===================================
5+
6+
This example shows how to add angle annotations to bracket arrow styles
7+
created using `.FancyArrowPatch`. Angles are annotated using
8+
``AngleAnnotation`` from the example
9+
:doc:`/gallery/text_labels_and_annotations/angle_annotation`.
10+
Additional `.FancyArrowPatch` arrows are added to show the directions of
11+
*angleA* and *angleB*.
12+
"""
13+
14+
#############################################################################
15+
# The ``AngleAnnotation`` class is copied from the
16+
# :doc:`/gallery/text_labels_and_annotations/angle_annotation` example.
17+
18+
importmatplotlib.pyplotasplt
19+
importnumpyasnp
20+
frommatplotlib.patchesimportArc,FancyArrowPatch
21+
frommatplotlib.transformsimportBbox,IdentityTransform,TransformedBbox
22+
23+
24+
classAngleAnnotation(Arc):
25+
"""
26+
Draws an arc between two vectors which appears circular in display space.
27+
"""
28+
def__init__(self,xy,p1,p2,size=75,unit="points",ax=None,
29+
text="",textposition="inside",text_kw=None,**kwargs):
30+
"""
31+
Parameters
32+
----------
33+
xy, p1, p2 : tuple or array of two floats
34+
Center position and two points. Angle annotation is drawn between
35+
the two vectors connecting *p1* and *p2* with *xy*, respectively.
36+
Units are data coordinates.
37+
38+
size : float
39+
Diameter of the angle annotation in units specified by *unit*.
40+
41+
unit : str
42+
One of the following strings to specify the unit of *size*:
43+
44+
* "pixels": pixels
45+
* "points": points, use points instead of pixels to not have a
46+
dependence on the DPI
47+
* "axes width", "axes height": relative units of Axes width, height
48+
* "axes min", "axes max": minimum or maximum of relative Axes
49+
width, height
50+
51+
ax : `matplotlib.axes.Axes`
52+
The Axes to add the angle annotation to.
53+
54+
text : str
55+
The text to mark the angle with.
56+
57+
textposition : {"inside", "outside", "edge"}
58+
Whether to show the text in- or outside the arc. "edge" can be used
59+
for custom positions anchored at the arc's edge.
60+
61+
text_kw : dict
62+
Dictionary of arguments passed to the Annotation.
63+
64+
**kwargs
65+
Further parameters are passed to `matplotlib.patches.Arc`. Use this
66+
to specify, color, linewidth etc. of the arc.
67+
68+
"""
69+
self.ax=axorplt.gca()
70+
self._xydata=xy# in data coordinates
71+
self.vec1=p1
72+
self.vec2=p2
73+
self.size=size
74+
self.unit=unit
75+
self.textposition=textposition
76+
77+
super().__init__(self._xydata,size,size,angle=0.0,
78+
theta1=self.theta1,theta2=self.theta2,**kwargs)
79+
80+
self.set_transform(IdentityTransform())
81+
self.ax.add_patch(self)
82+
83+
self.kw=dict(ha="center",va="center",
84+
xycoords=IdentityTransform(),
85+
xytext=(0,0),textcoords="offset points",
86+
annotation_clip=True)
87+
self.kw.update(text_kwor {})
88+
self.text=ax.annotate(text,xy=self._center,**self.kw)
89+
90+
defget_size(self):
91+
factor=1.
92+
ifself.unit=="points":
93+
factor=self.ax.figure.dpi/72.
94+
elifself.unit[:4]=="axes":
95+
b=TransformedBbox(Bbox.unit(),self.ax.transAxes)
96+
dic= {"max":max(b.width,b.height),
97+
"min":min(b.width,b.height),
98+
"width":b.width,"height":b.height}
99+
factor=dic[self.unit[5:]]
100+
returnself.size*factor
101+
102+
defset_size(self,size):
103+
self.size=size
104+
105+
defget_center_in_pixels(self):
106+
"""return center in pixels"""
107+
returnself.ax.transData.transform(self._xydata)
108+
109+
defset_center(self,xy):
110+
"""set center in data coordinates"""
111+
self._xydata=xy
112+
113+
defget_theta(self,vec):
114+
vec_in_pixels=self.ax.transData.transform(vec)-self._center
115+
returnnp.rad2deg(np.arctan2(vec_in_pixels[1],vec_in_pixels[0]))
116+
117+
defget_theta1(self):
118+
returnself.get_theta(self.vec1)
119+
120+
defget_theta2(self):
121+
returnself.get_theta(self.vec2)
122+
123+
defset_theta(self,angle):
124+
pass
125+
126+
# Redefine attributes of the Arc to always give values in pixel space
127+
_center=property(get_center_in_pixels,set_center)
128+
theta1=property(get_theta1,set_theta)
129+
theta2=property(get_theta2,set_theta)
130+
width=property(get_size,set_size)
131+
height=property(get_size,set_size)
132+
133+
# The following two methods are needed to update the text position.
134+
defdraw(self,renderer):
135+
self.update_text()
136+
super().draw(renderer)
137+
138+
defupdate_text(self):
139+
c=self._center
140+
s=self.get_size()
141+
angle_span= (self.theta2-self.theta1)%360
142+
angle=np.deg2rad(self.theta1+angle_span/2)
143+
r=s/2
144+
ifself.textposition=="inside":
145+
r=s/np.interp(angle_span, [60,90,135,180],
146+
[3.3,3.5,3.8,4])
147+
self.text.xy=c+r*np.array([np.cos(angle),np.sin(angle)])
148+
ifself.textposition=="outside":
149+
defR90(a,r,w,h):
150+
ifa<np.arctan(h/2/(r+w/2)):
151+
returnnp.sqrt((r+w/2)**2+ (np.tan(a)*(r+w/2))**2)
152+
else:
153+
c=np.sqrt((w/2)**2+(h/2)**2)
154+
T=np.arcsin(c*np.cos(np.pi/2-a+np.arcsin(h/2/c))/r)
155+
xy=r*np.array([np.cos(a+T),np.sin(a+T)])
156+
xy+=np.array([w/2,h/2])
157+
returnnp.sqrt(np.sum(xy**2))
158+
159+
defR(a,r,w,h):
160+
aa= (a% (np.pi/4))*((a% (np.pi/2))<=np.pi/4)+ \
161+
(np.pi/4- (a% (np.pi/4)))*((a% (np.pi/2))>=np.pi/4)
162+
returnR90(aa,r,*[w,h][::int(np.sign(np.cos(2*a)))])
163+
164+
bbox=self.text.get_window_extent()
165+
X=R(angle,r,bbox.width,bbox.height)
166+
trans=self.ax.figure.dpi_scale_trans.inverted()
167+
offs=trans.transform(((X-s/2),0))[0]*72
168+
self.text.set_position([offs*np.cos(angle),offs*np.sin(angle)])
169+
170+
171+
#############################################################################
172+
# The plot is generatd with the following code.
173+
174+
defget_point_of_rotated_vertical(origin,line_length,degrees):
175+
"""Return xy coordinates of the vertical line end rotated by degrees."""
176+
rad=np.deg2rad(-degrees)
177+
return [origin[0]+line_length*np.sin(rad),
178+
origin[1]+line_length*np.cos(rad)]
179+
180+
181+
fig,ax=plt.subplots(figsize=(8,7))
182+
ax.set(xlim=(0,6),ylim=(-1,4))
183+
ax.set_title('Angle annotations on bracket arrows')
184+
185+
fori,stylenameinenumerate(["]-[","|-|"]):
186+
forj,angleinenumerate([-40,60]):
187+
y=2*i+j
188+
arrow_centers= [(1,y), (5,y)]
189+
vlines= [[c[0],y+0.5]forcinarrow_centers]
190+
widths="widthA=1.5,widthB=1.5"
191+
arrowstyle=f"{stylename},{widths},angleA={angle},angleB={-angle}"
192+
patch=FancyArrowPatch(arrow_centers[0],arrow_centers[1],
193+
arrowstyle=arrowstyle,mutation_scale=25)
194+
ax.add_patch(patch)
195+
ax.text(3,y+0.05,arrowstyle.replace(f"{widths},",""),
196+
verticalalignment="bottom",horizontalalignment="center")
197+
ax.vlines([i[0]foriinvlines], [y,y], [i[1]foriinvlines],
198+
linestyles="--",color="C0")
199+
# Get the coordinates for the drawn patches at A and B
200+
patch_top_coords= [
201+
get_point_of_rotated_vertical(arrow_centers[0],0.5,angle),
202+
get_point_of_rotated_vertical(arrow_centers[1],0.5,-angle)
203+
]
204+
# Create points for annotating A and B with AngleAnnotation
205+
# Points include the top of the vline and patch_top_coords
206+
pointsA= [(1,y+0.5),patch_top_coords[0]]
207+
pointsB= [patch_top_coords[1], (5,y+0.5)]
208+
# Define the directions for the arrows for AngleAnnotation
209+
arrow_angles= [0.5,-0.5]
210+
# Reverse the points and arrow_angles when the angle is negative
211+
ifangle<0:
212+
pointsA.reverse()
213+
pointsB.reverse()
214+
arrow_angles.reverse()
215+
# Add AngleAnnotation and arrows to show angle directions
216+
data=zip(arrow_centers, [pointsA,pointsB],vlines,arrow_angles,
217+
patch_top_coords)
218+
forcenter,points,vline,arrow_angle,patch_topindata:
219+
am=AngleAnnotation(center,points[0],points[1],ax=ax,
220+
size=0.25,unit="axes min",text=str(-angle))
221+
arrowstyle="Simple, tail_width=0.5, head_width=4, head_length=8"
222+
kw=dict(arrowstyle=arrowstyle,color="C0")
223+
arrow=FancyArrowPatch(vline,patch_top,
224+
connectionstyle=f"arc3,rad={arrow_angle}",
225+
**kw)
226+
ax.add_patch(arrow)
227+
228+
229+
#############################################################################
230+
#
231+
# .. admonition:: References
232+
#
233+
# The use of the following functions, methods, classes and modules is shown
234+
# in this example:
235+
#
236+
# - `matplotlib.patches.ArrowStyle`

‎lib/matplotlib/patches.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3119,6 +3119,10 @@ class ArrowStyle(_Style):
31193119
stroked. This is meant to be used to correct the location of the
31203120
head so that it does not overshoot the destination point, but not all
31213121
classes support it.
3122+
3123+
Examples
3124+
--------
3125+
.. plot:: gallery/text_labels_and_annotations/angles_on_bracket_arrows.py
31223126
"""
31233127

31243128
_style_list= {}

‎lib/matplotlib/sphinxext/plot_directive.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
A directive for including a Matplotlib plot in a Sphinx document
33
================================================================
44
5-
By default, in HTML output, `plot` will include a .png file with alink to a
6-
high-res .png and .pdf. In LaTeX output, it will include a .pdf.
5+
This is a Sphinx extension providing areStructuredText directive
6+
``.. plot::`` for including a plot in a Sphinx document.
77
8-
The source code for the plot may be included in one of three ways:
8+
In HTML output, ``.. plot::`` will include a .png file with a link
9+
to a high-res .png and .pdf. In LaTeX output, it will include a .pdf.
10+
11+
The plot content may be defined in one of three ways:
912
1013
1. **A path to a source file** as the argument to the directive::
1114
@@ -28,10 +31,8 @@
2831
.. plot::
2932
3033
import matplotlib.pyplot as plt
31-
import matplotlib.image as mpimg
32-
import numpy as np
33-
img = mpimg.imread('_static/stinkbug.png')
34-
imgplot = plt.imshow(img)
34+
plt.plot([1, 2, 3], [4, 5, 6])
35+
plt.title("A plotting exammple")
3536
3637
3. Using **doctest** syntax::
3738
@@ -44,22 +45,22 @@
4445
Options
4546
-------
4647
47-
The ``plot`` directive supports the following options:
48+
The ``..plot::`` directive supports the following options:
4849
49-
format : {'python', 'doctest'}
50+
``:format:`` : {'python', 'doctest'}
5051
The format of the input. If unset, the format is auto-detected.
5152
52-
include-source : bool
53+
``:include-source:`` : bool
5354
Whether to display the source code. The default can be changed using
54-
the `plot_include_source` variable in :file:`conf.py` (which itself
55+
the ``plot_include_source`` variable in :file:`conf.py` (which itself
5556
defaults to False).
5657
57-
encoding : str
58+
``:encoding:`` : str
5859
If this source file is in a non-UTF8 or non-ASCII encoding, the
5960
encoding must be specified using the ``:encoding:`` option. The
6061
encoding will not be inferred using the ``-*- coding -*-`` metacomment.
6162
62-
context : bool or str
63+
``:context:`` : bool or str
6364
If provided, the code will be run in the context of all previous plot
6465
directives for which the ``:context:`` option was specified. This only
6566
applies to inline code plot directives, not those run from files. If
@@ -68,18 +69,19 @@
6869
running the code. ``:context: close-figs`` keeps the context but closes
6970
previous figures before running the code.
7071
71-
nofigs : bool
72+
``:nofigs:`` : bool
7273
If specified, the code block will be run, but no figures will be
7374
inserted. This is usually useful with the ``:context:`` option.
7475
75-
caption : str
76+
``:caption:`` : str
7677
If specified, the option's argument will be used as a caption for the
7778
figure. This overwrites the caption given in the content, when the plot
7879
is generated from a file.
7980
80-
Additionally, this directive supports all of the options of the `image`
81-
directive, except for *target* (since plot will add its own target). These
82-
include *alt*, *height*, *width*, *scale*, *align* and *class*.
81+
Additionally, this directive supports all the options of the `image directive
82+
<https://docutils.sourceforge.io/docs/ref/rst/directives.html#image>`_,
83+
except for ``:target:`` (since plot will add its own target). These include
84+
``:alt:``, ``:height:``, ``:width:``, ``:scale:``, ``:align:`` and ``:class:``.
8385
8486
Configuration options
8587
---------------------

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp