Ipywidgets快速构建简单界面及Docker化部署
看到一篇文章不以赚钱为目的的读大学,都是在浪费青春。题目或许很多人不认同,但于我而言却值得想一想的。
现在准备利用地理优势,开始代购的大业。上了这么多年学,就是为肉体翻墙做代购。。。
工欲善其事,必先利其器。首先想找个能方便记录
订单的工具,免得需要从excel表格中复制黏贴,再点个求和计算的。只需要几个简单的按钮,选择商品求和粗略的算下重量税率的。
做个简单界面的方法很多,C#
,python+tkinter
或者用flask
构建一个简单的web demo。现在大部分工作都是用python
做的,之前在做高光谱遥感作业时,用Jupyter Notebook
中的widgets.interact
,可以很方便的查看不同的波段组合,免去了还得去Envi
里面查看的功夫。
也可以看一下这篇文章中提及到的各个界面小工具
Static Interactive Widgets for IPython Notebooks
因此用这个方法尝试一下,而且可以利用现成的notebook的docker镜像直接部署到web。下面就开始用Ipywidgets
来开始构建一个简单的界面。
数据格式
数据都是简单临时构造的,仅用于示例。
在excel中,规格一列要避免使用数字,不然在dropdown组件中会报错。
选择器
首先需要能选择商品的类型,并根据类型筛选可选择的品牌和规格,用到了Dropdown
和Select
两个组件。
# 类型
type_ = widgets.Select(
options=types,
value=types[0],
description=u'类型:',
disabled=False,
continuous_update=False,
button_style='info' # 'success', 'info', 'warning', 'danger' or ''
)
# 品牌
brand_ = widgets.Dropdown(
options=brands,
value=brands[0],
description=u'品牌',
disabled=False,
continuous_update=True
)
当选择的内容改变时,需要能够触发事件,并执行相应的方法。没有找到类似onclick的事件,在stackoverflow上找到了一个解决办法:
def type_clicked(change):
if change['type'] == 'change' and change['name'] == 'value':
clear_output()
boolType = data.ix[:,0] == type_.selected_label
brands = list(data.ix[boolType,1].drop_duplicates().values)
brand_.options = brands
brand_.value = brands[0]
boolBrand = [item in brands for item in data.ix[:,1]]
specs = list(data.ix[boolBrand&boolType,2].drop_duplicates().values)
spec_.options = specs
spec_.value = specs[0]
def brand_clicked():
boolBrand = data.ix[:,1] == brand_.selected_label
boolType = data.ix[:,0] == type_.selected_label
specs = list(data.ix[boolBrand&boolType,2].drop_duplicates().values)
spec_.options = specs
spec_.value = specs[0]
每次触发事件时,可能会有输出,因此应该先清空之前的输出内容
clear_output()
按钮
按钮自然是在交互时,必不可少的:
btn_viewrecord = widgets.Button(
description=u'查看物品信息',
disabled=False,
button_style='warning', # 'success', 'info', 'warning', 'danger' or ''
tooltip=u'初始化',
icon='check'
)
display(btn_viewrecord)
初始化所选择的物品记录:
record = pd.Series()
触发事件:
def on_btn_viewrecord_clicked(p):
rec_cat = category_.selected_label
rec_brand = brand_.selected_label
rec_type = type_.selected_label
rec_spec = spec_.selected_label
q = (data.ix[:,0] == rec_type) & (data.ix[:,1] == rec_brand) & (data.ix[:,2] == rec_spec)
global record
record = pd.Series(data.ix[q,:].iloc[0])
clear_output()
print record
btn_viewrecord.on_click(on_btn_viewrecord_clicked)
滑块
用一个整数滑块,可以快速的选择所需要的数量:
number = widgets.IntSlider(
value=1,
min=1,
max=10,
step=1,
description=u'数量:',
disabled=False,
continuous_update=False,
orientation='horizontal',
readout=True,
readout_format='i',
slider_color='white'
)
display(number)
作用域问题
在将记录追加到订单dataframe中时,由于是在on_click
事件中完成,要将外部的变量定义为global
,不然会报错
UnboundLocalError: local variable 'record' referenced before assignment
具体如下:
def on_btn_order_clicked(p):
clear_output()
global order,record
record = record.append(pd.Series([int(number.value)], index=[u'数量']))
order = order.append(record,ignore_index=True)
weights = order.ix[:,u'毛重/kg'].sum()
taxes = (order.ix[:,u'价格/Euro'] * order.ix[:,u'税率']).sum()
weight.value = str(weights)
tax.value = str(taxes)
print order
btn_order.on_click(on_btn_order_clicked)
最终效果
是不是觉得这界面简直挫的弱爆了。。。
download.jpg
Docker部署
虽然界面看上去不咋地,但实现起来还是很快的,能用它做些简单的demo应该也还可以。既然是用的Juypter Notebook
,想让它运行在web上并不是难事。可以直接用个docker
云,再拖个Juypter Notebook
的镜像,把程序放上去就OK了。
比如DaoCloud
提供了免费的容器
代码下载
http://pan.baidu.com/s/1i4ZOxnf 密码: 关注个人微信公众号后,输入Ipywidgets
即可。
欢迎关注微信公众号