Mark Febrizio commited on
Commit
164c6c1
·
1 Parent(s): 6958bad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +76 -35
app.py CHANGED
@@ -1,10 +1,13 @@
 
 
 
1
  import asyncio
2
  from datetime import datetime, date, time
3
  from pathlib import Path
4
 
5
  from faicons import icon_svg
6
- from pandas import DataFrame, to_datetime
7
- from plotnine import ggplot, labs
8
 
9
  from modules import (
10
  DF,
@@ -20,65 +23,85 @@ from modules import (
20
  pad_missing_dates,
21
  plot_agency,
22
  plot_tf,
 
23
  )
24
 
25
  from shiny import reactive
26
  from shiny.express import input, render, ui
27
 
28
- TITLE = "CRA Window Tracker - GW Regulatory Studies Center"
 
29
 
30
- HEADER = "Rules in the Congressional Review Act (CRA) Window"
31
 
32
- FOOTER = f"""
33
- -----
34
-
35
- © 2024 [GW Regulatory Studies Center](https://go.gwu.edu/regstudies). See our page on the [Congressional Review Act](https://regulatorystudies.columbian.gwu.edu/congressional-review-act) for more information.
36
- """
37
 
38
- ui.include_css( Path(__file__).parent.joinpath("www") / "style.css")
39
 
40
- ui.tags.title(TITLE)
 
41
 
42
- sidebar_logo = ui.HTML(
 
 
43
  f"""
44
  <div class="header">
45
- <a href="https://go.gwu.edu/regstudies" target="_blank">
46
- <img src="logo.png" alt="Regulatory Studies Center logo"/>
47
- </a>
48
  </div>
49
  """
50
  )
51
 
52
- page_header = ui.HTML(
 
53
  f"""
54
  <div class="header">
55
- <span>{HEADER}</span>
 
 
56
  </div>
57
  """
58
  )
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  page_header
61
 
 
62
  with ui.sidebar(open={"desktop": "open", "mobile": "closed"}):
63
  sidebar_logo
64
 
65
- ui.input_date("start_date", "Select start of window", value=WINDOW_OPEN_DATE, min=START_DATE, max=date.today())
66
-
 
 
 
67
  ui.input_select("menu_agency", "Select agencies", choices=["all"] + AGENCIES, selected="all", multiple=True)
68
 
69
- ui.input_select("frequency", "Select frequency", choices=["daily", "monthly", "weekly"], selected="daily")
 
 
70
 
71
  #ui.input_switch("switch", "Stack significant rules in plots", False)
72
 
 
73
  with ui.layout_column_wrap():
74
- with ui.value_box(showcase=icon_svg("book")):
75
  "All final rules"
76
  @render.text
77
  def count_rules():
78
  return f"{filtered_df()['document_number'].count()}"
79
- ui.input_action_button("filter_all", "View", ) #class_="btn-success")
80
 
81
- with ui.value_box(showcase=icon_svg("book")):
82
  "Section 3(f)(1) Significant rules *"
83
  @render.text
84
  def count_3f1_significant():
@@ -86,9 +109,9 @@ with ui.layout_column_wrap():
86
  if GET_SIGNIFICANT:
87
  output = f"{filtered_df()['3f1_significant'].sum()}"
88
  return output
89
- ui.input_action_button("filter_3f1", "View", ) #class_="btn-success")
90
 
91
- with ui.value_box(showcase=icon_svg("book")):
92
  "Other Significant rules *"
93
  @render.text
94
  def count_other_significant():
@@ -96,14 +119,16 @@ with ui.layout_column_wrap():
96
  if GET_SIGNIFICANT:
97
  output = f"{filtered_df()['other_significant'].sum()}"
98
  return output
99
- ui.input_action_button("filter_other", "View", )
100
 
 
101
  ui.markdown(
102
  f"""
103
  \* *Executive Order 12866 significance data last updated **{LAST_UPDATED}***.
104
  """
105
  )
106
 
 
107
  with ui.navset_card_underline(title=""):
108
 
109
  with ui.nav_panel("Rules in detail"):
@@ -136,14 +161,12 @@ with ui.navset_card_underline(title=""):
136
  count_gte_zero = sum(1 if g > 0 else 0 for g in values)
137
  max_val = max(values, default=0)
138
  if (max_val < 2) or (count_gte_zero < 2):
139
- return (
140
- ggplot()
141
- + labs(title="Not enough data available to visualize.")
142
- )
143
  else:
144
  return plot_tf(
145
  grouped,
146
- input.frequency()
 
147
  )
148
 
149
  with ui.card(full_screen=True):
@@ -180,10 +203,14 @@ with ui.navset_card_underline(title=""):
180
  #if input.switch():
181
  # pass
182
  # # placeholder for stacked bar chart
183
- plot = plot_agency(
184
- grouped.head(10),
185
- )
186
- return plot
 
 
 
 
187
 
188
  with ui.card(full_screen=True):
189
  @render.data_frame
@@ -198,6 +225,7 @@ with ui.navset_card_underline(title=""):
198
  ]
