import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib.patches as patches
import matplotlib.gridspec as gridspec
from matplotlib.colors import ListedColormap
#色の準備
col_L = "dodgerblue"
col_R = "coral"
#紙の準備
fig = plt.figure()
fig.suptitle("2007東大数学 理系第6問",
color="0.5",ha="right",x=0.96,y=0.96)
fig.subplots_adjust(left=0.0,right=1.0,bottom=0.05,top=1.0)
gs = gridspec.GridSpec(4,30,height_ratios=[5,1,1,1],wspace=0.0,hspace=0.0)
ax1d = fig.add_subplot(gs[2:, 1:10])
ax2d = fig.add_subplot(gs[1:,12:17])
ax3d = fig.add_subplot(gs[2:,19:30])
ax2u = fig.add_subplot(gs[:1, 2:10])
ax4u = fig.add_subplot(gs[:1,11:19])
ax6u = fig.add_subplot(gs[:1,20:28])
#数式スペースの準備
for ax,width,height in zip([ax1d,ax2d,ax3d],[9,5,11],[4,6,4]):
ax.set_xlim(0,width)
ax.set_ylim(-height,0)
ax.axis("off")
#グラフスペースの準備
areadic = dict(fc="none",ec="0.4",hatch="....")
memoridic = dict(color="0.3",size=8,ha="center",va="center")
wbgs = []
for ax in [ax2u,ax4u,ax6u]:
ax.set_xlim(0.75,2.25)
ax.set_ylim(-0.4,1.2)
ax.set_aspect("equal")
ax.axes.xaxis.set_visible(False)
ax.axes.yaxis.set_visible(False)
ax.spines["top"].set_visible(False)
ax.spines["left"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.spines["bottom"].set_color("0.5")
ax.spines["bottom"].set_linewidth(0.7)
ax.spines["bottom"].set_position(("data",0))
ax.plot(1,0,">",color="0.5",markersize=4,transform=ax.get_yaxis_transform(),clip_on=False)
xw = np.linspace(0.75,2.25)
ax.plot(xw,1/xw,color="0.5",lw=0.7)
xs = np.linspace(1,2)
ax.text(1,-0.1,"$1$",**memoridic)
ax.text(2,-0.1,"$2$",**memoridic)
if ax == ax4u:
area = ax.fill_between(xs,1/xs,0,**areadic,zorder=100,alpha=0)
ax.text(1.4,0.8,"$y=\\dfrac{1}{x}$",color="0.3")
else:
ax.fill_between(xs,1/xs,0,**areadic)
ax.text(1.5,-0.1,"$\\frac{3}{2}$",**memoridic)
ax.set_visible(False)
wbg = patches.Rectangle((0.5,-3),2.2,4.3,fc="w",clip_on=False,zorder=90,alpha=0)
wbgs.append(wbg)
ax.add_patch(wbg)
#動かせる図形たちを描きます
wakudic = dict(fc="none",hatch="////",linewidth=1.5,zorder=100,alpha=0)
kagedic = dict(clip_on=False,alpha=0)
vL1 = [(1,0),(1.5,0),(1.5,4/5-4/25),(1,4/5+4/25)]
vL2 = [(1.5,0),(2,0),(2,4/7-4/49),(1.5,4/7+4/49)]
vL1a = [(1,0),(1.5,0),(1.5,4/5-4/25),(1.25,4/5),(1,4/5)]
vL1b = [(1.25,4/5),(1,4/5),(1,4/5+4/25)]
vL2a = [(1.5,0),(2,0),(2,4/7-4/49),(1.75,4/7),(1.5,4/7)]
vL2b = [(1.75,4/7),(1.5,4/7),(1.5,4/7+4/49)]
L1w = patches.Polygon(vL1,**wakudic)
L2w = patches.Polygon(vL2,**wakudic)
L1a = patches.Polygon(vL1a,**kagedic)
L1b = patches.Polygon(vL1b,**kagedic)
L2a = patches.Polygon(vL2a,**kagedic)
L2b = patches.Polygon(vL2b,**kagedic)
for L in [L1w,L2w]:
L.set_edgecolor(col_L)
ax2u.add_patch(L)
for L in [L1a,L1b,L2a,L2b]:
L.set_facecolor(col_L)
ax2u.add_patch(L)
vR1 = [(1,0),(1.5,0),(1.5,2/3),(1,1)]
vR2 = [(1.5,0),(2,0),(2,1/2),(1.5,2/3)]
R1w = patches.Polygon(vR1,**wakudic)
R2w = patches.Polygon(vR2,**wakudic)
R1k = patches.Polygon(vR1,**kagedic)
R2k = patches.Polygon(vR2,**kagedic)
for R in [R1w,R2w]:
R.set_edgecolor(col_R)
ax6u.add_patch(R)
for R in [R1k,R2k]:
R.set_facecolor(col_R)
ax6u.add_patch(R)
#長さ表記を準備
pdic = dict(color="0.6",linewidth=1,zorder=-10,clip_on=False,alpha=0)
tdic = dict(color="0.3",ha="center",va="center",alpha=0)
Rdic = dict(fc="w",clip_on=False,visible=False,zorder=-10)
class Length:
def __init__(self,ax):
self.ax = ax
self.objs = []
self.boxs = []
def hlen(self,edge1,edge2,position,latex):
x = np.linspace(edge1,edge2)
y = 2*(x-edge1)*(x-edge2)+position
p,= self.ax.plot(x,y,**pdic)
txt = self.ax.text((edge1+edge2)/2,position-0.12,"$"+latex+"$",**tdic)
self.objs += [p,txt]
pad = patches.Rectangle((((edge1+edge2)/2)-0.07,position-0.21),0.15,0.2,**Rdic)
self.ax.add_patch(pad)
self.boxs += [pad]
def vlen(self,edge1,edge2,position,latex,LR):
x = np.linspace(edge1,edge2)
y = -LR*0.48*(x-edge1)*(x-edge2)/(edge2-edge1)**2+position
p,= self.ax.plot(y,x,**pdic)
txt = self.ax.text(position+LR*0.12,(edge1+edge2)/2,"$"+latex+"$",**tdic)
self.objs += [p,txt]
pad = patches.Rectangle((position+LR*0.12-0.08,(edge1+edge2)/2-0.12),0.16,0.24,**Rdic)
self.ax.add_patch(pad)
self.boxs += [pad]
#長さ表記を埋め込んでいきます
Llen = Length(ax2u)
Llen.hlen(0.8,1.3,-1.1,"\\frac{1}{2}")
Llen.hlen(1.7,2.2,-1.1,"\\frac{1}{2}")
Llen.vlen(-1.1,4/5-1.1,1.05,"\\frac{4}{5}",-1)
Llen.vlen(-1.1,4/7-1.1,1.95,"\\frac{4}{7}",-1)
Llen.objs += ax2u.plot([1.05,1.05],[-1.1,4/5-1.1],linestyle="--",**pdic)
Llen.objs += ax2u.plot([1.95,1.95],[-1.1,4/7-1.1],linestyle="--",**pdic)
Rlen = Length(ax6u)
Rlen.hlen(0.8,1.3,-1.1,"\\frac{1}{2}")
Rlen.hlen(1.7,2.2,-1.1,"\\frac{1}{2}")
Rlen.vlen(-1.1,-0.1,0.8,"1",-1)
Rlen.vlen(-1.1,2/3-1.1,1.3,"\\frac{2}{3}",+1)
Rlen.vlen(-1.1,2/3-1.1,1.7,"\\frac{2}{3}",-1)
Rlen.vlen(-1.1,1/2-1.1,2.2,"\\frac{1}{2}",+1)
#最後に現れる不等号たち
futogodic = dict(size=14,ha="center",va="baseline",zorder=110,alpha=0,
bbox=dict(fc="w",lw=0,boxstyle="round,pad=0.15",alpha=0))
futogos = []
futogos += [fig.text(0.05,0.65,"0.68<",color="0.3",**futogodic)]
futogos += [ax2u.text(1.5,0.20,"$\\dfrac{24}{35}$",color=col_L,**futogodic)]
futogos += [fig.text(0.35,0.65,"<",color="0.3",**futogodic)]
futogos += [ax4u.text(1.5,0.20,"$\\log{2}$",color="0.2",**futogodic)]
futogos += [fig.text(0.65,0.65,"<",color="0.3",**futogodic)]
futogos += [ax6u.text(1.5,0.20,"$\\dfrac{17}{24}$",color=col_R,**futogodic)]
futogos += [fig.text(0.95,0.65,"<0.71",color="0.3",**futogodic)]
#数式たち
linedic=dict(va="baseline",usetex=True,clip_on=True,fontsize=16)
lines1=[
r"=\frac{\,4\,}{\,5\,}\times\frac{\,1\,}{\,2\,}+\frac{\,4\,}{\,7\,}\times\frac{\,1\,}{\,2\,}",
r"=\frac{\,24\,}{\,35\,}\,>\,0.68",
]
lines2=[
r"=\int_{1}^{2}\!\frac{\,1\,}{\,x\,}\,dx",
r"=\Bigg[\log x\,\Bigg]_{1}^{2}",
r"=\;\log 2",
]
lines3=[
r"=\frac{1}{2}\!\times\!\!\left(\!1\!+\!\frac{2}{3}\!+\!\frac{2}{3}\!+\!\frac{1}{2}\right)\!\!\times\!\frac{1}{2}",
r"=\frac{\,17\,}{\,24\,}\,<\,0.71",
]
#数式を書き込んでいきます
colors = [(1,1,1,alpha) for alpha in np.arange(0,11)/10]
cmap = ListedColormap(colors)
TXT = []
PCM = []
for ax,lines in zip([ax2d,ax3d,ax1d],[lines2,lines3,lines1]):
for i,line in enumerate(lines):
latex = "$\\displaystyle " + line + "$"
txt = ax.text(0,-(i+1)*2+0.73,latex,**linedic)
TXT.append(txt)
X,Y = np.mgrid[-2:14:0.1,-(i+1)*2:-i*2+0.1:2]
C = np.ones((len(X)-1,1))
C[0] = 0
pcm = ax.pcolormesh(X,Y,C,cmap=cmap,zorder=10)
PCM.append(pcm)
#コメントたち
commentdic = dict(ha="center",va="center",size=20,color="white",
zorder=200,linespacing=2.4,fontfamily="Meiryo",
bbox=dict(color="black",pad=300))
phrases = []
phrases.append("""
今から
$0.68\\,<\\,\\log2\\,<\\,0.71$
をお見せします
""")
phrases.append("""
$\\log2$ は
常用対数じゃなくて
自然対数の方なので
気をつけてね
""")
phrases.append("""
以上
$0.68\\,<\\,\\log2\\,<\\,0.71$
でした!
""")
phrases.append("""
ちなみに
$\\log2\\,=\\,0.6931\\ldots$
だそうです
""")
phrases.append("""
もちろん
$2\\,<\\,e$ なので
$\\log2$ は
1より小さくなります
""")
phrases.append("""
おしまい
(*`・ω・)ゞ
""")
#コメントを埋め込んでいきます
comments = []
for i,phrase in enumerate(phrases):
comment = fig.text(0.5,0.5,phrase,**commentdic)
comments.append(comment)
if i>0:
comment.set_visible(False)
#お気に入りのイージング関数
def easing(x):
if x<0.5:
return 2*x**2
else:
return 1-(-2*x+2)**2/2
#図形を平行移動させる関数
def slider(a,P,verts,x,y):
old_xy = np.array(verts)
slider = np.tile([a*x,a*y],(len(verts),1))
new_xy = old_xy + slider
P.set_xy(new_xy)
if a==1:
verts.clear()
verts.extend(new_xy)
#図形を回転移動させる関数
def rotate(a,P,verts,theta):
old_xy = np.array(verts).T
anchor = np.tile(verts[0],(len(verts),1)).T
R = np.array([[np.cos(a*theta),-np.sin(a*theta)],
[np.sin(a*theta), np.cos(a*theta)]])
new_xy = R @ (old_xy-anchor) + anchor
P.set_xy(new_xy.T)
if a==1:
verts.clear()
verts.extend(new_xy.T)
#数式が徐々に現れる関数
def appearing(i,pcm):
C = np.ones(len(pcm.get_array()))
C[:2*i+1] = 0
C[2*i+1:2*i+20] = np.arange(0.05,1.00,0.05)
pcm.set_array(C)
#セクションを判定する関数
def section(i):
n = np.argmin(~(i<endings[1:]))
k = i-endings[n]
T = list(periods.values())[n]
a = easing(k/(T-1))
keys = list(periods.keys())
key = keys[n]
pre = keys[n-1]
return k,a,key,pre
#台本の構成
periods = {"C1":50,"C2":50,
"A1":30,"T1":40,"T2":40,"T3":50,
"A2":30,"R1":30,"R2":30,"R3":30,"T4":70,"T5":70,
"A3":30,"L1":30,"L2":30,"L3":30,"L4":30,"T6":60,"T7":70,
"A4":60,"E1":40,
"C3":50,"C4":50,"C5":50,"C6":30}
endings = np.cumsum(list(periods.values()))
endings = np.append(0,endings)
#上演
def update(i):
k,a,key,pre = section(i)
if "T" in key:
appearing(k,PCM[int(key[1])-1])
elif "A1" == key:
area.set_alpha(a)
elif "A2" == key:
for R in [R1w,R2w]:
R.set_alpha(a)
for R in [R1k,R2k]:
R.set_alpha(0.5*a)
elif "A3" == key:
for L in [L1w,L2w]:
L.set_alpha(a)
for L in [L1a,L1b,L2a,L2b]:
L.set_alpha(0.5*a)
elif "A4" == key:
for wbg in wbgs:
wbg.set_alpha(a)
for futogo in futogos:
futogo.set_alpha(a)
futogo.get_bbox_patch().set_alpha(a)
elif "L1" == key:
slider(a,L1a,vL1a,0,-1.1)
slider(a,L1b,vL1b,0,-1.1)
slider(a,L2a,vL2a,0,-1.1)
slider(a,L2b,vL2b,0,-1.1)
elif "L2"== key:
slider(a,L1a,vL1a,-.2,0)
slider(a,L1b,vL1b,-.2,0)
slider(a,L2a,vL2a,0.2,0)
slider(a,L2b,vL2b,0.2,0)
elif "L3"== key:
for obj in Llen.objs:
obj.set_alpha(a)
elif "L4"== key:
rotate(a,L1b,vL1b,-np.pi)
rotate(a,L2b,vL2b,-np.pi)
elif "R1" == key:
slider(a,R1k,vR1,0,-1.1)
slider(a,R2k,vR2,0,-1.1)
elif "R2"== key:
slider(a,R1k,vR1,-.2,0)
slider(a,R2k,vR2,0.2,0)
elif "R3"== key:
for obj in Rlen.objs:
obj.set_alpha(a)
if k==0:
if "C" in key:
comments[int(key[1])-1].set_visible(True)
elif "A2"==key:
ax6u.set_visible(True)
elif "A3"==key:
ax2u.set_visible(True)
elif "L3"==key:
for obj in Llen.boxs:
obj.set_visible(True)
elif "R3"==key:
for obj in Rlen.boxs:
obj.set_visible(True)
if "C" in pre:
comments[int(pre[1])-1].set_visible(False)
mov = ani.FuncAnimation(fig,update,endings[-1],interval=100)
plt.show()