在经过与老师的探讨后,我们决定将之前创新实训的课题,继续深挖,开发一套基于人工智能模型的生物序列分析平台,内置了传统nlp模型与生物信息中的各类模型的整合,打算做到60个算法的集合,最终我们实现了两个平台上一共56个的算法。
本博客主要记录的内容是本人在智能生物序列分析平台的工作日志:
在代码构造方面:我们使用了react+material-UI的整体构架,将我们的BIO的界面更新迭代了Material-UI的UI框架,然后我逐步进行更深层次的代码迭代。
import React from 'react';import { Button }
from '@material-ui/core';
function App() {
return ;
}
因为Material-UI 组件是相互独立的,所以我们可以很快进行嵌入使用,工作时仅注入当前组件所需要的样式。这些Material-UI组件并依赖于任何全局的样式表。
import React from 'react';
import ReactDOM from 'react-dom';
import Button from '@material-ui/core/Button'; // 导入Button组件
function App() {
return (
);
}
ReactDOM.render( , document.querySelector('#app'));
对于组件的支持上,Materail-UI遵循实际的指导规范,支持所有主流的稳定的浏览器,支持IE11以上。Material-UI还支持node.js v6.x以上的服务端渲染。
其中我们使用了material-UI中的CssBaseline组件以建立统一的简单的样式基准。
import CssBaseline from '@material-ui/core/CssBaseline';
function App() {
return(
{/* 页面元素 */}
)
}
我们对于material-UI中的Grid布局使用的很多,下面介绍一下具体细节:
Material-UI的布局设计基础
Material-UI布局,使用统一的组件和间距,实现了多平台、多环境和屏幕尺寸的统一性。
1、使用 Grid / Hidden / Breakpoints 这三类组件,实现响应式UI,适配各种尺寸的屏幕。
2、组件使用 z-index属性,实现 Z 轴上的空间层次排布。在这一步我们频繁使用Grid的组件,从而实现了很好的flexbox模型
Grid 组件
Material-UI的响应式UI,是基于12列的栅格布局。Material-UI的栅格系统是由 Grid 组件实现的,它使用了 CSS 弹性盒模型,它有两种类型的布局,分别是 containers 和 items。item的宽度被设置为百分比,因此它们总是基于父元素而流动、动态地变换大小。items使用内边距padding生成元素之间的间距空间。Material-UI栅格系统支持五种断点模式,分别是 xs / sm / md / lg / xl 。
我们自己的适配代码如下:
{chipShowList &&
chipShowList.map((seq) => {
let selected = showSeq.includes(seq.value);
return (
: }
key={seq.value}
label={seq.label}
color={selected ? "primary" : "default"}
disabled={showSeq.length > 0 && !selected}
onClick={() => handleSeqChange(seq.value)}
sx={{ m: "3px 5px", float: "left" }}
/>
);
})}
这样可以很大程度上提高我们界面的布局管理,代码也具有很大的可读性。
最终我重构后的UI大致固定在如下图所示的状态:
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图2 宣传模块等home界面)
下面是我对这个框架的嵌入步骤:
Material-UI 组件无需任何额外的设置即可使用,并且不会影响全局变量。
以下的展示中,既可以体现前端页面的情况,也可以凸显后台所做的任务的复杂性。
导航栏模块:菜单、子菜单等菜单组建,通过简洁的icon图标与文字的配合,将用户快速引导到其需要的功能模块页面。
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图1 导航栏)
宣传模块、版权模块:简要说明项目所使用的机器学习模型、参考文献、联系方式等,增加用户对软件结果的信任度,也方便用户在软件出现问题时快速联系软件开发方。
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图2 宣传模块等home界面)
DNA/RNA/Protein预测表单模块:接收用户传递的生物大分子信息、机器学习相关参数,例如模型类型、算法、精度要求等,通过提交时对表单的校验,将一个完整的预测任务表单数据传递给后端。
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图3 训练任务:数据输入与超参数选取模块)
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图4 模型选取模块)
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图5 训练任务:邮件输入模块)
DNA/RNA/Protein序列训练模块:接收用户传递的生物大分子信息,用户可选择使用所有已经留存于服务器上的所有已训练的机器学习生物大分子模型对用户输入的分子序列进行分析,或者选择输入自己的数据(输入的数据来源既可以是直接复制粘贴的序列数据,也可以是体积很大的fasta数据),来微调机器学习模型的参数,此模型参数随表单的其他数据一并使用模块传入后端。
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图6 预测任务:数据输入与超参数选取模块)
任务结果列表模块:平铺展示运行在服务器上的所有项目,包括未运行、正在运行、获得结果3个状态的任务。用户可根据提交任务时给用户的任务ID、后台发送的任务完成电子邮件内信息等找到自己提交的任务,也可以查看其他使用此软件项目的用户提交的任务情况。
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图7 任务结果列表模块)
单任务结果展示模块:详细展示后台存放的数据,包括任务提交时间、完成时间、服务类型、任务类型以及各机器学习的参数(如精确度等),用图表等形式将参数可视化展示。
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图8 单任务结果展示模块:模型与超参数信息)
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图9 单任务结果展示模块:动态比较echart展示模块)
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图10 单任务结果展示模块:静态图表展示模块)
以上几张图都是来自于我们训练过程的最终结果展示部分。
前端使用echart图来将数据可视化,从而实现图的动态效果。
DNA/RNA/Protein序列训练模块:输入数据可以来自于用户,也可以来自于系统预存,模型可以使用系统提供已经训练好的模型,也可以使用之前用户自己通过平台训练的模型。对于结果来说针对DNA与RNA特殊数据,前端独立优化出了一套动态展示组件,基于用户自定义长度的兴趣点展示滑动窗口:
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图11 RNA/DNAmotif预测:尺度比较宽松的显示图)
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图12 RNA/DNAmotif预测:尺度放紧的显示图)
对于protein:我们的特色是对于结合位点的3D展示,利用生物序列可视化的3D模型与网页的深度绑定,我们将其适配到了web端为我们的蛋白质进行3D建模:
因为项目隐私性,我们这个具体图片放在了最终的提交报告中
(图13 蛋白质位点预测:3D展示页面)
这里的图是完全可以是用户拖动旋转与放大的。
对于后台部分我真对这部分也做了对应echart的生成任务,主要使用的框架是pyechart:
from pyecharts import options as opts
from pyecharts.charts import Bar
from pyecharts.charts import Pie
from pyecharts.globals import ThemeType
names = ["A", "C", "G", "U"]
data_p = []
data_n = []
data_sum = []
for i in names:
data_p.append(keyvalueP[i])
data_n.append(keyvalueF[i])
data_sum.append((keyvalueP[i] + keyvalueF[i]))
c = (
Bar(init_opts=opts.InitOpts(width="100%", height="350px", theme=ThemeType.LIGHT))
.add_xaxis(names)
.add_yaxis("Positive", data_p, stack="stack1")
.add_yaxis("Negative", data_n, stack="stack1")
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(legend_opts=opts.LegendOpts(pos_bottom = "0%"))
.render('{}/{}.{}'.format(config['savepath'], 'rna_train_statistics', 'html'))
)
c = (
Bar(init_opts=opts.InitOpts(width="450px", height="350px", theme=ThemeType.LIGHT))
.add_xaxis(names)
.add_yaxis("Positive", data_p, stack="stack1")
.add_yaxis("Negative", data_n, stack="stack1")
.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(legend_opts=opts.LegendOpts(pos_bottom="0%"))
# .render('{}/{}.{}'.format(config['savepath'], 'rna_train_statistics', 'html'))
)
make_snapshot(snapshot, c.render(),
'{}/{}.{}'.format(config['savepath'], 'rna_train_statistics_pyecharts', 'png'))
make_snapshot(snapshot, c.render(),
'{}/{}.{}'.format(config['savepath'], 'rna_train_statistics_pyecharts', 'pdf'))
make_snapshot(snapshot, c.render(),
'{}/{}.{}'.format(config['savepath'], 'rna_train_statistics_pyecharts', 'svg'))
d = (
Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width="100%", height="350px", ))
.add("", [list(z) for z in zip(names, data_sum)], center=["50%", "40%"])
.set_global_opts(
legend_opts=opts.LegendOpts(pos_bottom = "0%"))
.set_series_opts(label_opts=opts.LabelOpts(is_show=False), tooltip_opts=opts.TooltipOpts(trigger="item", formatter="{b}: {c} ({d}%)"))
.render('{}/{}.{}'.format(config['savepath'], 'rna_train_statistics_pie', 'html'))
)
c = (
Pie(init_opts=opts.InitOpts(theme=ThemeType.LIGHT, width="450px", height="350px", ))
.add("", [list(z) for z in zip(names, data_sum)], center=["50%", "40%"])
.set_global_opts(
legend_opts=opts.LegendOpts(pos_bottom="0%"))
.set_series_opts(label_opts=opts.LabelOpts(is_show=False),
tooltip_opts=opts.TooltipOpts(trigger="item", formatter="{b}: {c} ({d}%)"))
# .render('{}/{}.{}'.format(config['savepath'], 'rna_train_statistics_pie', 'html'))
)
make_snapshot(snapshot, c.render(),
'{}/{}.{}'.format(config['savepath'], 'rna_train_statistics_pie_pyecharts', 'png'))
make_snapshot(snapshot, c.render(),
'{}/{}.{}'.format(config['savepath'], 'rna_train_statistics_pie_pyecharts', 'pdf'))
make_snapshot(snapshot, c.render(),
'{}/{}.{}'.format(config['savepath'], 'rna_train_statistics_pie_pyecharts', 'svg'))
对于这部分我们使用前后端的联调模式,先通过后端生成echart的html文件,然后通过nginx将对应的文件目录暴露在公网ip上,最后通过前端代码进行调用,
最终我们形成前后端深度绑定的业务逻辑,实现了端到端的效果。