199
  return render.DataTable(grouped.loc[:, [c for c in cols if c in grouped.columns]])
200
 
 
201
  with ui.accordion(open=False):
202
 
203
  with ui.accordion_panel("Download Data"):
@@ -231,6 +259,7 @@ with ui.accordion(open=False):
231
  await asyncio.sleep(0.25)
232
  yield filtered_df().loc[:, output_cols].to_csv(index=False)
233
 
 
234
  with ui.accordion(open=False):
235
 
236
  with ui.accordion_panel("Notes"):
@@ -243,6 +272,7 @@ with ui.accordion(open=False):
243
  """
244
  )
245
 
 
246
  ui.markdown(
247
  FOOTER
248
  )
@@ -266,6 +296,17 @@ def filtered_df():
266
  bool_agency = [True if sum(selected in agency for selected in input.menu_agency()) > 0 else False for agency in filt_df["parent_slug"]]
267
  filt_df = filt_df.loc[bool_agency]
268
 
 
 
 
 
 
 
 
 
 
 
 
269
  return filt_df
270
 
271
 
 
1
+ # ----- IMPORTS ----- #
2
+
3
+
4
  import asyncio
5
  from datetime import datetime, date, time
6
  from pathlib import Path
7
 
8
  from faicons import icon_svg
9
+ from pandas import DataFrame
10
+ from numpy import array
11
 
12
  from modules import (
13
  DF,
 
23
  pad_missing_dates,
24
  plot_agency,
25
  plot_tf,
26
+ plot_NA,
27
  )
28
 
29
  from shiny import reactive
30
  from shiny.express import input, render, ui
31
 
32
+ # load css styles from external file
33
+ ui.include_css( Path(__file__).parent.joinpath("www") / "style.css")
34
 
 
35
 
36
+ # ----- CREATE OBJECTS ----- #
 
 
 
 
37
 
 
38
 
39
+ # this text appears in the browser tab
40
+ TITLE = "CRA Window Tracker - GW Regulatory Studies Center"
41
 
42
+ # page header above main content
43
+ HEADER = "Rules in the Congressional Review Act (CRA) Window"
44
+ page_header = ui.HTML(
45
  f"""
46
  <div class="header">
47
+ <span>{HEADER}</span>
 
 
48
  </div>
49
  """
50
  )
51
 
52
+ # logo at the top of the sidebar
53
+ sidebar_logo = ui.HTML(
54
  f"""
55
  <div class="header">
56
+ <a href="https://go.gwu.edu/regstudies" target="_blank">
57
+ <img src="logo.png" alt="Regulatory Studies Center logo"/>
58
+ </a>
59
  </div>
