半導體封裝行業已經實現工廠自動化中,涉及到一些作業流程,也產生了很多的alarm及過站信息,需要做個dashboard看板,將報警和過站信息結合起來看。
利用R的shiny包可以很快的構架數據看板。代碼如下:
ui.R:
library(shiny)
library(shinydashboard)
library(DT)
library(ggplot2)
library(tidyr)
library(rCharts)
library(dplyr)
library(stringr)
library(plotly)
library(ggthemes)
dashboardPage(skin="green",
dashboardHeader(title="Automatic product data display"),
dashboardSidebar(
sidebarMenu(
menuItem("Data",tabName="unload",icon=icon('table'),
menuItem("EAPAlertfile",tabName="Alert",icon=icon('chain')),
menuItem('EAPTrackfile',tabName='Track',icon=icon('chain'))),
menuItem("EAP_Alert",tabName="EAPAlert",icon=icon('plus-circle'),
menuItem("EAPAlert",tabName="EAPAlertChart",icon=icon('bar-chart')),
menuItem("EAPAlert by day",tabName="EAPAlert_Per",icon=icon('bar-chart')),
menuItem("EAPAlert of 24h",tabName="EAPAlert_24",icon=icon('bar-chart'))),
#selectInput("EAPAlert_24","選擇報警",c(unique(Alertfile$process))),
menuItem("EAPtrackout",tabName="EAPTrackChart",icon=icon('train'),
menuItem("EAPTrackin",tabName="EAPTrackinChart",icon=icon('line-chart')),
menuItem("EAPTrackout",tabName="EAPTrackoutChart",icon=icon('line-chart'))),
menuItem("Handle data",tabName="Merge_Analysis",icon=icon('cog'),
menuItem("Merge",tabName="merge_data",icon=icon('th')),
menuItem("Chart anlisis",tabName="TrackAlert_chart",icon=icon('picture-o'))),
selectInput("process","Process seletion",c("Sputter","Coating","Exposing","Developing","Plating","Wet","AOI","Descume","Curing","SAW","LaserMark")),
selectInput("currentstate","EAPAlert station selection",c("S_QueryCarrierInfo","S_CheckRecipeBody","S_QueryLotInfo","S_CheckEquipmentOnOperation")))),
dashboardBody(
tabItems(
tabItem(tabName="Alert",fileInput("EAPAlert_file","Select EAP_Alert.csv file to upload",accept=c('text/csv','text/comma-separated-values,text/plain',".csv")),
DT::dataTableOutput("EAPAlert")),
tabItem(tabName="Track",fileInput("EAPtrack_file","Select EAP track file to upload",accept = c('text/csv','text/comma-separated-values,text/plain',".csv")),
DT::dataTableOutput("EAPtrack")),
tabItem(tabName="EAPAlertChart",
box(title="EAP Alert Chart",width=12,solidHeader = TRUE,status="success",plotOutput("AlertChart"))),
tabItem(tabName="EAPAlert_Per",
box(title="EAP Alert by day",width=12,solidHeader = TRUE,status="success",plotOutput("Alertbyday"))),
tabItem(tabName="EAPAlert_24",
box(title="EAPAlert in 24h",width=12,solidHeader = TRUE,status="success",plotOutput("AlertChart_24"))),
tabItem(tabName="EAPTrackinChart",
box(title="Operation Menthod",width=12,solidHeader=TRUE,status="success",plotOutput("TrackChart"))),
tabItem(tabName="EAPTrackoutChart",
box(title="Lot trackout statistics",width=12,solidHeader=TRUE,status="success",plotOutput("TrackoutChart"))),
tabItem(tabName="merge_data",
fluidRow(
box(title="Data display",width=12,solidHeader=TRUE,status="success",DT::dataTableOutput("TrackAlertfile")),
box(width=2,actionButton("data_merge","Action",icon=icon("car"))))),
tabItem(tabName="TrackAlert_chart",
fluidRow(
box(title="EAP Alert & trackout",width=12,solidHeader=TRUE,status="success",plotOutput("TrackAlertChart"))))
)
)
)
server.R
options(shiny.maxRequestSize=30*1024^2)
function(input,output){
Alertfile
if(is.null(input$EAPAlert_file))
return(NULL)
F
F$gongxu
F$Alarm
attach(F)
F$gongxu[str_detect(sEquipmentId,"AOI")==TRUE]
F$gongxu[str_detect(sEquipmentId,"PLA")==TRUE]
F$gongxu[str_detect(sEquipmentId,"REF")==TRUE]
F$gongxu[str_detect(sEquipmentId,"ETC")==TRUE]
F$gongxu[str_detect(sEquipmentId,"OSB")==TRUE]
F$gongxu[str_detect(sEquipmentId,"STP")==TRUE]
F$gongxu[str_detect(sEquipmentId,"WEE")==TRUE]
F$gongxu[str_detect(sEquipmentId,"SDV")==TRUE]
F$gongxu[str_detect(sEquipmentId,"WYO")==TRUE]
F$gongxu[str_detect(sEquipmentId,"DES")==TRUE]
F$gongxu[str_detect(sEquipmentId,"GPD")==TRUE]
F$gongxu[str_detect(sEquipmentId,"KSM")==TRUE]
F$gongxu[str_detect(sEquipmentId,"NIM")==TRUE]
F$gongxu[str_detect(sEquipmentId,"PVD")==TRUE]
F$gongxu[str_detect(sEquipmentId,"SCB")==TRUE]
F$gongxu[str_detect(sEquipmentId,"MEA")==TRUE]
F$gongxu[str_detect(sEquipmentId,"SAW")==TRUE]
F$gongxu[str_detect(sEquipmentId,"LMK")==TRUE]
F$Alarm[grepl("MES機臺狀態",sErrorContent)==TRUE]
F$Alarm[grepl("MES檢查機臺狀態",sErrorContent)==TRUE]
F$Alarm[grepl("MES檢查機臺工步",sErrorContent)==TRUE]
F$Alarm[grepl("MES檢查PDE設定",sErrorContent)==TRUE]
F$Alarm[grepl("無法與MES",sErrorContent)==TRUE]
F$Alarm[grepl("MES中該Lot",sErrorContent)==TRUE]
F$Alarm[grepl("MES進站失敗",sErrorContent)==TRUE]
F$Alarm[grepl("MES出站失敗",sErrorContent)==TRUE]
F$Alarm[grepl("服務器中不存在當前",sErrorContent)==TRUE]
F$Alarm[grepl("RMS檢查未過關",sErrorContent)==TRUE]
F$Alarm[grepl("超過30天未驗證RMS",sErrorContent)==TRUE]
F$Alarm[grepl("機臺內未找到Lot要用的程序",sErrorContent)==TRUE]
F$Alarm[grepl("機臺未完全IDLE",sErrorContent)==TRUE]
F$Alarm[grepl("機臺拒絕",sErrorContent)==TRUE]
F$Alarm[grepl("機臺設備軟件界面上必須顯示Ready狀態",sErrorContent)==TRUE]
F$Alarm[grepl("機臺前一狀態為ProcessingAbort",sErrorContent)==TRUE]
F$Alarm[grepl("發送PP_Select命令失敗",sErrorContent)==TRUE]
F$Alarm[grepl("類似Lot的程序",sErrorContent)==TRUE]
F$Alarm[grepl("程序不同",sErrorContent)==TRUE]
F$Alarm[grepl("IDLE超過2小時",sErrorContent)==TRUE]
F$Alarm[grepl("光罩",sErrorContent)==TRUE]
F$Alarm[grepl("通過productrrn值找不到相應的數據",sErrorContent)==TRUE]
F$Alarm[grepl("Dummy批次",sErrorContent)==TRUE]
F$Alarm[grepl("無法發送詢問Load命令給機臺",sErrorContent)==TRUE]
F$Alarm[grepl("EAP出站失敗",sErrorContent)==TRUE]
F$Alarm[grepl("掃",sErrorContent)==TRUE]
F$Alarm[grepl("中不存在",sErrorContent)==TRUE]
F$Alarm[grepl("mismatch",sErrorContent)==TRUE]
F$Alarm[grepl("超過2小時",sErrorContent)==TRUE]
F$Alarm[grepl("不在OnlineRemote",sErrorContent)==TRUE]
F$Alarm[grepl("請通知CIM值班人員",sErrorContent)==TRUE]
F$Alarm[grepl("首檢",sErrorContent)==TRUE]
F$Alarm[grepl("已劃過",sErrorContent)==TRUE]
F$Alarm[grepl("腔體實際",sErrorContent)==TRUE]
detach(F)
print(F)
})
Trackfile
if(is.null(input$EAPtrack_file))
return(NULL)
T
attach(T)
T$trackInEmp[str_detect(trackInEmp,'^[0-9]')==TRUE]
# T$trackOutEmp[str_detect(trackOutEmp,'[0-9]')==TRUE]
T$trackOutEmp[str_detect(trackOutEmp,"[a-zA-Z0-9]")==FALSE]
# 工序劃分
T$gongxu[str_detect(machineId,"AOI")==TRUE]
T$gongxu[str_detect(machineId,"PLA")==TRUE]
T$gongxu[str_detect(machineId,"REF")==TRUE]
T$gongxu[str_detect(machineId,"ETC")==TRUE]
T$gongxu[str_detect(machineId,"OSB")==TRUE]
T$gongxu[str_detect(machineId,"STP")==TRUE]
T$gongxu[str_detect(machineId,"WEE")==TRUE]
T$gongxu[str_detect(machineId,"SDV")==TRUE]
T$gongxu[str_detect(machineId,"MEA")==TRUE]
T$gongxu[str_detect(machineId,"WYO")==TRUE]
T$gongxu[str_detect(machineId,"DES")==TRUE]
T$gongxu[str_detect(machineId,"GPD")==TRUE]
T$gongxu[str_detect(machineId,"KSM")==TRUE]
T$gongxu[str_detect(machineId,"NIM")==TRUE]
T$gongxu[str_detect(machineId,"PVD")==TRUE]
T$gongxu[str_detect(machineId,"SCB")==TRUE]
T$gongxu[str_detect(machineId,"SAW")==TRUE]
T$gongxu[str_detect(machineId,"LMK")==TRUE]
detach(T)
print(T)
})
output$EAPAlert
DT::datatable(Alertfile(),rownames = F)
})
output$EAPtrack
DT::datatable(Trackfile(),rownames= F)
})
output$AlertChart
if(is.null(input$EAPAlert_file))
return(NULL)
A
A%>%filter(gongxu==input$process)%>%
ggplot(aes(x=sEquipmentId,fill=Alarm))+
geom_bar(stat="count",position="stack")+theme_economist()+
theme(axis.title.y=element_blank(),axis.title.x=element_blank(),legend.position = "bottom",legend.text=element_text(size=10))+
geom_text(aes(label=..count..),stat="count")+
coord_flip()
})
output$Alertbyday
if(is.null(input$EAPAlert_file))
return(NULL)
A
A%>%filter(gongxu==input$process)%>%
filter(sCurrentState==input$currentstate)%>%
separate(tCreationDate,c("Date","Time"),sep=' ')%>%
group_by(Date,sCurrentState)%>%
summarise(number=n())%>%
ggplot(aes(x=Date,y=number))+geom_bar(stat="identity",fill="red")+theme_economist()+
geom_text(aes(label=number))+
theme(axis.title=element_blank())
})
# 查看24小時報警圖,確認是否網絡問題導致
output$AlertChart_24
if(is.null(input$EAPAlert_file))
return(NULL)
A
A%>%filter(sCurrentState==input$currentstate)%>%
filter(gongxu==input$process)%>%
separate(tCreationDate,c("Date","Time"),sep=' ')%>%
separate(Time,c("Hour","Min"),sep=":")%>%unite(Minute,Hour,Min,sep=":")%>%
group_by(sCurrentState,Minute)%>%
summarise(number=n())%>%
ggplot(aes(x=as.factor(Minute),y=number))+geom_bar(stat="identity",fill="red")+theme_economist()+
theme(axis.text.x=element_text(angle=90),axis.title.x=element_blank())
})
#進站review
output$TrackChart
if(is.null(input$EAPtrack_file))
return(NULL)
T
T%>%filter(gongxu==input$process)%>%
ggplot(aes(machineId,fill=trackInEmp))+
geom_bar(stat="count",position="stack")+theme_economist()+
theme(axis.title.y=element_blank(),legend.position = "top",axis.title.x=element_blank())+
geom_text(aes(label=..count..),stat="count")+coord_flip()
})
#出站異常問題查看
output$TrackoutChart
if(is.null(input$EAPtrack_file))
return(NULL)
T
T%>%filter(gongxu==input$process)%>%
ggplot(aes(machineId,fill=trackOutEmp))+
geom_bar(stat="count",position="stack")+theme_economist()+
theme(axis.title.y = element_blank(),legend.position = "top",axis.title.x=element_blank())+
geom_text(aes(label=..count..),stat="count")+coord_flip()
})
Merge_file
if(is.null(input$EAPtrack_file)|is.null(input$EAPAlert_file))
return(NULL)
Af
Tf
F
print(F)
})
output$TrackAlertfile
DT::datatable(Merge_file(),rownames = F)
})
output$TrackAlertChart
M
M%>%filter(gongxu.x==input$process)%>%filter(trackInEmp!='NA')%>%
ggplot(aes(as.factor(Alarm),sLotId,color=trackInEmp))+geom_point()+theme_economist()+
theme(axis.text.x=element_text(angle=90 ,color='red',vjust=0),axis.title.x=element_blank(),legend.position="top")
#nPlot(sEquipmentId~lotId,group='trackOutEmp',data=M,type="scatterChart")
})
}
運行代碼後:
因部分原因無法連接數據庫,使用本地上傳文件的方式
24H分析報警,有時需要確認在同1分鐘內某個報警是否增多,來判斷網絡異常
過站信息統計,非EAP和EAP
出站信息統計
報警和進站的關係圖