我的Python自学之路

Ipywidgets快速构建简单界面及Docker化部署

2016-11-01  本文已影响1700人  时空Drei

看到一篇文章不以赚钱为目的的读大学,都是在浪费青春。题目或许很多人不认同,但于我而言却值得想一想的。

现在准备利用地理优势,开始代购的大业。上了这么多年学,就是为肉体翻墙做代购。。。

工欲善其事,必先利其器。首先想找个能方便记录订单的工具,免得需要从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组件中会报错。

选择器

首先需要能选择商品的类型,并根据类型筛选可选择的品牌和规格,用到了DropdownSelect两个组件。

# 类型
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即可。


欢迎关注微信公众号
上一篇下一篇

猜你喜欢

热点阅读