60
  """
61
  )
62
 
63
+ # footer at the bottom of the page
64
+ FOOTER = f"""
65
+ -----
66
+
67
+ &copy; 2024 [GW Regulatory Studies Center](https://go.gwu.edu/regstudies). See our page on the [Congressional Review Act](https://regulatorystudies.columbian.gwu.edu/congressional-review-act) for more information.
68
+ """
69
+
70
+
71
+ # ----- APP LAYOUT ----- #
72
+
73
+
74
+ ui.tags.title(TITLE)
75
+
76
  page_header
77
 
78
+ # sidebar settings
79
  with ui.sidebar(open={"desktop": "open", "mobile": "closed"}):
80
  sidebar_logo
81
 
82
+ #ui.markdown("Estimated CRA window open date: [May 23](https://www.huntonak.com/the-nickel-report/federal-agencies-face-looming-congressional-review-act-deadline)")
83
+ with ui.tooltip(placement="right", id="window_tooltip"):
84
+ ui.input_date("start_date", "Select start of window", value=WINDOW_OPEN_DATE, min=START_DATE, max=date.today())
85
+ "The estimated CRA window open date is May 23. See the notes for more information."
86
+
87
  ui.input_select("menu_agency", "Select agencies", choices=["all"] + AGENCIES, selected="all", multiple=True)
88
 
89
+ ui.input_select("frequency", "Select frequency", choices=["daily", "weekly", "monthly"], selected="weekly")
90
+
91
+ ui.input_select("menu_significant", "Select rule significance", choices=["all", "3f1-significant", "other-significant"], selected="all", multiple=True)
92
 
93
  #ui.input_switch("switch", "Stack significant rules in plots", False)
94
 
95
+ # value boxes with summary data
96
  with ui.layout_column_wrap():
97
+ with ui.value_box():
98
  "All final rules"
99
  @render.text
100
  def count_rules():
101
  return f"{filtered_df()['document_number'].count()}"
102
+ ui.input_action_button("filter_all", "Clear Filters", class_="btn-filter", icon=icon_svg("book"))
103
 
104
+ with ui.value_box():
105
  "Section 3(f)(1) Significant rules *"
106
  @render.text
107
  def count_3f1_significant():
 
109
  if GET_SIGNIFICANT:
110
  output = f"{filtered_df()['3f1_significant'].sum()}"
111
  return output
112
+ ui.input_action_button("filter_3f1", "Filter", class_="btn-filter", icon=icon_svg("book"))
113
 
114
+ with ui.value_box():
115
  "Other Significant rules *"
116
  @render.text
117
  def count_other_significant():
 
119
  if GET_SIGNIFICANT:
120
  output = f"{filtered_df()['other_significant'].sum()}"
121
  return output
122
+ ui.input_action_button("filter_other", "Filter", class_="btn-filter", icon=icon_svg("book"))
123
 
124
+ # documentation note on significance data
125
  ui.markdown(
126
  f"""
127
  \* *Executive Order 12866 significance data last updated **{LAST_UPDATED}***.
128
  """
129
  )
130
 
131
+ # main content
132
  with ui.navset_card_underline(title=""):
133
 
134
  with ui.nav_panel("Rules in detail"):
 
161
  count_gte_zero = sum(1 if g > 0 else 0 for g in values)
162
  max_val = max(values, default=0)
163
  if (max_val < 2) or (count_gte_zero < 2):
164
+ return plot_NA()
 
 
 
165
  else:
166
  return plot_tf(
167
  grouped,
168
+ input.frequency(),
169
+ rule_type=filter_value.get(),
170
  )
171
 
172
  with ui.card(full_screen=True):
 
203
  #if input.switch():
204
  # pass
205
  # # placeholder for stacked bar chart
206
+ if len(grouped) < 2:
207
+ return plot_NA()
208
+ else:
209
+ plot = plot_agency(
210
+ grouped.head(10),
211
+ rule_type=filter_value.get(),
212
+ )
213
+ return plot
214
 
215
  with ui.card(full_screen=True):
216
  @render.data_frame
 
225
  ]
226
  return render.DataTable(grouped.loc[:, [c for c in cols if c in grouped.columns]])
227
 
228
+ # download data
229
  with ui.accordion(open=False):
230
 
231
  with ui.accordion_panel("Download Data"):
 
259
  await asyncio.sleep(0.25)
260
  yield filtered_df().loc[:, output_cols].to_csv(index=False)
261
 
262
+ # notes
263
  with ui.accordion(open=False):
264
 
265
  with ui.accordion_panel("Notes"):
 
272
  """
273
  )
274
 
275
+ # footer citation
276
  ui.markdown(
277
  FOOTER
278
  )
 
296
  bool_agency = [True if sum(selected in agency for selected in input.menu_agency()) > 0 else False for agency in filt_df["parent_slug"]]
297
  filt_df = filt_df.loc[bool_agency]
298
 
299
+ print(input.menu_significant())
300
+ # filter significance
301
+ bool_ = []
302
+ if (input.menu_significant() is not None) and ("all" not in input.menu_significant()):
303
+ if "3f1-significant" in input.menu_significant():
304
+ bool_.append((filt_df["3f1_significant"] == 1).to_numpy())
305
+ if "other-significant" in input.menu_significant():
306
+ bool_.append((filt_df["other_significant"] == 1).to_numpy())
307
+ filt_df = filt_df.loc[array(bool_).any(axis=0)]
308
+
309
+ # return filtered dataframe
310
  return filt_df
311
 
312