近期在公司实现在线实时监控特性报表系统,还没有完成,中间有部分知识点记录
先看看效果,发现数据还是有些问题,后期准备用pandas进行数据清洗:
views核心代码:
from django.shortcuts import render,redirect,HttpResponse
from datetime import datetime,timedelta
from pereport import PEModels,models
from functools import reduce
from pereport.conf.report_settings import CHART
#随机产生线条颜色
import random
def randomcolor():
colorArr = ['1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
color = ""
for i in range(6):
color += colorArr[random.randint(0,14)]
return "#"+color
def big_chart(request):
return render(request, "report/pe/big_line_chart.html")
def bigcd_chart(request):
param = request.GET.get("param",None)
print(param)
end = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
start = (datetime.now() + timedelta(hours=-24)).strftime("%Y-%m-%d %H:%M:%S")
ret_ls=[]
temp = None
for item in CHART[param]:
sub_equip_id_pds = item["sub_equip_id_pds"]
step_id_insp = item["step_id_insp"]
param_name = item["param_name"]
float_point = item["float_point"]
temp = big_cd(sub_equip_id_pds,start,end,step_id_insp,param_name,float_point)
ret_ls.append(temp)
ret_dict = {"chart1":ret_ls[0],"chart2":ret_ls[1],"line":param}
return render(request,"report/pe/big_line_chart.html",ret_dict)
def small_chart(request):
return render(request, "report/pe/small_line_chart.html")
def big_cd(sub_equip_id_pds,start,end,step_id_insp,param_name,float_point):
#定义捞取数据时间段
#获取当前inline Run货产品名
prod, prod_ls, prod_name = PEModels.prod_id(
sub_equip_id_pds=sub_equip_id_pds,
start=start,
end=end, )
prod_ls = (prod_name, "")
obj=""
if prod:
#获取产品信息
obj = models.PEProdInfo.objects.filter(
product_id=prod_name,step_id_insp=step_id_insp,sub_equip_id_pds=sub_equip_id_pds,
param_name=param_name
).first()
if obj:
#print(obj,obj.OOS_H,"xxxxxxxxxxxx")
#获取量测当侧EXP/COT经过TPM的Glass ID
sampling_cnt, glasses = PEModels.glass_info_byINSPEQ(
step_id_pds=obj.step_id_pds,
sub_equip_id_pds=obj.sub_equip_id_pds,
prod_ls=prod_ls,
start=start,
end=end,
step_id_insp=obj.step_id_insp
)
#print(sampling_cnt,glasses)
#获取这些glass id的量测数据,time_asc=0表示先以时间排序然后以site_no排序
ret=PEModels.insp_rawdata(
step_id_insp=obj.step_id_insp,
step_id_pds = obj.step_id_pds,
prod=prod,
param_name=obj.param_name,
glasses=tuple(glasses),
start=start, end=end,time_asc=0
)
html_str = """ {
data: %s,
type: 'line',
itemStyle : {
normal : {
lineStyle:{
color:'#FFFFFF'
}
}
},
},"""
#平均值,并设置可以显示数值
html_str1="""{
data: %s,
type: 'line',
itemStyle : { normal:
{label :
{show: true,color: 'red',textStyle:
{
fontWeight: 'bolder' //字体加粗
}
}
}
},
markLine : {
symbol:'none',
lineStyle: {
normal: {
type: 'solid'
}
},
data : [
{ yAxis: %s ,name:'min'},
{ yAxis: %s ,name:'target'},
{ yAxis: %s ,name:'max'},
]
},
},"""
#by时间画CD图
html_ret=""
x_data = []
x_data_time = []
data = set()
data_temp=[]
data_ret = []
if ret:
for item in ret:
#x轴坐标系标签
if item[0] not in x_data:
x_data_time.append(item[1].strftime("%m-%d %H:%M"))
x_data.append(item[0])
#y轴对应的数据
if item[2] not in data:
data_ret.append(data_temp)
data_temp=[]
data.add(item[2])
data_temp.append(item[3])
else:
data_temp.append(item[3])
print("data_temp",data_temp)
data_ret.append(data_temp)
#print(data_ret,len(data_ret))
average_data=[]
sum=0
if data_ret:
del data_ret[0]
for item in data_ret:
html_ret += html_str%str(item)
len_site = len(data_ret[0])
print(len_site,"len_site")
print(len(data_ret),"len_data_ret")
for j in range(0,len_site):
for i in range(0,len(data_ret)):
try:
sum += data_ret[i][j]
except:
sum +=0
print("len_site %s"%j, "len_data_ret %s"%i)
# 求每片glass所有value平均值,并存入average_data中,保留一位小数
average_data.append(round(sum/len(data_ret),float_point))
sum=0
#print(average_data)
# print(x_data_time,len(x_data_time))
# print(data_ret,len(data_ret))
html_ret+=html_str1%(average_data,obj.OOC_H,obj.item1,obj.OOC_L)
html2_str = """ {
data: %s,
type: 'line',
itemStyle : {
normal : {
lineStyle:{
color:'%s'
}
}
},
},"""
html2_temp = """
markLine : {
symbol:'none',
lineStyle: {
normal: {
type: 'solid'
}
},
data : [
{ yAxis: %s ,name:'min'},
{ yAxis: %s ,name:'target'},
{ yAxis: %s ,name:'max'},
]
}}"""
# 获取这些glass id的量测数据,time_asc=1表示先以site_no排序然后以时间排序
ret2=PEModels.insp_rawdata(
step_id_insp=obj.step_id_insp,
step_id_pds = obj.step_id_pds,
prod=prod,
param_name=obj.param_name,
glasses=tuple(glasses),
start=start, end=end,time_asc=1
)
#by点位画折线图
html2_ret=""
x_data2 = []
data2 = set()
data_ret2 = []
if ret2:
for item in ret2:
if item[2] not in x_data2:
x_data2.append(item[2])
if item[2] == '001':
data_ret2.append(data2)
data2 = []
data2.append(item[3])
else:
data2.append(item[3])
data_ret2.append(data2)
if data_ret2:
del data_ret2[0]
for item in data_ret2:
html2_ret+=html2_str%(item,randomcolor())
#加上markline
html2_ret = html2_ret[:-2]+html2_temp%(obj.OOC_H,obj.item1,obj.OOC_L)
return {'obj':obj,'x_data':x_data_time,'y_data':html_ret,'x_data2':x_data2,'y_data2':html2_ret}
else:
return None
数据库操作主要代码:
from pereport.edaDB import OracleConnect
from datetime import datetime,timedelta
import pandas as pd
from pereport.log import logger
class GlassDate(object):
def __init__(self,**kwargs):
self.glass_id = kwargs['glass_id']
self.average = kwargs['average']
self.range = kwargs['range']
self.max_value = kwargs['max_value']
self.min_value = kwargs['min_value']
self.sigma3 = kwargs['sigma3']
class SummaryData(object):
def __init__(self, **kwargs):
self.prod = kwargs['prod']
self.layer = kwargs['layer']
self.character = kwargs['character']
self.unit = kwargs['unit']
self.phase = kwargs['phase']
self.total_cnt = kwargs['total_cnt']
self.sampling_cnt = kwargs['sampling_cnt']
self.sampling_rate = kwargs['sampling_rate']
self.average = kwargs['average']
self.range = kwargs['range']
self.max_value = kwargs['max_value']
self.min_value = kwargs['min_value']
self.sigma3 = kwargs['sigma3']
self.time_diff = kwargs['time_diff']
self.alarm = kwargs['alarm']
self.OOC_L = kwargs['OOC_L']
self.OOC_H = kwargs['OOC_H']
self.OOS_L = kwargs['OOS_L']
self.OOS_H = kwargs['OOS_H']
self.target = kwargs['target']
conn = OracleConnect().conn()
# def exesql(sql):
# try:
# ret = conn.cursor().execute(sql)
# except:
# print("oracle已断开,重新获取连接")
# conn = OracleConnect().conn()
# ret = conn.cursor().execute(sql)
# return ret
# end = datetime.now()
# end = end.strftime("%Y-%m-%d %H:%M:%S")
# start = datetime.now() + timedelta(hours=-48)
# start = start.strftime("%Y-%m-%d %H:%M:%S")
#最新run货产品inline product_id_list and newest prod_id
def prod_id(**kwargs):
sql="""SELECT product_id,max(glass_start_time) MYTIME
FROM lcdsys.cf_pds_glass_t
WHERE
sub_equip_id = '{sub_equip_id_pds}'
AND glass_start_time BETWEEN TO_DATE('{start}','yy-MM-dd hh24:mi:ss')
AND TO_DATE('{end}','yy-MM-dd hh24:mi:ss')
GROUP BY product_id
ORDER BY MYTIME DESC"""
new_sql = sql.format(**kwargs)
#print(new_sql)
try:
global conn
ret = conn.cursor().execute(new_sql)
except:
logger.log_critical("oracle已断开,重新获取连接")
conn = OracleConnect().conn()
ret = conn.cursor().execute(new_sql)
prod_ls=[]
prod=""
prod_name=""
for item in ret:
prod_ls.append(item[0])
if len(prod_ls) > 0:
prod = prod_ls[0][0:3]
prod_name = prod_ls[0]
#print("xxxx",prod_ls,"xxxxx",prod)
return prod,prod_ls,prod_name
else:
logger.log_info("prod is null")
return prod, prod_ls, prod_name
# prod,prod_ls,prod_name = prod_id(#step_id_pds='3100_EXP',
# sub_equip_id_pds='1FOVNM10',
# #line_id='1FPHT1',
# start=start,
# end=end,
# )
# inline总Run货数
def glass_cnt_byLine(**kwargs):
sql="""select count(*) from lcdsys.cf_pds_glass_t
WHERE
step_id = '{step_id_pds}'
AND sub_equip_id = '{sub_equip_id_pds}'
AND product_id IN {prod_ls}
AND equip_id='{line_id}'
AND glass_start_time BETWEEN TO_DATE('{start}', 'yy-MM-dd hh24:mi:ss')
AND TO_DATE('{end}', 'yy-MM-dd hh24:mi:ss')"""
new_sql = sql.format(**kwargs)
ret = conn.cursor().execute(new_sql)
return ret.fetchone()[0]
# glass_total_cnt = glass_cnt_byLine(step_id_pds='3100_EXP',
# sub_equip_id_pds='1FEXPM10',
# line_id='1FPHT1',
# start=start,
# end=end,
# prod_ls=tuple(prod_ls)
# )
# print(glass_total_cnt)
#获取glass_id & glass_cnt by inspect EQ AND inline cot/exp
#返回玻璃数量、玻璃id list
def glass_info_byINSPEQ(**kwargs):
sql="""SELECT glass_id FROM lcdsys.cf_glass_t
WHERE
glass_id IN (
SELECT glass_id FROM lcdsys.cf_pds_glass_t
WHERE
sub_equip_id = '{sub_equip_id_pds}'
AND product_id IN {prod_ls}
AND step_id ='{step_id_pds}'
AND glass_start_time BETWEEN TO_DATE('{start}', 'yy-MM-dd hh24:mi:ss')
AND TO_DATE('{end}', 'yy-MM-dd hh24:mi:ss')
)
AND product_id IN {prod_ls}
AND step_id ='{step_id_insp}'
AND glass_start_time BETWEEN TO_DATE('{start}', 'yy-MM-dd hh24:mi:ss')
AND TO_DATE('{end}', 'yy-MM-dd hh24:mi:ss')
ORDER BY glass_start_time DESC"""
new_sql = sql.format(**kwargs)
#print(new_sql)
ret = conn.cursor().execute(new_sql)
ls = []
if ret:
for item in ret:
ls.append(item[0])
#print(ls)
return len(ls),ls
# glass_cnt,glasses = glass_info_byINSPEQ(step_id_pds="3100_EXP",
# sub_equip_id_pds="1FEXPM10",
# prod_ls=tuple(prod_ls),
# start=start,
# end=end,
# step_id_insp='3100_TPM')
# print("glass cnt",glass_cnt)
# print(glasses)
#获取数据,average,range,max,min,3sigma,time_diff,
def insp_summray_data(**kwargs):
sql="""SELECT glass_id,AVG(value) average,max(value)-min(value) range,
max(value) max,min(value) min,variance(value)*3 sigma3,max(glass_start_time) data_time
FROM lcdsys.cf_result_t
WHERE
glass_id IN {glasses}
AND param_name = '{param_name}'
AND step_id='{step_id_insp}'
AND glass_start_time BETWEEN TO_DATE('{start}', 'yy-MM-dd hh24:mi:ss')
AND TO_DATE('{end}', 'yy-MM-dd hh24:mi:ss')
GROUP BY glass_id
ORDER BY data_time"""
if len(kwargs['glasses'])>1:
new_sql = sql.format(**kwargs)
# qs = conn.cursor().execute(new_sql).fetchall()
df =pd.read_sql_query(sql=new_sql,con=conn)
# try:
# #print(df.head())
# #获取最新一片玻璃量测时间
# # print(df['DATA_TIME'].max())
# # last_time = df['DATA_TIME'].max().strftime("%Y-%m-%d %H:%M:%S")
# # # 最新一片玻璃量测时间与当前时间差值
# # time_diff=datetime.strptime(end,"%Y-%m-%d %H:%M:%S")-datetime.strptime(last_time,"%Y-%m-%d %H:%M:%S")
# # #换算成小时
# # time_diff = time_diff.seconds/60/60
average = df['AVERAGE'].mean()
range = df['RANGE'].mean()
max_value = df['MAX'].max()
min_value = df['MIN'].min()
sigma3 = df['SIGMA3'].mean()
#print(average,range,max_value,min_value,sigma3,time_diff)
return {
'average':average,
'range':range,
'max_value':max_value,
'min_value':min_value,
'sigma3':sigma3,
}
else:
#raise Exception("什么意思?summary data错误?")
logger.log_error("summary_data error,no data")
return {
'average':0,
'range':0,
'max_value':0,
'min_value':0,
'sigma3':0,
'time_diff':0,
}
# s = time.time()
#
# insp_summray_data(step_id_insp='3100_TPM',
# prod = prod,
# param_name='CD1',
# glasses=tuple(glasses),
# start=start,end=end)
# e = time.time()
# print("total cost time:",e-s)
#获取最新一片玻璃量测时间
def get_newtime_insp(**kwargs):
sql="""select max(glass_start_time) from lcdsys.cf_pds_glass_t
WHERE step_id = '{step_id_pds}'
AND sub_equip_id = '{sub_equip_id_pds}'
AND glass_id in {glasses}
AND product_id = '{prod_name}'
AND equip_id='{line_id}'
AND glass_start_time BETWEEN TO_DATE('{start}', 'yy-MM-dd hh24:mi:ss')
AND TO_DATE('{end}', 'yy-MM-dd hh24:mi:ss')"""
new_sql = sql.format(**kwargs)
#print(new_sql)
if len(kwargs['glasses'])>1:
ret = conn.cursor().execute(new_sql)
return ret.fetchone()[0]
else:
#logger.log_info("insp glass cnt < 1")
return datetime.now()
#获取原始数据
def insp_rawdata(**kwargs):
if kwargs['time_asc']==0:
sql="""SELECT r.glass_id,t.glass_start_time t_time,r.site_name,r.value,r.glass_start_time r_time
FROM lcdsys.cf_result_t r, lcdsys.cf_pds_glass_t t
WHERE
r.glass_id = t.glass_id
AND t.step_id = '{step_id_pds}'
AND r.glass_id IN {glasses}
AND r.param_name = '{param_name}'
AND r.step_id='{step_id_insp}'
AND r.glass_start_time BETWEEN TO_DATE('{start}', 'yy-MM-dd hh24:mi:ss')
AND TO_DATE('{end}', 'yy-MM-dd hh24:mi:ss')
ORDER BY r.site_name asc,t.glass_start_time"""
else:
sql="""SELECT r.glass_id,t.glass_start_time t_time,r.site_name,r.value,r.glass_start_time r_time
FROM lcdsys.cf_result_t r, lcdsys.cf_pds_glass_t t
WHERE
r.glass_id = t.glass_id
AND t.step_id = '{step_id_pds}'
AND r.glass_id IN {glasses}
AND r.param_name = '{param_name}'
AND r.step_id='{step_id_insp}'
AND r.glass_start_time BETWEEN TO_DATE('{start}', 'yy-MM-dd hh24:mi:ss')
AND TO_DATE('{end}', 'yy-MM-dd hh24:mi:ss')
ORDER BY t.glass_start_time,r.site_name asc"""
if len(kwargs['glasses'])>1:
new_sql = sql.format(**kwargs)
print(new_sql)
ret = conn.cursor().execute(new_sql)
return ret
else:
return None
前端导航栏(特性按钮栏)
{% include 'report/common/header.html' %}
<script src="/static/js/echarts.min.js"></script>
<div STYLE="padding-top:5px">
<!-- Standard button -->
<button type="button" class="btn btn-default" id="BM1CD" STYLE="background-color:#696969;color:white;">
BM CD
</button>
<button type="button" class="btn btn-default" STYLE="background-color:#696969;color:white;">
BM TTP
</button>
<button type="button" class="btn btn-default" STYLE="background-color:#696969;color:white;">
BM TKS
</button>
<button type="button" class="btn btn-danger">R TKS</button>
<button type="button" class="btn btn-danger" id="R1CD">R CD</button>
<button type="button" class="btn btn-success">G TKS</button>
<button type="button" class="btn btn-success" id="G1CD">G CD</button>
<button type="button" class="btn btn-primary">B TKS</button>
<button type="button" class="btn btn-primary" id="B1CD">B CD</button>
<button type="button" class="btn btn-warning">PSH Chart</button>
<button type="button" class="btn btn-warning" id="PS1CD">PS CD&段差</button>
<button type="button" class="btn btn-warning">PS OL</button>
<button type="button" class="btn btn-warning">ITO/OC</button>
</div>
{% include 'report/pe/big_CD.html'%}
<script src="/static/js/jquery-1.11.3.min.js"></script>
<script>
$(function(){
$("#BM1CD").click(function(){
window.location.href="/insp/pe/bigcd_chart?param=BM1_CD"
});
$("#R1CD").click(function(){
window.location.href="/insp/pe/bigcd_chart?param=R1_CD"
});
$("#G1CD").click(function(){
window.location.href="/insp/pe/bigcd_chart?param=G1_CD"
});
$("#B1CD").click(function(){
window.location.href="/insp/pe/bigcd_chart?param=B1_CD"
});
$("#PS1CD").click(function(){
window.location.href="/insp/pe/bigcd_chart?param=PS1_CD"
});
});
</script>
</body>
</html>
前端echarts主要代码:
<style>
.chart-H{
width: 100%;
height: 300px;
}
.mychart{
width: 100%;
height:90%;
background-color:white;
padding-left:5%;
padding-right:5%;
}
.mark{
height: 10%;
text-align: center;
font-family: 'Arial';
padding-top: 10px;
}
.content{
float:left;
height:100%;
width: 50%;
}
</style>
<div>
<div class="chart-H">
<div class="content">
<div class="mark">
{{line}} {{chart1.obj.product_id}} {{chart1.obj.param_name}} {{chart1.obj.sub_equip_id_pds}}
</div>
<div id="chart1-1" class="mychart"> </div>
</div>
<div class="content">
<div class="mark">
{{line}} {{chart2.obj.product_id}} {{chart2.obj.param_name}} {{chart2.obj.sub_equip_id_pds}}
</div>
<div id="chart1-2" class="mychart"> </div>
</div>
</div>
<div class="chart-H">
<div class="content">
<div class="mark">
{{line}} {{chart1.obj.product_id}} {{chart1.obj.param_name}} {{chart1.obj.sub_equip_id_pds}}
</div>
<div id="chart2-1" class="mychart"> </div>
</div>
<div class="content">
<div class="mark">
{{line}} {{chart2.obj.product_id}} {{chart2.obj.param_name}} {{chart2.obj.sub_equip_id_pds}}
</div>
<div id="chart2-2" class="mychart"> </div>
</div>
</div>
</div>
<script>
var myChart11 = echarts.init(document.getElementById('chart1-1'));
option = {
tooltip : {
trigger: 'axis',
axisPointer : { // 坐标轴指示器,坐标轴触发有效
type : 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
xAxis: {
type: 'category',
data: {{ chart1.x_data|safe }},
axisLabel: {
// interval: 0,
rotate: 45, // 20度角倾斜显示(***这里是关键)
}
},
yAxis: {
type: 'value',
min: {{chart1.obj.OOS_H|safe}},
max: {{chart1.obj.OOS_L|safe}},
splitLine: {
show: false
}
},
visualMap: {
top: 10,
right: 10,
pieces: [{
gt: {{chart1.obj.OOC_L|safe}},
lte: {{chart1.obj.OOC_H|safe}},
color: '#0000ff'
}],
outOfRange: {
color: 'red'
}
},
series: [
{{ chart1.y_data|safe}}
]
};
myChart11.setOption(option);
</script>
<script>
var myChart12 = echarts.init(document.getElementById('chart1-2'));
option = {
tooltip : {
trigger: 'axis',
axisPointer : { // 坐标轴指示器,坐标轴触发有效
type : 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
xAxis: {
type: 'category',
data: {{ chart2.x_data|safe }},
axisLabel: {
// interval: 0,
rotate: 45, // 20度角倾斜显示(***这里是关键)
}
},
yAxis: {
type: 'value',
min: {{chart2.obj.OOS_H|safe}},
max: {{chart2.obj.OOS_L|safe}},
splitLine: {
show: false
}
},
visualMap: {
top: 10,
right: 10,
pieces: [{
gt: {{chart2.obj.OOC_L|safe}},
lte: {{chart2.obj.OOC_H|safe}},
color: '#0000ff'
}],
outOfRange: {
color: 'red'
}
},
series: [
{{ chart2.y_data|safe}}
]
};
myChart12.setOption(option);
</script>
<script>
var myChart21 = echarts.init(document.getElementById('chart2-1'));
option = {
tooltip : {
trigger: 'axis',
axisPointer : { // 坐标轴指示器,坐标轴触发有效
type : 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
xAxis: {
type: 'category',
data: {{ chart1.x_data2|safe }},
axisLabel: {
// interval: 0,
rotate: 45, // 20度角倾斜显示(***这里是关键)
}
},
yAxis: {
type: 'value',
min: {{chart1.obj.OOS_H|safe}},
max: {{chart1.obj.OOS_L|safe}},
splitLine: {
show: false
}
},
visualMap: {
top: 10,
right: 10,
pieces: [{
gt: {{chart1.obj.OOC_L|safe}},
lte: {{chart1.obj.OOC_H|safe}},
color: '#0000ff'
}],
outOfRange: {
color: 'red'
}
},
series: [
{{ chart1.y_data2|safe}}
]
};
myChart21.setOption(option);
</script>
<script>
var myChart22 = echarts.init(document.getElementById('chart2-2'));
option = {
tooltip : {
trigger: 'axis',
axisPointer : { // 坐标轴指示器,坐标轴触发有效
type : 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
xAxis: {
type: 'category',
data: {{ chart2.x_data2|safe }},
axisLabel: {
// interval: 0,
rotate: 45, // 20度角倾斜显示(***这里是关键)
}
},
yAxis: {
type: 'value',
min: {{chart2.obj.OOS_H|safe}},
max: {{chart2.obj.OOS_L|safe}},
splitLine: {
show: false
}
},
visualMap: {
top: 10,
right: 10,
pieces: [{
gt: {{chart2.obj.OOC_L|safe}},
lte: {{chart2.obj.OOC_H|safe}},
color: '#0000ff'
}],
outOfRange: {
color: 'red'
}
},
series: [
{{ chart2.y_data2|safe}}
]
};
myChart22.setOption(option);
</script>