本篇将基于Python开源的Pyxley包,从MySQL数据库读取信息,并将数据以线图(ploty)的形式展示出来。
Pyxley是基于Flask框架开发的开源的Web Dashboard平台,包下集成多种数据可视化模块。不用书写复杂的JS、HTML和CSS就能通过调用Python接口实现一个Web应用。官方网站()给出了详细的说明并给出了一个线图(ploty)的例子,但由于给的是代码段且有部分有Bug,于是我从Github开源站()下载了源码包,并对源码包中的Example做了解读。
一、MySQL连接及数据收集
import MySQLdb as mysql
import pandas as pd
# 建立 sql链接
conn = mysql.connect(host="172.17.11.188",user="root",passwd="root",db="wind_analysis")
sql = conn.cursor()
# 获取表为DataFrame
sql.execute('select FARM_NAME,FAN_TYPE,FAN_NO,DATA_DATE,WIND_SPEED,AC_POWER from pcbin_month')
rows = sql.fetchall()
df = pd.DataFrame([[ij for ij in i] for i in rows])
df.rename(columns={0:'farm',1:'type',2:"no",3:"date",4:"windspeed",5:"power"},inplace=True)
二、Pyxley example 下的 ploty案例解读
1.案例概述
example下的ploty文件目录
前文提到Pyxley是基于Flask开发的,所有工程必有两个核心文件
__init__.py :初始化应用,需要再此声明应用目录,数据来源等核心设置
buildui.py :应用的UI设计,在这里通过调用Flask和Pyxley的接口实现将初始化
类传来的数据可视化(下图为数据预览)
2.案例代码解读
__init__.py
from os import path
from buildui import get_layouts
from pyxley.utils import create_app, default_static_path, default_template_path
# create the flask app
# #获取文件路径
here = path.abspath(path.dirname(__file__))
# #调用Pyxley接口创建应用
app = create_app(here, default_static_path(), default_template_path())
# build the layout
# #调用buildui.py的自定义方法,将依赖的应用、数据文件传入
get_layouts(app, here+"/fitbit_data.csv")
if __name__ == "__main__":
app.run(debug=True)
buildui.py
from pyxley.charts.plotly import PlotlyAPI
from pyxley.filters import SelectButton
from pyxley import UILayout, register_layouts
import pandas as pd
from flask import jsonify, request
def make_ui(filename):
df = pd.read_csv(filename)
# Make a UI
# #新建 UI模板
ui = UILayout("FilterChart")
# Read in the data and stack it, so that we can filter on columns
# 将 Date作为 Index 方便按其余列拆分
# 实现以Date为X轴
以其他任意列为Y轴
_stack = df.set_index("Date").stack().reset_index()
_stack = _stack.rename(columns={"level_1": "Data", 0: "value"})
# Make a Button
# 按钮选项集
cols = [c for c in df.columns if c != "Date"]
# SelectButton(按钮默认填充,标签元素,标签别名(底层 API会用),默认选择)
btn = SelectButton("Data", cols, "Data", "Steps")
# add the button to the UI
# 按钮置入UI
ui.add_filter(btn)
# 初始选择的按钮 {按钮名:按钮某个选项}
init_params = {"Data": "Steps"}
# 根据按钮选项调整数据集 返回实现线性接口
def get_data():
args = {}
# 调用Flask的 request实现获取页面选项参数
for c in init_params:
if request.args.get(c):
args[c] = request.args[c]
else:
args[c] = init_params[c]
return jsonify(
# 实现线性接口(输入的 DF,元组型列值对应的列表,界面类型,属性参数)
PlotlyAPI.line_plot(
PlotlyAPI.apply_filters(_stack, args),
[("Date", "value")],
"lines+markers",
{}
))
# 创建 plot接口型(ChartId,URL链接,初始化时执行的方法,初始化参数)
_plot = PlotlyAPI(
"plotly_chart",
"/api/plotly_line_plot/",
get_data,
init_params=init_params
)
ui.add_chart(_plot)
return ui
def get_layouts(mod, filename):
# plotly
# 调用 make_ui(数据文件)
plotly_ui = make_ui(filename)
# UI适用于APP(APP)
plotly_ui.assign_routes(mod)
# 获取属性
plotly_props = plotly_ui.build_props()
# 创建界面 类型:{UI属性,标题}
_layouts = {
"plotly": {
"layout": [plotly_props],
"title": "Plotly"
}
}
# 返回注册好的界面
register_layouts(_layouts, mod)
运行__init__.py 进入localhost:5000查看
3.自己应用
数据预览
需求简介:通过选择FARM_NAME、FAN_TYPE、FAN_NO、DATA_DATE
将对应的WIND_SPEED--AC_POWER图画出来。
可以看出,案例给的相当于“一个X对应多个Y,通过Y标签确定Y”,
但这个需求是“多个属性确定一组对应的XY”。于是我将问题
转化为“多个X对应多组Y,通过属性标签确认X”
__init__.py
这里我采用从MySQL数据库中读取数据,并直接以Data Frame的格式扔给buildui.py
# -coding:utf-8
from os import path
from buildui import get_layouts
import MySQLdb as mysql
import pandas as pd
from pyxley.utils import create_app, default_static_path, default_template_path
# 建立 Flask 类型APP
# 获取文件路径
here = path.abspath(path.dirname(__file__))
# 创建 APP(项目路径,默认路径,默认缓存路径)
app = create_app(here, default_static_path(), default_template_path())
# 建立 sql链接
conn = mysql.connect(host="172.17.11.188",user="root",passwd="root",db="wind_analysis")
sql = conn.cursor()
# 获取表为DataFrame
sql.execute('select FARM_NAME,FAN_TYPE,FAN_NO,DATA_DATE,WIND_SPEED,AC_POWER from pcbin_month')
rows = sql.fetchall()
df = pd.DataFrame([[ij for ij in i] for i in rows])
df.rename(columns={0:'farm',1:'type',2:"no",3:"date",4:"windspeed",5:"power"},inplace=True)
# 获取界面(APP,数据文件)
get_layouts(app, df)
if __name__ == "__main__":
print here
app.run(debug=True)
buildui.py
#- coding:utf-8
from pyxley.charts.plotly import PlotlyAPI
from pyxley.filters import SelectButton
from pyxley import UILayout, register_layouts
import pandas as pd
import json
from flask import jsonify, request,session
# 自定义过滤数据矩阵方法,来根据属性筛选对应的XY,而不使用它自己的Filter
def dataFilter(data,filters):
rel = data[(data.farm==filters.get("farm"))&
(data.type==filters.get("type"))&
(data.no == filters.get("no"))&
(data.date == filters.get("date"))]
rel = rel.sort_values(by="windspeed",ascending=True)
return rel
# 创建 UI
def make_ui(DF):
# # # 数据层==============================================================================================
# 数据读入
df = DF
# 将 Date作为 Index 方便按其余列拆分
# 这里将X和X的属性列 测试风场 GW50-750 WT02287 2015-10-01 一起作为Index
_stack = df.set_index(["windspeed","farm","type","no","date"]).stack().reset_index()
# 改个名
_stack = _stack.rename(columns={"level_5": "Data", 0: "value"})
# # # UI层=================================================================================================
# 新建 UI模板
ui = UILayout("FilterChart")
# # 制作按钮选项-------------------------------------------------------------------------------------------
# 按钮选项集
cols1 = list(set(_stack.farm))
cols2 = list(set(_stack.type))
cols3 = list(set(_stack.no))
cols4 = list(set(_stack.date))
# SelectButton(按钮默认填充,标签元素,标签别名(底层 API会用),默认选择)
btn1 = SelectButton("风机风场", cols1, "farm", "????")
btn2 = SelectButton("风机型号", cols2, "type", "GW50-750")
btn3 = SelectButton("风机编号", cols3, "no", "WT02309")
btn4 = SelectButton("数据日期", cols4, "date", "201601")
# 按钮置入UI
ui.add_filter(btn1)
ui.add_filter(btn2)
ui.add_filter(btn3)
ui.add_filter(btn4)
# 初始选择的按钮 {按钮名:按钮某个选项}
global params
params = {"farm": "????", "type": "GW50-750","no":"WT02309","date":"201601"}
# # 制作线图-----------------------------------------------------------------------------------------------
# 根据按钮选项调整数据集 返回实现线性接口
def get_data():
global params
# 通过收集每次按钮事件请求,更新整体属性选择
params_in = request.args
for k in params_in:
v = params_in[k]
params.update({k: v})
# 返回 json
return jsonify(
# 实现线性接口(输入的 DF,元组型列值对应的列表,界面类型,属性参数)
PlotlyAPI.line_plot(
# (数据集,过滤的{列:值})返回df,而不调用它自己的Filter
dataFilter(_stack, params),
[("windspeed", "value")],
"lines+markers",
{}
))
# 创建 plot接口型(ChartId,URL链接,初始化时执行的方法,初始化参数)
_plot = PlotlyAPI(
"plotly_chart",
"/api/plotly_line_plot/",
get_data,
init_params=params
)
_plot2 = PlotlyAPI(
"plotly_chart",
"/api/plotly_line_plot/",
get_data,
init_params=params
)
ui.add_chart(_plot)
ui.add_chart(_plot2)
# 返回 UI
return ui
# 主要函数 创建界面(APP 数据文件)
def get_layouts(mod, DF):
# 调用 make_ui(数据文件)
plotly_ui = make_ui(DF)
# UI适用于APP(APP)
plotly_ui.assign_routes(mod)
# 获取属性
plotly_props = plotly_ui.build_props()
# 创建界面 类型:{UI属性,标题}
_layouts = {
"plotly": {
"layout": [plotly_props],
"title": "NEU_LightBuld Hadoop实验结果数据演示"
}
}
# 返回注册好的界面
register_layouts(_layouts, mod)
结果预览
对于数据库极大的可以采用在__init___.py接受请求,直接利用SQLConnector得到需要的部分发给buildui.py