sugitora commited on
Commit
532543a
·
verified ·
1 Parent(s): 68ceaa9

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +165 -47
app.R CHANGED
@@ -1,58 +1,176 @@
 
 
1
  library(shiny)
2
- library(bslib)
3
  library(dplyr)
4
- library(ggplot2)
5
-
6
- df <- readr::read_csv("penguins.csv")
7
- # Find subset of columns that are suitable for scatter plot
8
- df_num <- df |> select(where(is.numeric), -Year)
9
-
10
- ui <- page_sidebar(
11
- theme = bs_theme(bootswatch = "minty"),
12
- title = "Penguins explorer",
13
- sidebar = sidebar(
14
- varSelectInput("xvar", "X variable", df_num, selected = "Bill Length (mm)"),
15
- varSelectInput("yvar", "Y variable", df_num, selected = "Bill Depth (mm)"),
16
- checkboxGroupInput("species", "Filter by species",
17
- choices = unique(df$Species), selected = unique(df$Species)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  ),
19
- hr(), # Add a horizontal rule
20
- checkboxInput("by_species", "Show species", TRUE),
21
- checkboxInput("show_margins", "Show marginal plots", TRUE),
22
- checkboxInput("smooth", "Add smoother"),
23
- ),
24
- plotOutput("scatter")
 
 
25
  )
26
 
 
 
 
 
27
  server <- function(input, output, session) {
28
- subsetted <- reactive({
29
- req(input$species)
30
- df |> filter(Species %in% input$species)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  })
32
-
33
- output$scatter <- renderPlot(
34
- {
35
- p <- ggplot(subsetted(), aes(!!input$xvar, !!input$yvar)) +
36
- theme_light() +
37
- list(
38
- theme(legend.position = "bottom"),
39
- if (input$by_species) aes(color = Species),
40
- geom_point(),
41
- if (input$smooth) geom_smooth()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  )
43
-
44
- if (input$show_margins) {
45
- margin_type <- if (input$by_species) "density" else "histogram"
46
- p <- p |> ggExtra::ggMarginal(
47
- type = margin_type, margins = "both",
48
- size = 8, groupColour = input$by_species, groupFill = input$by_species
 
 
 
 
 
 
 
49
  )
50
- }
51
-
52
- p
53
- },
54
- res = 100
55
- )
 
 
 
 
 
 
56
  }
57
 
58
- shinyApp(ui, server)
 
1
+ # app.R
2
+
3
  library(shiny)
 
4
  library(dplyr)
5
+ library(lubridate)
6
+ library(leaflet)
7
+
8
+ set.seed(123)
9
+
10
+ # =========================
11
+ # 1. ダミーデータ作成
12
+ # =========================
13
+
14
+ # 工事現場(北海道の適当な範囲でランダム)
15
+ sites <- tibble::tibble(
16
+ site_id = 1:5,
17
+ site_name = paste0("工事現場", 1:5),
18
+ city = c("札幌市", "札幌市", "旭川市", "函館市", "帯広市"),
19
+ lat = runif(5, 42.0, 44.5), # 北海道っぽい緯度
20
+ lng = runif(5, 141.0, 143.5), # 北海道っぽい経度
21
+ start = as.Date("2025-12-01"),
22
+ end = as.Date("2025-12-31"),
23
+ required_guards = c(3, 4, 2, 5, 3)
24
+ )
25
+
26
+ cities <- sites$city
27
+
28
+ # 警備員(住所は市レベルで、対応可能期間は12月中でバラバラ)
29
+ guards <- tibble::tibble(
30
+ guard_id = 1:20,
31
+ guard_name = paste0("警備員", 1:20),
32
+ city = sample(cities, 20, replace = TRUE),
33
+ lat = runif(20, 42.0, 44.5),
34
+ lng = runif(20, 141.0, 143.5),
35
+ available_from = sample(seq(as.Date("2025-12-01"), as.Date("2025-12-15"), by = "day"),
36
+ 20, replace = TRUE),
37
+ available_to = sample(seq(as.Date("2025-12-16"), as.Date("2025-12-31"), by = "day"),
38
+ 20, replace = TRUE)
39
+ ) %>%
40
+ # from <= to になるように補正
41
+ mutate(
42
+ tmp_min = pmin(available_from, available_to),
43
+ tmp_max = pmax(available_from, available_to),
44
+ available_from = tmp_min,
45
+ available_to = tmp_max
46
+ ) %>%
47
+ select(-tmp_min, -tmp_max)
48
+
49
+ # =========================
50
+ # 2. UI
51
+ # =========================
52
+
53
+ ui <- fluidPage(
54
+ titlePanel("北海道・工事現場 × 警備員マッチング(ダミーデータ)"),
55
+ sidebarLayout(
56
+ sidebarPanel(
57
+ dateInput(
58
+ "selected_date",
59
+ "日付を選択",
60
+ value = as.Date("2025-12-01"),
61
+ min = as.Date("2025-12-01"),
62
+ max = as.Date("2025-12-31")
63
+ ),
64
+ checkboxInput("show_guards", "警備員の位置も地図に表示", TRUE),
65
+ width = 3
66
  ),
67
+ mainPanel(
68
+ leafletOutput("map", height = 500),
69
+ br(),
70
+ h4("工事現場別マッチング状況(選択日ベース)"),
71
+ tableOutput("summary"),
72
+ width = 9
73
+ )
74
+ )
75
  )
