本日は
先日の記事
の応用という事で, 回転行列の角度をスライダーで変更させるコードを書いてみましょう.
実装例
rotmatslider.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, widgetbox, gridplot
from bokeh.io import curdoc
def rot_mat(degree):
theta = np.deg2rad(degree)
mat = np.array([[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]])
return mat
class RotationViewer(object):
def __init__(self):
xs = np.linspace(-np.pi, np.pi, 11)
ys = xs
Xs, Ys = np.meshgrid(xs, ys)
self.Xs, self.Ys = Xs.flatten(), Ys.flatten()
initdegree = 0
mat = rot_mat(initdegree)
transXs, transYs = mat @ np.array([self.Xs, self.Ys])
TOOLS = "pan,lasso_select,save,reset"
self.source = ColumnDataSource(data=dict(Xs=self.Xs, Ys=self.Ys,
transXs=transXs,
transYs=transYs))
self.fig = figure(tools=TOOLS, title="target",
x_range=(-np.pi*np.sqrt(2)-1, np.pi*np.sqrt(2)+1),
y_range=(-np.pi*np.sqrt(2)-1, np.pi*np.sqrt(2)+1))
self.fig.circle('Xs', 'Ys', source=self.source)
self.transfig = figure(tools=TOOLS, title="transformed",
x_range=self.fig.x_range, y_range=self.fig.y_range)
self.transfig.circle('transXs', 'transYs', source=self.source, size=6)
self.rot_param = Slider(title="degree", value=0,
start=0, end=360, step=1)
self.rot_param.on_change('value', self.update_data)
self.plot = column(self.rot_param, gridplot([[self.fig, self.transfig]]))
def update_data(self, attr, old, new):
mat = rot_mat(self.rot_param.value)
transXs, transYs = mat @ np.array([self.Xs, self.Ys])
self.source.data = dict(Xs=self.Xs, Ys=self.Ys,
transXs=transXs, transYs=transYs)
self.transfig.title.text = "degree {}".format(self.rot_param.value)
def main():
viewer = RotationViewer()
document = curdoc()
document.add_root(viewer.plot)
main()
実行例
$ bokeh serve --show rotmatslider.py
こんな感じです.
気持ち悪いぐらいヌルヌル動きます.
お試しあれ.
追加
2x2 行列のパラメータ版も作ってみました.
こんな風に動いてたんですね.