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

Commiteae36f5

Browse files
committed
Draw RadioButtons using scatter to ensure circular buttons.
To ensure backcompat without bothering the majority of users who don'tactually access the .circles attribute, dynamically (and irreversibly)switch back to the old draw method (list of Circles) whenever thatattribute is accessed for the first time (if ever).
1 parent1fa7467 commiteae36f5

File tree

4 files changed

+57
-51
lines changed

4 files changed

+57
-51
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
``RadioButtons.circles``
2+
~~~~~~~~~~~~~~~~~~~~~~~~
3+
... is deprecated. (RadioButtons now draws itself using `~.Axes.scatter`.)
Binary file not shown.

‎lib/matplotlib/tests/test_widgets.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,18 +1003,21 @@ def test_check_radio_buttons_image():
10031003
plt.subplots_adjust(left=0.3)
10041004
rax1=plt.axes([0.05,0.7,0.15,0.15])
10051005
rax2=plt.axes([0.05,0.2,0.15,0.15])
1006-
widgets.RadioButtons(rax1, ('Radio 1','Radio 2','Radio 3'))
1006+
rb=widgets.RadioButtons(rax1, ('Radio 1','Radio 2','Radio 3'))
1007+
withpytest.warns(DeprecationWarning):
1008+
rb.circles# Trigger the old-style elliptic radiobuttons.
10071009
widgets.CheckButtons(rax2, ('Check 1','Check 2','Check 3'),
10081010
(False,True,True))
10091011

10101012

1011-
@image_comparison(['check_bunch_of_radio_buttons.png'],
1012-
style='mpl20',remove_text=True)
1013-
deftest_check_bunch_of_radio_buttons():
1014-
rax=plt.axes([0.05,0.1,0.15,0.7])
1015-
widgets.RadioButtons(rax, ('B1','B2','B3','B4','B5','B6',
1016-
'B7','B8','B9','B10','B11','B12',
1017-
'B13','B14','B15'))
1013+
@check_figures_equal(extensions=["png"])
1014+
deftest_radio_buttons(fig_test,fig_ref):
1015+
widgets.RadioButtons(fig_test.subplots(), ["tea","coffee"])
1016+
ax=fig_ref.add_subplot(xticks=[],yticks=[])
1017+
ax.scatter([.15,.15], [2/3,1/3],transform=ax.transAxes,
1018+
s=(plt.rcParams["font.size"]/2)**2,c=["C0","none"])
1019+
ax.text(.25,2/3,"tea",transform=ax.transAxes,va="center")
1020+
ax.text(.25,1/3,"coffee",transform=ax.transAxes,va="center")
10181021

10191022

10201023
deftest_slider_slidermin_slidermax_invalid():