76
 
77
+ # =========================
78
+ # 3. Server
79
+ # =========================
80
+
81
  server <- function(input, output, session) {
82
+
83
+ # 選択日ごとのデータ
84
+ daily_data <- reactive({
85
+ d <- input$selected_date
86
+
87
+ # その日に稼働中の現場(期間内)
88
+ active_sites <- sites %>%
89
+ filter(start <= d, end >= d)
90
+
91
+ # その日に勤務可能な警備員
92
+ available_guards <- guards %>%
93
+ filter(available_from <= d, available_to >= d)
94
+
95
+ list(
96
+ date = d,
97
+ active_sites = active_sites,
98
+ available_guards = available_guards
99
+ )
100
  })
101
+
102
+ # マッチング集計(ここでは「同じ市にいる警備員数」で集計)
103
+ summary_tbl <- reactive({
104
+ dd <- daily_data()
105
+ active_sites <- dd$active_sites
106
+ available_guards <- dd$available_guards
107
+
108
+ guards_by_city <- available_guards %>%
109
+ count(city, name = "available_guards")
110
+
111
+ active_sites %>%
112
+ left_join(guards_by_city, by = "city") %>%
113
+ mutate(
114
+ available_guards = ifelse(is.na(available_guards), 0L, available_guards),
115
+ shortage = pmax(required_guards - available_guards, 0L)
116
+ ) %>%
117
+ select(
118
+ 現場ID = site_id,
119
+ 現場名 = site_name,
120
+ 市区町村 = city,
121
+ 必要人数 = required_guards,
122
+ "対応可能人数(同一市内)" = available_guards,
123
+ "不足人数" = shortage
124
+ )
125
+ })
126
+
127
+ # 地図描画
128
+ output$map <- renderLeaflet({
129
+ dd <- daily_data()
130
+
131
+ # ベースマップ(北海道あたりを初期表示)
132
+ m <- leaflet() %>%
133
+ addTiles() %>%
134
+ setView(lng = 142.0, lat = 43.0, zoom = 6)
135
+
136
+ # 工事現場
137
+ if (nrow(dd$active_sites) > 0) {
138
+ m <- m %>%
139
+ addCircleMarkers(
140
+ data = dd$active_sites,
141
+ ~lng, ~lat,
142
+ radius = 8,
143
+ color = "blue",
144
+ fillOpacity = 0.8,
145
+ label = ~paste0(site_name, "(必要人数: ", required_guards, "人)"),
146
+ group = "sites"
147
  )
148
+ }
149
+
150
+ # 警備員
151
+ if (input$show_guards && nrow(dd$available_guards) > 0) {
152
+ m <- m %>%
153
+ addCircleMarkers(
154
+ data = dd$available_guards,
155
+ ~lng, ~lat,
156
+ radius = 5,
157
+ color = "red",
158
+ fillOpacity = 0.7,
159
+ label = ~paste0(guard_name, "(", city, "在住)"),
160
+ group = "guards"
161
  )
162
+ }
163
+
164
+ m %>% addLayersControl(
165
+ overlayGroups = c("sites", "guards"),
166
+ options = layersControlOptions(collapsed = FALSE)
167
+ )
168
+ })
169
+
170
+ # 集計テーブル
171
+ output$summary <- renderTable({
172
+ summary_tbl()
173
+ })
174
  }
175
 
176
+ shinyApp(ui, server)