参考:https://docs.rstudio.com/shinyapps.io/
1. 日期计算
链接:https://dingdangsunny.shinyapps.io/DateCalculate/
练习Shiny基本输入输出。
library(shiny)
ui <- fluidPage(
titlePanel("使用Shiny进行日期计算"),
h4(textOutput("currentTime")),
helpText("请输入起止日期,计算日期间隔。"),
helpText("默认计算当前日期与今年1月1日的间隔。"),
dateRangeInput(inputId = "daterange", label = "日期范围:",
start = as.Date(paste(format(Sys.time()+8*60*60,
"%Y"),
"/01/01",sep = ""),
"%Y/%m/%d"),
end = as.Date(format(Sys.time()+8*60*60,
"%Y/%m/%d"),
"%Y/%m/%d")),
textOutput("datedif"),
tags$hr(),
helpText("请输入起始日期和日期间隔,推算目标日期。"),
helpText("(输入负数则为向前推算。)"),
dateInput(inputId = "date", label = "起始日期:"),
numericInput(inputId = "days", label = "日期间隔:",
value = 100),
textOutput("dateaft")
)
server <- function(input, output, session) {
output$currentTime <- renderText({
invalidateLater(1000, session)
paste("当前时间是", Sys.time()+8*60*60)
})
output$datedif <- renderText({
paste("相距", diff(input$daterange), "天")
})
output$dateaft <- renderText({
d <- input$date + input$days
paste("推算得日期为", d, format.Date(d,"%A"))
})
}
shinyApp(ui = ui, server = server)
这里时间加8小时调整一下时区。
界面:

APP链接:https://dingdangsunny.shinyapps.io/DateCalculate/
2. FFT
关于FFT(快速傅里叶变换):https://www.cnblogs.com/dingdangsunny/p/12573744.html
链接:https://dingdangsunny.shinyapps.io/FastFourierTransform/
2.1 源代码
global.R
library(dplyr)
FFT<-function(data, Fs, isDetrend=TRUE)
{
# 快速傅里叶变换
# data:波形数据
# Fs:采样率
# isDetrend:逻辑值,是否进行去均值处理,默认为true
# 返回[Fre:频率,Amp:幅值,Ph:相位(弧度)]
n=length(data)
if(n%%2==1)
{
n=n-1
data=data[1:n]
}
if(n<4)
{
result<-data.frame(Fre=0,Amp=0,Ph=0)
return(result)
}
if(isDetrend)
{
data<-scale(data,center=T,scale=F)
}
library(stats)
Y = fft(data)
#频率
Fre=(0:(n-1))*Fs/n
Fre=Fre[1:(n/2)]
#幅值
Amp=Mod(Y[1:(n/2)])
Amp[c(1,n/2)]=Amp[c(1,n/2)]/n
Amp[2:(n/2-1)]=Amp[2:(n/2-1)]/(n/2)
#相位
Ph=Arg(Y[1:(n/2)])
result<-data.frame(Fre=Fre,Amp=Amp,Ph=Ph)
return(result)
}
SUB<-function(t,REG)
{
# 通过正则表达式提取输入数据
m<-gregexpr(REG, t)
start<-m[[1]]
stop<-start+attr(m[[1]],"match.length")-1
l<-length(start)
r<-rep("1",l)
for(i in 1:l)
{
r[i]<-substr(t,start[i],stop[i])
}
return(r)
}
#生成示例信号
deg2rad<-function(a)
{
return(a*pi/180)
}
N = 256
Fs = 150
t = (0:(N-1))/Fs
wave = (5 + 8*cos(2*pi*10.*t) +
4*cos(2*pi*20.*t + deg2rad(30)) +
2*cos(2*pi*30.*t + deg2rad(60)) +
1*cos(2*pi*40.*t + deg2rad(90)) +
rnorm(length(t))) %>%
paste(collapse = ",")
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("使用Shiny进行FFT分析"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "input_mode",
label = "选择一种数据输入方式",
choices = c("文本输入", "上传文件")),
textAreaInput(inputId = "data",
label = "原始数据:",
value = wave,
rows = 10),
fileInput("file", "选择CSV文件进行上传",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
checkboxInput("header", "是否有表头", TRUE),
radioButtons("sep", "分隔符",
choices = c("逗号" = ",",
"分号" = ";",
"制表符" = " "),
selected = ","),
numericInput(inputId = "Fs",
label = "采样频率:",
value = 150),
sliderInput("xlim", "x坐标范围:",
min = 0, max = 1,
value = c(0,1)),
sliderInput("ylim", "y坐标范围:",
min = 0, max = 1,
value = c(0,1)),
checkboxInput("isDetrend", "数据中心化", TRUE),
checkboxInput("showgrid", "添加网格线", TRUE)
),
mainPanel(
tabsetPanel(
type = "tabs",
tabPanel("图像", plotOutput(outputId = "data_in"),
plotOutput(outputId = "result")),
tabPanel("频谱",
helpText("频谱分析结果如下。"),
helpText("输入基频获取THD计算结果。"),
numericInput(inputId = "fund",
label = "基频:",
value = 10),
verbatimTextOutput("THD"),
numericInput(inputId = "num",
label = "展示几行数据:",
value = 15),
downloadButton("downloadData", "下载数据"),
tableOutput("resultview")
),
tabPanel("帮助",
helpText("这是一个基于Shiny创建的网页程序,
可以进行快速傅里叶变换(FFT)。",
"了解Shiny请访问:",
a(em("https://shiny.rstudio.com/"),
href="https://shiny.rstudio.com/")),
helpText("您可以选择在文本框中输入原始数据或通过CSV文件进行上传,
文本框中的数据应由逗号或空格分隔开,CSV中的数据应处于表格
的第一列。图像面板中向您展示了原始数据的序列和FFT变换后的结果,
通过x和y坐标范围的滑块,可以将分析结果的图形进行放大。
如果勾选了数据中心化的复选框,则将滤除直流成分,否则将保留。
在频谱面板中,可以查看FFT分析的数值结果并进行下载,通过输入基频,
可以获得总谐波失真(THD)计算结果。"),
helpText("源代码和演示示例请访问:",
a(em("叮叮当当sunny的博客"),
href="https://www.cnblogs.com/dingdangsunny/p/12586274.html#_label1"),
"")
)
)
)
)
))
server.R
library(shiny)
library(dplyr)
shinyServer(function(input, output) {
data <- reactive({
if(input$input_mode=="文本输入")
{
return(SUB(input$data,"[-0-9.]+") %>%
as.numeric())
}
else if(input$input_mode=="上传文件")
{
req(input$file)
data <- read.csv(input$file$datapath,
header = input$header,
sep = input$sep)
return(data[,1])
}
})
result <- reactive({
FFT(data(), input$Fs, input$isDetrend)
})
output$data_in <- renderPlot({
ylabel <- function()
{
if(input$input_mode=="上传文件" & input$header==TRUE)
return((read.csv(input$file$datapath,
header = TRUE, sep = input$sep) %>%
names())[1])
else
return("value")
}
par(mai=c(1,1,0.5,0.5))
plot((1:length(data()))/input$Fs, data(),
type = "l", main = "The original data",
xlab = "time/s", ylab = ylabel())
if(input$showgrid)
{
grid(col = "darkblue", lwd = 0.5)
}
})
output$result <- renderPlot({
Fre_max <- max(result()$Fre)
Amp_max <- max(result()$Amp)
x_ran <- (input$xlim*1.1-0.05)*Fre_max
y_ran <- (input$ylim*1.1-0.05)*Amp_max
par(mai=c(1,1,0.5,0.5))
plot(result()$Fre, result()$Amp, type = "l",
xlab = "Frequency/Hz", ylab = "Amplitude",
main = "FFT analysis results",
xlim = x_ran, ylim = y_ran)
if(input$showgrid)
{
grid(col = "darkblue", lwd = 0.5)
}
})
output$resultview <- renderTable({
r <- cbind(result()[1:input$num,],
result()[(1+input$num):(2*input$num),])
names(r) <- rep(c("频率", "幅值", "相位"), 2)
r
})
output$THD <- renderPrint({
n <- floor(dim(result())[1]/input$fund)
A <- rep(0, n)
for(i in 1:n)
{
A[i] <- result()$Amp[which(abs(result()$Fre-i*input$fund)==
min(abs(result()$Fre-i*input$fund)))]
}
THD <- sqrt(sum((A[2:n])^2)/(A[1])^2)
cat("总谐波失真THD = ",THD*100,"%",sep = "")
})
output$downloadData <- downloadHandler(
filename = function() {
return("FFTresult.csv")
},
content = function(file) {
write.csv(result(), file)
}
)
})
2.2 测试
由默认数据集测试得到界面如下:

频率数据界面:

帮助文本界面:

用https://www.cnblogs.com/dingdangsunny/p/12573744.html#_label2中提到的数据进行文件上传测试。

APP链接:https://dingdangsunny.shinyapps.io/FastFourierTransform/
另外,发现了一个用Shiny写的有趣的小工具,http://qplot.cn/toolbox/,可以一试……