‎lib/matplotlib/widgets.py

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,41 +1404,23 @@ def __init__(self, ax, labels, active=0, activecolor='blue'):
14041404
"""
14051405
super().__init__(ax)
14061406
self.activecolor=activecolor
1407-
self.value_selected=None
1407+
self.value_selected=labels[active]
14081408

14091409
ax.set_xticks([])
14101410
ax.set_yticks([])
14111411
ax.set_navigate(False)
1412-
dy=1./ (len(labels)+1)
1413-
ys=np.linspace(1-dy,dy,len(labels))
1414-
cnt=0
1415-
axcolor=ax.get_facecolor()
1416-
1417-
# scale the radius of the circle with the spacing between each one
1418-
circle_radius=dy/2-0.01
1419-
# default to hard-coded value if the radius becomes too large
1420-
circle_radius=min(circle_radius,0.05)
1421-
1422-
self.labels= []
1423-
self.circles= []
1424-
fory,labelinzip(ys,labels):
1425-
t=ax.text(0.25,y,label,transform=ax.transAxes,
1426-
horizontalalignment='left',
1427-
verticalalignment='center')
14281412

1429-
ifcnt==active:
1430-
self.value_selected=label
1431-
facecolor=activecolor
1432-
else:
1433-
facecolor=axcolor
1413+
ys=np.linspace(1,0,len(labels)+2)[1:-1]
1414+
text_size=mpl.rcParams["font.size"]/2
14341415

1435-
p=Circle(xy=(0.15,y),radius=circle_radius,edgecolor='black',
1436-
facecolor=facecolor,transform=ax.transAxes)
1437-
1438-
self.labels.append(t)
1439-
self.circles.append(p)
1440-
ax.add_patch(p)
1441-
cnt+=1
1416+
self.labels= [
1417+
ax.text(0.25,y,label,transform=ax.transAxes,
1418+
horizontalalignment="left",verticalalignment="center")
1419+
fory,labelinzip(ys,labels)]
1420+
self._buttons=ax.scatter(
1421+
[.15]*len(ys),ys,transform=ax.transAxes,s=text_size**2,
1422+
c=[activecolorifi==activeelse"none"foriinrange(len(ys))],
1423+
edgecolor="black")
14421424

14431425
self.connect_event('button_press_event',self._clicked)
14441426

@@ -1448,11 +1430,20 @@ def _clicked(self, event):
14481430
ifself.ignore(event)orevent.button!=1orevent.inaxes!=self.ax:
14491431
return
14501432
pclicked=self.ax.transAxes.inverted().transform((event.x,event.y))
1433+
_,inds=self._buttons.contains(event)
1434+
coords=self._buttons.get_offset_transform().transform(
1435+
self._buttons.get_offsets())
14511436
distances= {}
1452-
fori, (p,t)inenumerate(zip(self.circles,self.labels)):
1453-
if (t.get_window_extent().contains(event.x,event.y)
1454-
ornp.linalg.norm(pclicked-p.center)<p.radius):
1455-
distances[i]=np.linalg.norm(pclicked-p.center)
1437+
ifhasattr(self,"_circles"):# Remove once circles is removed.
1438+
fori, (p,t)inenumerate(zip(self._circles,self.labels)):
1439+
if (t.get_window_extent().contains(event.x,event.y)
1440+
ornp.linalg.norm(pclicked-p.center)<p.radius):
1441+
distances[i]=np.linalg.norm(pclicked-p.center)
1442+
else:
1443+
fori,tinenumerate(self.labels):
1444+
if (iininds["ind"]
1445+
ort.get_window_extent().contains(event.x,event.y)):
1446+
distances[i]=np.linalg.norm(pclicked-coords[i])
14561447
iflen(distances)>0:
14571448
closest=min(distances,key=distances.get)
14581449
self.set_active(closest)
@@ -1465,19 +1456,14 @@ def set_active(self, index):
14651456
"""
14661457
ifindexnotinrange(len(self.labels)):
14671458
raiseValueError(f'Invalid RadioButton index:{index}')
1468-
14691459
self.value_selected=self.labels[index].get_text()
1470-
1471-
fori,pinenumerate(self.circles):
1472-
ifi==index:
1473-
color=self.activecolor
1474-
else:
1475-
color=self.ax.get_facecolor()
1476-
p.set_facecolor(color)
1477-
1460+
self._buttons.get_facecolor()[:]=colors.to_rgba("none")
1461+
self._buttons.get_facecolor()[index]=colors.to_rgba(self.activecolor)
1462+
ifhasattr(self,"_circles"):# Remove once circles is removed.
1463+
fori,pinenumerate(self._circles):
1464+
p.set_facecolor(self.activecolorifi==indexelse"none")
14781465
ifself.drawon:
14791466
self.ax.figure.canvas.draw()
1480-
14811467
ifself.eventson:
14821468
self._observers.process('clicked',self.labels[index].get_text())
14831469

@@ -1493,6 +1479,20 @@ def disconnect(self, cid):
14931479
"""Remove the observer with connection id *cid*."""
14941480
self._observers.disconnect(cid)
14951481

1482+
@_api.deprecated("3.7")
1483+
@property
1484+
defcircles(self):
1485+
radius=min(.5/ (len(self.labels)+1)-.01,.05)
1486+
circles=self._circles= [
1487+
Circle(xy=self._buttons.get_offsets()[i],edgecolor="black",
1488+
facecolor=self._buttons.get_facecolor()[i],
1489+
radius=radius,transform=self.ax.transAxes)
1490+
foriinrange(len(self.labels))]
1491+
self._buttons.set_visible(False)
1492+
forcircleinself._circles:
1493+
self.ax.add_patch(circle)
1494+
returncircles
1495+
14961496

14971497
classSubplotTool(Widget):
14981498
"""

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp