指数関数のアニメーションと静止画を作成する SageMath スクリプト
正の実数を底とする指数関数と、その導関数の関係を説明するために、グラフのアニメーションと静止画を、SageMath を使って作成しました。 その SageMath スクリプトを、このページで公開します。
(There is the English(英語) page.)
(最終更新日: 2021年3月24日)
前書き
前のページ で、正の実数 \(a\) を底とする指数関数 \(a^x\) と、その導関数の関係について、説明しています。 この説明の中では、視覚的な理解を促すために、これらの式を描くグラフのアニメーションと静止画を使用しています。 また、補足説明のために、対数関数のグラフのアニメーションと静止画も使用しています。
これらのアニメーションと静止画は、SageMath で作成しました。 その SageMath スクリプトを、次の章 に公開します。
アニメーションと静止画を作成するスクリプト
前のページ に掲載した、アニメーションと静止画を作成するための、SageMath スクリプトを以下に示します。 このスクリプトは、先に、静止画を作成し、次に、アニメーションを作成します。
# This SageMath script have been tested with SageMath 9.1 and FFmpeg 3.4.8
# on Ubuntu 18.04.
# This script outputs the graph image files (SVG format) of
# the following functions:
#
# * The exponential function y=a^x and its derivative y',
# where "a" is a positive real number.
# 2, e, and 4 are substituted for the "a" respectively.
# In the script below, this graph is named "exp graph".
#
# * The logarithm function y=log(x).
# The point (a, log(a)) is added to the graph.
# This graph is named "log graph".
#
# * Another graph that arranges the above two graphs side by side
# is also output.
# This graph is named "parallel graph".
#
# This script outputs the graph animation files (MP4 and WebM formats).
# The animations illustrate the variations in the above graphs
# when the "a" is continuously varied from 1.1 to 5.
# These animations are named "exp animation", "log animation", and
# "parallel animation" respectively.
#
# This script also outputs another animation that plays both
# the "exp animation" and the "log animation" serially.
# This animation is named "serial animation".
#
# The "exp animation" and the "log animation" are grouped together and
# named "single animations".
# Similarly, the "parallel animation" and the "serial animation"
# are grouped together and named "double animations"
# The "a" in the following script represents the above "a".
# It is not an English "indefinite article".
a_min, a_max = 1.1, 5
def create_a_list():
l=srange(a_min, a_max, 0.02, include_endpoint=True) + [e]
l.sort()
return l
def format_a(a):
return r'\mathrm{e}' if a == e else format(float(a), '.2f')
def format_log_text(a, log_a):
t= r'$\log(a=' + format_a(a) + ')'
if a == e:
t+= '=1'
else:
t+= r'\approx' + format(float(round(log_a, 3)), '.3f')
if log_a < 1:
t+= '<1'
else:
t+= '>1'
t+= '$'
return t
def format_graph(g):
g.axes_labels(['$x$', '$y$'])
g.fontsize(14)
g.axes_labels_size(1.3)
g.set_legend_options(font_size='xx-large', labelspacing=0.5)
g.set_aspect_ratio(1)
tick_formats={'ticks_integer':True, 'tick_formatter':'latex'}
text_formats={'axis_coords':True, 'horizontal_alignment':'left', \
'fontsize':'xx-large', 'rgbcolor':'black', \
'bounding_box':{'boxstyle':'square', 'fc':'w', 'ec':'darkgray'}}
def create_exp_graph(a):
x_min, x_max = -1, 3
g=plot([a^x, (a^x)*log(a)], (x, x_min, x_max), \
legend_label=['$a^x$', "$(a^x)'$"], **tick_formats)
g+=text('$a=' + format_a(a) + '$', (0.785, 0.64), **text_formats)
format_graph(g)
g.set_legend_options(loc='upper right')
g.set_axes_range(x_min, x_max, 0, 3.5)
return g
def create_log_graph(a):
x_min, x_max = 0.5, (a_max +0.5)
x_axes_min, x_axes_max = (x_min -0.1), (x_max +0.1)
log_a = log(a)
g=plot(log(x), (x, x_min, x_max), \
legend_label=r'$\log(x)$', **tick_formats)
g+=text(format_log_text(a, log_a), (0.38, 0.92), **text_formats)
g+=line([(x_axes_min, 1), (x_axes_max, 1)], \
rgbcolor='black', thickness=0.2)
g+=point((a, log_a), rgbcolor='red', pointsize=80, \
legend_label=r'$\left(a, \log(a) \right)$')
g+=line([(a, log_a), (a, 0)], \
rgbcolor='red', thickness=0.3)
g+=arrow((a, log_a), (x_axes_min, log_a), \
rgbcolor='red', width=0.3, arrowsize=4)
format_graph(g)
g.set_legend_options(loc='upper left')
g.set_axes_range(x_min, x_max, -0.7, 3.0)
return g
def make_parallel_graph(exp_graph, log_graph):
return multi_graphics([ \
(exp_graph, (0 , 0, 0.45, 0.45)), \
(log_graph, (0.43, 0, 0.5 , 0.45))])
parallel_graph_formats={'figsize':[13, 8.7]}
# Write the graph image files of "exp", "log", and "parallel"
def write_images():
for a in [2, e, 4]:
exp_graph = create_exp_graph(a)
log_graph = create_log_graph(a)
parallel_graph = make_parallel_graph(exp_graph, log_graph)
exp_graph.save('exp-' + str(a) + '.svg')
log_graph.save('log-' + str(a) + '.svg')
parallel_graph.save('parallel-' + str(a) + '.svg', \
**parallel_graph_formats)
# Create the lists of "exp graph" and "log graph" respectively
def create_exp_log_graph_lists():
a_list = create_a_list()
exp_graph_list = [create_exp_graph(a) for a in a_list]
log_graph_list = [create_log_graph(a) for a in a_list]
return exp_graph_list, log_graph_list
animation_ext_list = ['.mp4', '.webm']
def write_single_animations():
exp_graph_list, log_graph_list = create_exp_log_graph_lists()
for file_ext in animation_ext_list:
animate(exp_graph_list).save('exp' + file_ext)
animate(log_graph_list).save('log' + file_ext)
def write_parallel_animation(exp_graph_list, log_graph_list):
parallel_graph_list = [make_parallel_graph(exp_graph, log_graph) \
for exp_graph, log_graph in zip(exp_graph_list, log_graph_list)]
for file_ext in animation_ext_list:
animate(parallel_graph_list, **parallel_graph_formats).save( \
'parallel' + file_ext)
def write_serial_animation(exp_graph_list, log_graph_list):
for log_graph in log_graph_list:
log_graph.set_legend_options(font_size='x-large')
serial_graph_list = exp_graph_list + log_graph_list
serial_graph_formats={'figsize':[5.0, 5.0], 'fig_tight':False, \
'aspect_ratio':'automatic'}
for file_ext in animation_ext_list:
animate(serial_graph_list, **serial_graph_formats).save( \
'serial' + file_ext)
def write_double_animations():
exp_graph_list, log_graph_list = create_exp_log_graph_lists()
write_parallel_animation(exp_graph_list, log_graph_list)
write_serial_animation(exp_graph_list, log_graph_list)
write_images()
write_single_animations()
write_double_animations()
このスクリプトは、アニメーションを作成するために、FFmpeg を使用します。
静止画は、SVG形式で出力されます。 また、アニメーションは、MP4 と WebM の2種類の形式で出力されます。
上記のスクリプトで出力される MP4 ファイルのプロファイルは、「High 4:4:4 Predictive」です。 このプロファイルの MP4 ファイルを、正常に表示できないアプリケーションも存在します。
そこで、MP4 ファイルを、「Main」プロファイルに変換するための、FFmpeg を使用した、シェルスクリプトを、以下に示します。
#!/bin/sh
# This shell script have been tested with FFmpeg 3.4.8 on Ubuntu 18.04.
# This script converts "High 4:4:4 Predictive profile" of
# the MP4 files (H.264 codec) into "Main profile".
#
# The resolution (width and height) after the conversion
# must both be an even number.
# Therefore, if the width or height of the frame in the input file
# is an odd number, the corresponding edge of the frame is deleted
# by one pixel.
# Since the input videos have margins, the above deletion is not
# a problem.
for target_basename in exp log parallel serial
do
input_filename="${target_basename}.mp4" # e.g. exp.mp4
output_filename="${target_basename}-m.mp4" # e.g. exp-m.mp4
ffmpeg -y -i "${input_filename}" -codec:v libx264 -profile:v main \
-pix_fmt yuv420p -vf "crop=trunc(iw/2)*2:trunc(ih/2)*2" \
"${output_filename}"
done
この2つのスクリプトで作成される、静止画とアニメーションのほとんどは、前のページに掲載されています。 掲載されていないのは、指数関数アニメーションと対数関数アニメーションの両方を、連続して再生するアニメーションです。 上記のスクリプトでは、そのアニメーションを「連続アニメーション」と名付けています。 そのアニメーションのリンクを、以下に示します。
この「連続アニメーション」は、前のページの内容を、別の Web サイトで紹介するときに、動画として表示することを想定して、作成されました。
コメント
コメントを投稿