Python
数学
Bokeh

Bokehで微分と接線の関係の可視化を試みる.

More than 1 year has passed since last update.

本日は

最近QiitaのUIが刷新されたようですね.
今日のお題は関数 $f=f(x)$ の導関数 $f'(x)$ は各々の位置での接線の傾きを表すという高校1,2年生で習うことをPython可視化ライブラリBokehで実現してみましょう.

導入

一変数関数 $f$ の位置(または抽象的に言えば点) $x=a$ での微分は次の極限が存在するときに定義できます:

\lim_{h\to 0}\frac{f(a+h)-f(a)}{h} _{.}

この極限が存在するとき, $f$ は $x=a$ で微分可能と呼んでいました.そしてこの極限値を$f'(a)$
と記しました.

(私に取っては遠い過去の話なので「た」と過去形で書いていますが,現在形にすべきかは皆さんの解釈に委ねます.)

位置 $x=a$ での接線は, $xy$ 平面上の点 $(a,f(a))$ と $(a+h,f(a+h))$ を結ぶ直線において,パラメータ $h$を0に近づけた時の極限で得られます.したがって,接線は点 $(a,f(a))$ を通る傾きが $f'(a)$ の直線

y=f'(a)(x-a)+f(a)

の方程式を満たします.このことを確認するために可視化してみましょう.

実装例

deriv.py
import numpy as np
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Slider
from bokeh.layouts import column
from bokeh.io import curdoc


h = 1e-5


def get_tangentdata(a):
    df = (test_func(a+h)-test_func(a))/h
    txs = np.linspace(-0.5+a, 0.5+a, 10)
    tys = df*(txs-a)+test_func(a)
    return txs, tys


def test_func(xs, a=3.0):
    return 1/(1+np.exp(-a*xs))


class DerivViewer(object):

    def __init__(self):
        self.xs = np.linspace(-2.0, 2.0, 100)
        self.ys = test_func(self.xs)

        self.source1 = ColumnDataSource(data=dict(xs=self.xs,
                                                  ys=self.ys))
        a = 0
        txs, tys = get_tangentdata(a)
        self.source2 = ColumnDataSource(data=dict(txs=txs,
                                                  tys=tys))
        self.source3 = ColumnDataSource(data=dict(x=[a], y=[test_func(a)]))
        self.fig = figure(title='view tangent line',
                          x_range=(-2.0, 2.0),
                          y_range=(-0.2, 1.2))
        self.fig.line('xs', 'ys', source=self.source1)
        self.fig.line('txs', 'tys', source=self.source2, color='orange')
        self.fig.circle('x', 'y', source=self.source3, color='red')

        self.slider = Slider(title='position',
                             value=0,
                             start=-1.5,
                             end=1.5,
                             step=0.1)
        self.slider.on_change('value', self.update_data)
        self.plot = column(self.slider, self.fig)

    def update_data(self, attr, old, new):
        a = self.slider.value
        txs, tys = get_tangentdata(a)
        self.source2.data = dict(txs=txs, tys=tys)
        self.source3.data = dict(x=[a], y=[test_func(a)])


def main():
    viewer = DerivViewer()
    document = curdoc()
    document.add_root(viewer.plot)

main()

get_tangentdata 関数で接線を描画させるためのデータを作っています.

test_func のところを自前で変えると対応する関数の接線を作ってくれます.

実行例

bokeh serve --show deriv.py

ブラウザが立ち上がり下のように動作させることができます.

tangentline.gif

こういうのを学校の先生たちは勉強して見せてくれると生徒さんはワクワクするんだろうなー.
もう終わっちゃったけれど,ワクワクさんこういうので復活してくれないだろうか.