Upload folder using huggingface_hub
Browse files- README.md +2 -8
- backend.py +250 -0
- footnotes.py +58 -0
- gradio_app.py +344 -0
- ice_detention_data.csv +1 -0
- requirements.txt +1 -0
- streamlit_app.py +46 -0
README.md
CHANGED
@@ -1,12 +1,6 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
-
|
4 |
-
colorFrom: pink
|
5 |
-
colorTo: red
|
6 |
sdk: gradio
|
7 |
sdk_version: 5.38.0
|
8 |
-
app_file: app.py
|
9 |
-
pinned: false
|
10 |
---
|
11 |
-
|
12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
---
|
2 |
+
title: movement
|
3 |
+
app_file: gradio_app.py
|
|
|
|
|
4 |
sdk: gradio
|
5 |
sdk_version: 5.38.0
|
|
|
|
|
6 |
---
|
|
|
|
backend.py
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Functions to scrape and graph data from TRAC's "ICE Detainees" page
|
3 |
+
(https://tracreports.org/immigration/detentionstats/pop_agen_table.html).
|
4 |
+
"""
|
5 |
+
|
6 |
+
import streamlit as st
|
7 |
+
import requests
|
8 |
+
import pandas as pd
|
9 |
+
import plotly.express as px
|
10 |
+
|
11 |
+
colorblind_palette = colorblind_palette = [
|
12 |
+
"#377eb8", # blue
|
13 |
+
"#ff7f00", # orange
|
14 |
+
"#a65628", # brown
|
15 |
+
"#999999", # gray
|
16 |
+
]
|
17 |
+
|
18 |
+
|
19 |
+
@st.cache_data(ttl="15m")
|
20 |
+
def get_detention_data():
|
21 |
+
"""
|
22 |
+
Get the data which powers TRAC's "ICE Detainees" page and return it as a dataframe.
|
23 |
+
|
24 |
+
This function caches the data for 15 minutes. They seem to update the site just a few times a month, so this should
|
25 |
+
be fine.
|
26 |
+
|
27 |
+
URLS of interest:
|
28 |
+
1. TRAC Reports homepage: https://tracreports.org/
|
29 |
+
2. TRAC Reports Immigration page: https://tracreports.org/immigration/
|
30 |
+
3. TRAC Reports Immigration Detention Quick Facts page:
|
31 |
+
https://tracreports.org/immigration/quickfacts/detention.html
|
32 |
+
4. The "See More Data" page when you get on "Detention Quick Facts":
|
33 |
+
https://tracreports.org/immigration/detentionstats/pop_agen_table.html
|
34 |
+
5. The JSON which populates the Detention Quick Facts page:
|
35 |
+
https://tracreports.org/immigration/detentionstats/pop_agen_table.json
|
36 |
+
|
37 |
+
This function gets the data from (5), does some light processing, and returns it.
|
38 |
+
"""
|
39 |
+
response = requests.get(
|
40 |
+
"https://tracreports.org/immigration/detentionstats/pop_agen_table.json"
|
41 |
+
)
|
42 |
+
|
43 |
+
df = pd.DataFrame(response.json())
|
44 |
+
df.date = pd.to_datetime(df.date).dt.date
|
45 |
+
|
46 |
+
return df
|
47 |
+
|
48 |
+
|
49 |
+
def get_aa_count_chart():
|
50 |
+
"""Get a chart that shows detentions by arresting authority as a count."""
|
51 |
+
df = get_detention_data()
|
52 |
+
|
53 |
+
df = df.rename(columns={"ice_all": "ICE", "cbp_all": "CBP", "total_all": "Total"})
|
54 |
+
|
55 |
+
# Converts df from wide to long
|
56 |
+
df_melted = df.melt(
|
57 |
+
id_vars="date",
|
58 |
+
value_vars=["ICE", "CBP", "Total"],
|
59 |
+
var_name="Arresting Authority",
|
60 |
+
value_name="count",
|
61 |
+
)
|
62 |
+
|
63 |
+
fig = px.line(
|
64 |
+
df_melted,
|
65 |
+
x="date",
|
66 |
+
y="count",
|
67 |
+
color="Arresting Authority",
|
68 |
+
color_discrete_sequence=colorblind_palette,
|
69 |
+
)
|
70 |
+
|
71 |
+
fig.update_layout(
|
72 |
+
xaxis_title="Date",
|
73 |
+
yaxis_title="Detainees",
|
74 |
+
title="ICE Detainees by Date* and Arresting Authority",
|
75 |
+
)
|
76 |
+
|
77 |
+
return fig
|
78 |
+
|
79 |
+
|
80 |
+
def get_aa_pct_chart():
|
81 |
+
"""Get a chart that shows detentions by arresting authority as a percent."""
|
82 |
+
df = get_detention_data()
|
83 |
+
|
84 |
+
df["ICE"] = (df.ice_all / df.total_all * 100).round() # Rounding is in the original
|
85 |
+
df["CBP"] = (df.cbp_all / df.total_all * 100).round()
|
86 |
+
|
87 |
+
# Converts df from wide to long
|
88 |
+
df_melted = df.melt(
|
89 |
+
id_vars="date",
|
90 |
+
value_vars=["ICE", "CBP"],
|
91 |
+
var_name="Arresting Authority",
|
92 |
+
value_name="percent",
|
93 |
+
)
|
94 |
+
|
95 |
+
fig = px.line(
|
96 |
+
df_melted,
|
97 |
+
x="date",
|
98 |
+
y="percent",
|
99 |
+
color="Arresting Authority",
|
100 |
+
color_discrete_sequence=colorblind_palette,
|
101 |
+
)
|
102 |
+
|
103 |
+
fig.update_layout(
|
104 |
+
xaxis_title="Date",
|
105 |
+
yaxis_title="Percent",
|
106 |
+
title="ICE Detainees by Date* and Arresting Authority",
|
107 |
+
)
|
108 |
+
|
109 |
+
return fig
|
110 |
+
|
111 |
+
|
112 |
+
def get_col_prefix(authority):
|
113 |
+
"""
|
114 |
+
Return the column prefix for the UI text "ICE", "CBP" and "All".
|
115 |
+
|
116 |
+
When viewing the criminality dataset the UI lets users select stats for each arresting authority ("ICE", "CBP") and
|
117 |
+
together ("All"). In the dataset, these subsets are denoted by the column prefixes "ice", "cbp" and "total". This
|
118 |
+
function converts the UI text to the column prefix.
|
119 |
+
"""
|
120 |
+
if authority == "All":
|
121 |
+
return "total"
|
122 |
+
elif authority == "ICE":
|
123 |
+
return "ice"
|
124 |
+
elif authority == "CBP":
|
125 |
+
return "cbp"
|
126 |
+
else:
|
127 |
+
raise ValueError(f"Unknown authority {authority}")
|
128 |
+
|
129 |
+
|
130 |
+
def get_criminality_count_chart(authority):
|
131 |
+
"""Get a chart that shows the criminality of detainees by arresting authority as a count."""
|
132 |
+
df = get_detention_data()
|
133 |
+
|
134 |
+
# Converts df from wide to long
|
135 |
+
prefix = get_col_prefix(authority)
|
136 |
+
df = df.rename(
|
137 |
+
columns={
|
138 |
+
f"{prefix}_all": "Total",
|
139 |
+
f"{prefix}_conv": "Convicted Criminal",
|
140 |
+
f"{prefix}_pend": "Pending Criminal Charges",
|
141 |
+
f"{prefix}_other": "Other Immigration Violator",
|
142 |
+
}
|
143 |
+
)
|
144 |
+
|
145 |
+
df_melted = df.melt(
|
146 |
+
id_vars="date",
|
147 |
+
value_vars=[
|
148 |
+
"Convicted Criminal",
|
149 |
+
"Pending Criminal Charges",
|
150 |
+
"Other Immigration Violator",
|
151 |
+
"Total",
|
152 |
+
],
|
153 |
+
var_name="Criminal Status",
|
154 |
+
value_name="count",
|
155 |
+
)
|
156 |
+
|
157 |
+
fig = px.line(
|
158 |
+
df_melted,
|
159 |
+
x="date",
|
160 |
+
y="count",
|
161 |
+
color="Criminal Status",
|
162 |
+
color_discrete_sequence=colorblind_palette,
|
163 |
+
)
|
164 |
+
|
165 |
+
fig.update_layout(
|
166 |
+
xaxis_title="Date",
|
167 |
+
yaxis_title="Detainees",
|
168 |
+
title="ICE Detainees by Date*, Criminality** and Arresting Authority",
|
169 |
+
)
|
170 |
+
|
171 |
+
return fig
|
172 |
+
|
173 |
+
|
174 |
+
def get_criminality_pct_chart(authority):
|
175 |
+
"""Get a chart that shows the criminality of detainees by arresting authority as a percent."""
|
176 |
+
df = get_detention_data()
|
177 |
+
|
178 |
+
prefix = get_col_prefix(authority)
|
179 |
+
all_col = f"{prefix}_all"
|
180 |
+
conv_col = f"{prefix}_conv"
|
181 |
+
pend_col = f"{prefix}_pend"
|
182 |
+
other_col = f"{prefix}_other"
|
183 |
+
|
184 |
+
df["Convicted Criminal"] = (
|
185 |
+
df[conv_col] / df[all_col] * 100
|
186 |
+
).round() # Rounding is in the original
|
187 |
+
df["Pending Criminal Charges"] = (df[pend_col] / df[all_col] * 100).round()
|
188 |
+
df["Other Immigration Violator"] = (df[other_col] / df[all_col] * 100).round()
|
189 |
+
|
190 |
+
# Converts df from wide to long
|
191 |
+
df_melted = df.melt(
|
192 |
+
id_vars="date",
|
193 |
+
value_vars=[
|
194 |
+
"Convicted Criminal",
|
195 |
+
"Pending Criminal Charges",
|
196 |
+
"Other Immigration Violator",
|
197 |
+
],
|
198 |
+
var_name="Criminal Status",
|
199 |
+
value_name="percent",
|
200 |
+
)
|
201 |
+
|
202 |
+
fig = px.line(
|
203 |
+
df_melted,
|
204 |
+
x="date",
|
205 |
+
y="percent",
|
206 |
+
color="Criminal Status",
|
207 |
+
color_discrete_sequence=colorblind_palette,
|
208 |
+
)
|
209 |
+
|
210 |
+
fig.update_layout(
|
211 |
+
xaxis_title="Date",
|
212 |
+
yaxis_title="Percent",
|
213 |
+
title="ICE Detainees by Date*, Criminality** and Arresting Authority",
|
214 |
+
)
|
215 |
+
|
216 |
+
return fig
|
217 |
+
|
218 |
+
|
219 |
+
def get_graph(dataset, display, authority):
|
220 |
+
"""
|
221 |
+
Get the graph specified by the dataset, display and authority.
|
222 |
+
|
223 |
+
Parameters
|
224 |
+
----------
|
225 |
+
- dataset: one of "Arresting Authority" or "Criminality"
|
226 |
+
- display: one of "Count" or "Percent"
|
227 |
+
- authority: one of "CBP" (for "Customers and Border Protection"), "ICE" (for "Immigration and Customers
|
228 |
+
Enforcement") or "All" (for the total number)
|
229 |
+
|
230 |
+
Returns
|
231 |
+
-------
|
232 |
+
- A plotly figure
|
233 |
+
"""
|
234 |
+
if dataset == "Arresting Authority":
|
235 |
+
if display == "Count":
|
236 |
+
fig = get_aa_count_chart()
|
237 |
+
elif display == "Percent":
|
238 |
+
fig = get_aa_pct_chart()
|
239 |
+
elif dataset == "Criminality":
|
240 |
+
if display == "Count":
|
241 |
+
fig = get_criminality_count_chart(authority)
|
242 |
+
elif display == "Percent":
|
243 |
+
fig = get_criminality_pct_chart(authority)
|
244 |
+
|
245 |
+
if not fig:
|
246 |
+
raise ValueError(
|
247 |
+
f"Cannot create graph for dataset={dataset}, display={display}"
|
248 |
+
)
|
249 |
+
|
250 |
+
return fig
|
footnotes.py
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
These footnotes are taken verbatim from
|
3 |
+
https://tracreports.org/immigration/detentionstats/pop_agen_table.html.
|
4 |
+
We don't include the third and final footnote because it is not used anywhere
|
5 |
+
on the page.
|
6 |
+
"""
|
7 |
+
|
8 |
+
|
9 |
+
def get_abbreviations_text():
|
10 |
+
return '"ICE" stands for "Immigration and Customs Enforcement". "CBP" stands for "Customs and Border Protection".'
|
11 |
+
|
12 |
+
|
13 |
+
def get_date_footnote_text():
|
14 |
+
return (
|
15 |
+
"* Dates before 11/15/2021 refer to the date ICE posted the data; "
|
16 |
+
"dates after 11/15/2021 refer to the date the information was current as of."
|
17 |
+
)
|
18 |
+
|
19 |
+
|
20 |
+
def get_criminality_footnote_text():
|
21 |
+
return (
|
22 |
+
"** ICE classifies an individual as a convicted criminal if they have been convicted "
|
23 |
+
"of any criminal violation. Violations can range from serious felonies all the way down "
|
24 |
+
"to a purely immigration violation (such as illegal entry which is a petty offense under "
|
25 |
+
"the U.S. Code), or a violation which results in only in a fine such as not keeping a dog "
|
26 |
+
"on a leash, fishing without a permit, driving a vehicle with a tail light out, etc. For "
|
27 |
+
"historical series on ICE detainees identifying the most serious offense they have been "
|
28 |
+
"convicted of along with other details such as when they entered the U.S., nationality, "
|
29 |
+
"gender, etc. go to https://tracreports.org/phptools/immigration/detention/"
|
30 |
+
)
|
31 |
+
|
32 |
+
|
33 |
+
def get_date_footnote():
|
34 |
+
return f"""
|
35 |
+
<p style='font-size: 0.85em; font-style: italic; margin-top: 10px;'>
|
36 |
+
{get_abbreviations_text()}<br>
|
37 |
+
{get_date_footnote_text()}
|
38 |
+
</p>
|
39 |
+
"""
|
40 |
+
|
41 |
+
|
42 |
+
def get_criminality_footnote():
|
43 |
+
return f"""
|
44 |
+
<p style='font-size: 0.85em; font-style: italic; margin-top: 10px;'>
|
45 |
+
{get_abbreviations_text()}<br>
|
46 |
+
{get_date_footnote_text()}<br>
|
47 |
+
{get_criminality_footnote_text()}
|
48 |
+
</p>
|
49 |
+
"""
|
50 |
+
|
51 |
+
|
52 |
+
def get_footnote(dataset):
|
53 |
+
if dataset == "Arresting Authority":
|
54 |
+
return get_date_footnote()
|
55 |
+
elif dataset == "Criminality":
|
56 |
+
return get_criminality_footnote()
|
57 |
+
else:
|
58 |
+
raise ValueError(f"Unknown dataset {dataset}")
|
gradio_app.py
ADDED
@@ -0,0 +1,344 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import requests
|
3 |
+
import pandas as pd
|
4 |
+
import plotly.express as px
|
5 |
+
import plotly.graph_objects as go
|
6 |
+
|
7 |
+
# Color palette for accessibility
|
8 |
+
colorblind_palette = [
|
9 |
+
"#377eb8", # blue
|
10 |
+
"#ff7f00", # orange
|
11 |
+
"#a65628", # brown
|
12 |
+
"#999999", # gray
|
13 |
+
]
|
14 |
+
|
15 |
+
# Cache for data (simple in-memory cache)
|
16 |
+
_cached_data = None
|
17 |
+
_cache_timestamp = None
|
18 |
+
|
19 |
+
def get_detention_data():
|
20 |
+
"""
|
21 |
+
Get the data which powers TRAC's "ICE Detainees" page and return it as a dataframe.
|
22 |
+
"""
|
23 |
+
global _cached_data, _cache_timestamp
|
24 |
+
|
25 |
+
import time
|
26 |
+
current_time = time.time()
|
27 |
+
|
28 |
+
# Check if we have cached data that's less than 15 minutes old
|
29 |
+
if _cached_data is not None and _cache_timestamp is not None:
|
30 |
+
if current_time - _cache_timestamp < 900: # 15 minutes in seconds
|
31 |
+
return _cached_data
|
32 |
+
|
33 |
+
try:
|
34 |
+
response = requests.get(
|
35 |
+
"https://tracreports.org/immigration/detentionstats/pop_agen_table.json"
|
36 |
+
)
|
37 |
+
response.raise_for_status()
|
38 |
+
|
39 |
+
df = pd.DataFrame(response.json())
|
40 |
+
df.date = pd.to_datetime(df.date).dt.date
|
41 |
+
|
42 |
+
# Cache the data
|
43 |
+
_cached_data = df
|
44 |
+
_cache_timestamp = current_time
|
45 |
+
|
46 |
+
return df
|
47 |
+
except Exception as e:
|
48 |
+
# Return empty dataframe if request fails
|
49 |
+
return pd.DataFrame()
|
50 |
+
|
51 |
+
def get_col_prefix(authority):
|
52 |
+
"""Return the column prefix for the UI text "ICE", "CBP" and "All"."""
|
53 |
+
if authority == "All":
|
54 |
+
return "total"
|
55 |
+
elif authority == "ICE":
|
56 |
+
return "ice"
|
57 |
+
elif authority == "CBP":
|
58 |
+
return "cbp"
|
59 |
+
else:
|
60 |
+
raise ValueError(f"Unknown authority {authority}")
|
61 |
+
|
62 |
+
def get_aa_count_chart():
|
63 |
+
"""Get a chart that shows detentions by arresting authority as a count."""
|
64 |
+
df = get_detention_data()
|
65 |
+
if df.empty:
|
66 |
+
return go.Figure().add_annotation(text="Error loading data", showarrow=False)
|
67 |
+
|
68 |
+
df = df.rename(columns={"ice_all": "ICE", "cbp_all": "CBP", "total_all": "Total"})
|
69 |
+
|
70 |
+
df_melted = df.melt(
|
71 |
+
id_vars="date",
|
72 |
+
value_vars=["ICE", "CBP", "Total"],
|
73 |
+
var_name="Arresting Authority",
|
74 |
+
value_name="count",
|
75 |
+
)
|
76 |
+
|
77 |
+
fig = px.line(
|
78 |
+
df_melted,
|
79 |
+
x="date",
|
80 |
+
y="count",
|
81 |
+
color="Arresting Authority",
|
82 |
+
color_discrete_sequence=colorblind_palette,
|
83 |
+
)
|
84 |
+
|
85 |
+
fig.update_layout(
|
86 |
+
xaxis_title="Date",
|
87 |
+
yaxis_title="Detainees",
|
88 |
+
title="ICE Detainees by Date* and Arresting Authority",
|
89 |
+
)
|
90 |
+
|
91 |
+
return fig
|
92 |
+
|
93 |
+
def get_aa_pct_chart():
|
94 |
+
"""Get a chart that shows detentions by arresting authority as a percent."""
|
95 |
+
df = get_detention_data()
|
96 |
+
if df.empty:
|
97 |
+
return go.Figure().add_annotation(text="Error loading data", showarrow=False)
|
98 |
+
|
99 |
+
df["ICE"] = (df.ice_all / df.total_all * 100).round()
|
100 |
+
df["CBP"] = (df.cbp_all / df.total_all * 100).round()
|
101 |
+
|
102 |
+
df_melted = df.melt(
|
103 |
+
id_vars="date",
|
104 |
+
value_vars=["ICE", "CBP"],
|
105 |
+
var_name="Arresting Authority",
|
106 |
+
value_name="percent",
|
107 |
+
)
|
108 |
+
|
109 |
+
fig = px.line(
|
110 |
+
df_melted,
|
111 |
+
x="date",
|
112 |
+
y="percent",
|
113 |
+
color="Arresting Authority",
|
114 |
+
color_discrete_sequence=colorblind_palette,
|
115 |
+
)
|
116 |
+
|
117 |
+
fig.update_layout(
|
118 |
+
xaxis_title="Date",
|
119 |
+
yaxis_title="Percent",
|
120 |
+
title="ICE Detainees by Date* and Arresting Authority",
|
121 |
+
)
|
122 |
+
|
123 |
+
return fig
|
124 |
+
|
125 |
+
def get_criminality_count_chart(authority):
|
126 |
+
"""Get a chart that shows the criminality of detainees by arresting authority as a count."""
|
127 |
+
df = get_detention_data()
|
128 |
+
if df.empty:
|
129 |
+
return go.Figure().add_annotation(text="Error loading data", showarrow=False)
|
130 |
+
|
131 |
+
prefix = get_col_prefix(authority)
|
132 |
+
df = df.rename(
|
133 |
+
columns={
|
134 |
+
f"{prefix}_all": "Total",
|
135 |
+
f"{prefix}_conv": "Convicted Criminal",
|
136 |
+
f"{prefix}_pend": "Pending Criminal Charges",
|
137 |
+
f"{prefix}_other": "Other Immigration Violator",
|
138 |
+
}
|
139 |
+
)
|
140 |
+
|
141 |
+
df_melted = df.melt(
|
142 |
+
id_vars="date",
|
143 |
+
value_vars=[
|
144 |
+
"Convicted Criminal",
|
145 |
+
"Pending Criminal Charges",
|
146 |
+
"Other Immigration Violator",
|
147 |
+
"Total",
|
148 |
+
],
|
149 |
+
var_name="Criminal Status",
|
150 |
+
value_name="count",
|
151 |
+
)
|
152 |
+
|
153 |
+
fig = px.line(
|
154 |
+
df_melted,
|
155 |
+
x="date",
|
156 |
+
y="count",
|
157 |
+
color="Criminal Status",
|
158 |
+
color_discrete_sequence=colorblind_palette,
|
159 |
+
)
|
160 |
+
|
161 |
+
fig.update_layout(
|
162 |
+
xaxis_title="Date",
|
163 |
+
yaxis_title="Detainees",
|
164 |
+
title="ICE Detainees by Date*, Criminality** and Arresting Authority",
|
165 |
+
)
|
166 |
+
|
167 |
+
return fig
|
168 |
+
|
169 |
+
def get_criminality_pct_chart(authority):
|
170 |
+
"""Get a chart that shows the criminality of detainees by arresting authority as a percent."""
|
171 |
+
df = get_detention_data()
|
172 |
+
if df.empty:
|
173 |
+
return go.Figure().add_annotation(text="Error loading data", showarrow=False)
|
174 |
+
|
175 |
+
prefix = get_col_prefix(authority)
|
176 |
+
all_col = f"{prefix}_all"
|
177 |
+
conv_col = f"{prefix}_conv"
|
178 |
+
pend_col = f"{prefix}_pend"
|
179 |
+
other_col = f"{prefix}_other"
|
180 |
+
|
181 |
+
df["Convicted Criminal"] = (df[conv_col] / df[all_col] * 100).round()
|
182 |
+
df["Pending Criminal Charges"] = (df[pend_col] / df[all_col] * 100).round()
|
183 |
+
df["Other Immigration Violator"] = (df[other_col] / df[all_col] * 100).round()
|
184 |
+
|
185 |
+
df_melted = df.melt(
|
186 |
+
id_vars="date",
|
187 |
+
value_vars=[
|
188 |
+
"Convicted Criminal",
|
189 |
+
"Pending Criminal Charges",
|
190 |
+
"Other Immigration Violator",
|
191 |
+
],
|
192 |
+
var_name="Criminal Status",
|
193 |
+
value_name="percent",
|
194 |
+
)
|
195 |
+
|
196 |
+
fig = px.line(
|
197 |
+
df_melted,
|
198 |
+
x="date",
|
199 |
+
y="percent",
|
200 |
+
color="Criminal Status",
|
201 |
+
color_discrete_sequence=colorblind_palette,
|
202 |
+
)
|
203 |
+
|
204 |
+
fig.update_layout(
|
205 |
+
xaxis_title="Date",
|
206 |
+
yaxis_title="Percent",
|
207 |
+
title="ICE Detainees by Date*, Criminality** and Arresting Authority",
|
208 |
+
)
|
209 |
+
|
210 |
+
return fig
|
211 |
+
|
212 |
+
def get_footnote_text(dataset):
|
213 |
+
"""Get footnote text for the dataset."""
|
214 |
+
abbreviations = '"ICE" stands for "Immigration and Customs Enforcement". "CBP" stands for "Customs and Border Protection".'
|
215 |
+
date_footnote = "*Dates before 11/15/2021 refer to the date ICE posted the data; dates after 11/15/2021 refer to the date the information was current as of."
|
216 |
+
|
217 |
+
if dataset == "Arresting Authority":
|
218 |
+
return f"{abbreviations}\n{date_footnote}"
|
219 |
+
elif dataset == "Criminality":
|
220 |
+
criminality_footnote = "**ICE classifies an individual as a convicted criminal if they have been convicted of any criminal violation. Violations can range from serious felonies all the way down to a purely immigration violation (such as illegal entry which is a petty offense under the U.S. Code), or a violation which results in only in a fine such as not keeping a dog on a leash, fishing without a permit, driving a vehicle with a tail light out, etc."
|
221 |
+
return f"{abbreviations}\n{date_footnote}\n{criminality_footnote}"
|
222 |
+
return ""
|
223 |
+
|
224 |
+
def update_chart(dataset, display, authority):
|
225 |
+
"""Update the chart based on user selections."""
|
226 |
+
try:
|
227 |
+
if dataset == "Arresting Authority":
|
228 |
+
if display == "Count":
|
229 |
+
fig = get_aa_count_chart()
|
230 |
+
elif display == "Percent":
|
231 |
+
fig = get_aa_pct_chart()
|
232 |
+
elif dataset == "Criminality":
|
233 |
+
if display == "Count":
|
234 |
+
fig = get_criminality_count_chart(authority)
|
235 |
+
elif display == "Percent":
|
236 |
+
fig = get_criminality_pct_chart(authority)
|
237 |
+
|
238 |
+
footnote = get_footnote_text(dataset)
|
239 |
+
return fig, footnote
|
240 |
+
except Exception as e:
|
241 |
+
error_fig = go.Figure().add_annotation(
|
242 |
+
text=f"Error creating chart: {str(e)}",
|
243 |
+
showarrow=False
|
244 |
+
)
|
245 |
+
return error_fig, "Error loading data"
|
246 |
+
|
247 |
+
def get_data_info():
|
248 |
+
"""Get information about the data."""
|
249 |
+
return """"""
|
250 |
+
|
251 |
+
def download_data():
|
252 |
+
"""Prepare data for download."""
|
253 |
+
df = get_detention_data()
|
254 |
+
if df.empty:
|
255 |
+
return None
|
256 |
+
return df.to_csv(index=False)
|
257 |
+
|
258 |
+
# Create the Gradio interface
|
259 |
+
def create_app():
|
260 |
+
with gr.Blocks(title="US Immigration Enforcement Data", theme=gr.themes.Soft()) as app:
|
261 |
+
gr.Markdown("# US Immigration Enforcement Data")
|
262 |
+
|
263 |
+
with gr.Tabs():
|
264 |
+
with gr.TabItem("📈 Graphs"):
|
265 |
+
with gr.Row():
|
266 |
+
dataset = gr.Dropdown(
|
267 |
+
choices=["Arresting Authority", "Criminality"],
|
268 |
+
value="Arresting Authority",
|
269 |
+
label="Dataset"
|
270 |
+
)
|
271 |
+
display = gr.Dropdown(
|
272 |
+
choices=["Count", "Percent"],
|
273 |
+
value="Count",
|
274 |
+
label="Display"
|
275 |
+
)
|
276 |
+
authority = gr.Dropdown(
|
277 |
+
choices=["All", "ICE", "CBP"],
|
278 |
+
value="All",
|
279 |
+
label="Arresting Authority",
|
280 |
+
visible=False
|
281 |
+
)
|
282 |
+
|
283 |
+
chart = gr.Plot()
|
284 |
+
footnote = gr.Markdown()
|
285 |
+
|
286 |
+
# Update authority dropdown visibility based on dataset
|
287 |
+
def update_authority_visibility(dataset_choice):
|
288 |
+
return gr.Dropdown(visible=(dataset_choice == "Criminality"))
|
289 |
+
|
290 |
+
dataset.change(
|
291 |
+
update_authority_visibility,
|
292 |
+
inputs=[dataset],
|
293 |
+
outputs=[authority]
|
294 |
+
)
|
295 |
+
|
296 |
+
# Update chart when any input changes
|
297 |
+
for input_component in [dataset, display, authority]:
|
298 |
+
input_component.change(
|
299 |
+
update_chart,
|
300 |
+
inputs=[dataset, display, authority],
|
301 |
+
outputs=[chart, footnote]
|
302 |
+
)
|
303 |
+
|
304 |
+
# Initial chart load
|
305 |
+
app.load(
|
306 |
+
update_chart,
|
307 |
+
inputs=[dataset, display, authority],
|
308 |
+
outputs=[chart, footnote]
|
309 |
+
)
|
310 |
+
|
311 |
+
with gr.TabItem("📋 Data"):
|
312 |
+
gr.Markdown(get_data_info())
|
313 |
+
|
314 |
+
with gr.Row():
|
315 |
+
refresh_btn = gr.Button("Refresh Data")
|
316 |
+
download_btn = gr.DownloadButton(
|
317 |
+
"Download as CSV",
|
318 |
+
lambda: download_data(),
|
319 |
+
filename="ice_detention_data.csv"
|
320 |
+
)
|
321 |
+
|
322 |
+
data_display = gr.Dataframe(
|
323 |
+
label="ICE Detention Data",
|
324 |
+
wrap=True
|
325 |
+
)
|
326 |
+
|
327 |
+
def refresh_data():
|
328 |
+
global _cached_data, _cache_timestamp
|
329 |
+
_cached_data = None
|
330 |
+
_cache_timestamp = None
|
331 |
+
df = get_detention_data()
|
332 |
+
return df
|
333 |
+
|
334 |
+
refresh_btn.click(refresh_data, outputs=[data_display])
|
335 |
+
|
336 |
+
# Load data on app start
|
337 |
+
app.load(lambda: get_detention_data(), outputs=[data_display])
|
338 |
+
|
339 |
+
|
340 |
+
return app
|
341 |
+
|
342 |
+
if __name__ == "__main__":
|
343 |
+
app = create_app()
|
344 |
+
app.launch()
|
ice_detention_data.csv
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
[{"date":"07/13/2025","ice_all":41349,"cbp_all":15467,"total_all":56816,"ice_other":13653,"cbp_other":13099,"total_other":26752,"ice_pend":12825,"cbp_pend":1066,"total_pend":13891,"ice_conv":14871,"cbp_conv":1302,"total_conv":16173},{"date":"06/29/2025","ice_all":41447,"cbp_all":16414,"total_all":57861,"ice_other":13318,"cbp_other":13859,"total_other":27177,"ice_pend":13140,"cbp_pend":1178,"total_pend":14318,"ice_conv":14989,"cbp_conv":1377,"total_conv":16366},{"date":"06/15/2025","ice_all":39312,"cbp_all":17085,"total_all":56397,"ice_other":11763,"cbp_other":14407,"total_other":26170,"ice_pend":13022,"cbp_pend":1241,"total_pend":14263,"ice_conv":14527,"cbp_conv":1437,"total_conv":15964},{"date":"06/01/2025","ice_all":33976,"cbp_all":17326,"total_all":51302,"ice_other":7781,"cbp_other":14657,"total_other":22438,"ice_pend":12414,"cbp_pend":1257,"total_pend":13671,"ice_conv":13781,"cbp_conv":1412,"total_conv":15193},{"date":"05/18/2025","ice_all":31095,"cbp_all":17775,"total_all":48870,"ice_other":5845,"cbp_other":15196,"total_other":21041,"ice_pend":11721,"cbp_pend":1199,"total_pend":12920,"ice_conv":13529,"cbp_conv":1380,"total_conv":14909},{"date":"05/04/2025","ice_all":30420,"cbp_all":18585,"total_all":49005,"ice_other":5400,"cbp_other":15850,"total_other":21250,"ice_pend":11529,"cbp_pend":1201,"total_pend":12730,"ice_conv":13491,"cbp_conv":1534,"total_conv":15025},{"date":"04/20/2025","ice_all":30039,"cbp_all":19145,"total_all":49184,"ice_other":5433,"cbp_other":16564,"total_other":21997,"ice_pend":10987,"cbp_pend":1010,"total_pend":11997,"ice_conv":13619,"cbp_conv":1571,"total_conv":15190},{"date":"04/06/2025","ice_all":28688,"cbp_all":19240,"total_all":47928,"ice_other":5254,"cbp_other":16995,"total_other":22249,"ice_pend":10180,"cbp_pend":885,"total_pend":11065,"ice_conv":13254,"cbp_conv":1360,"total_conv":14614},{"date":"03/23/2025","ice_all":27838,"cbp_all":20054,"total_all":47892,"ice_other":5146,"cbp_other":17868,"total_other":23014,"ice_pend":9618,"cbp_pend":891,"total_pend":10509,"ice_conv":13074,"cbp_conv":1295,"total_conv":14369},{"date":"03/09/2025","ice_all":25732,"cbp_all":20537,"total_all":46269,"ice_other":4684,"cbp_other":18397,"total_other":23081,"ice_pend":8586,"cbp_pend":851,"total_pend":9437,"ice_conv":12462,"cbp_conv":1289,"total_conv":13751},{"date":"02/23/2025","ice_all":22622,"cbp_all":21137,"total_all":43759,"ice_other":3721,"cbp_other":19076,"total_other":22797,"ice_pend":7381,"cbp_pend":777,"total_pend":8158,"ice_conv":11520,"cbp_conv":1284,"total_conv":12804},{"date":"02/09/2025","ice_all":19304,"cbp_all":21865,"total_all":41169,"ice_other":2758,"cbp_other":19780,"total_other":22538,"ice_pend":5997,"cbp_pend":717,"total_pend":6714,"ice_conv":10549,"cbp_conv":1368,"total_conv":11917},{"date":"01/26/2025","ice_all":14882,"cbp_all":24356,"total_all":39238,"ice_other":945,"cbp_other":22161,"total_other":23106,"ice_pend":4682,"cbp_pend":747,"total_pend":5429,"ice_conv":9255,"cbp_conv":1448,"total_conv":10703},{"date":"01/12/2025","ice_all":14557,"cbp_all":25146,"total_all":39703,"ice_other":858,"cbp_other":22991,"total_other":23849,"ice_pend":4605,"cbp_pend":755,"total_pend":5360,"ice_conv":9094,"cbp_conv":1400,"total_conv":10494},{"date":"12/29/2024","ice_all":14320,"cbp_all":24832,"total_all":39152,"ice_other":871,"cbp_other":22732,"total_other":23603,"ice_pend":4512,"cbp_pend":759,"total_pend":5271,"ice_conv":8937,"cbp_conv":1341,"total_conv":10278},{"date":"12/15/2024","ice_all":14292,"cbp_all":24114,"total_all":38406,"ice_other":863,"cbp_other":21984,"total_other":22847,"ice_pend":4423,"cbp_pend":781,"total_pend":5204,"ice_conv":9006,"cbp_conv":1349,"total_conv":10355},{"date":"12/01/2024","ice_all":14073,"cbp_all":24655,"total_all":38728,"ice_other":842,"cbp_other":22519,"total_other":23361,"ice_pend":4330,"cbp_pend":754,"total_pend":5084,"ice_conv":8901,"cbp_conv":1382,"total_conv":10283},{"date":"11/03/2024","ice_all":13902,"cbp_all":24961,"total_all":38863,"ice_other":850,"cbp_other":22738,"total_other":23588,"ice_pend":4187,"cbp_pend":780,"total_pend":4967,"ice_conv":8865,"cbp_conv":1443,"total_conv":10308},{"date":"09/08/2024","ice_all":13561,"cbp_all":23834,"total_all":37395,"ice_other":793,"cbp_other":21678,"total_other":22471,"ice_pend":4158,"cbp_pend":716,"total_pend":4874,"ice_conv":8610,"cbp_conv":1440,"total_conv":10050},{"date":"08/25/2024","ice_all":13508,"cbp_all":22715,"total_all":36223,"ice_other":753,"cbp_other":20574,"total_other":21327,"ice_pend":4091,"cbp_pend":727,"total_pend":4818,"ice_conv":8664,"cbp_conv":1414,"total_conv":10078},{"date":"08/11/2024","ice_all":13450,"cbp_all":22876,"total_all":36326,"ice_other":762,"cbp_other":20670,"total_other":21432,"ice_pend":3976,"cbp_pend":776,"total_pend":4752,"ice_conv":8712,"cbp_conv":1430,"total_conv":10142},{"date":"07/14/2024","ice_all":13252,"cbp_all":23752,"total_all":37004,"ice_other":742,"cbp_other":21277,"total_other":22019,"ice_pend":3727,"cbp_pend":878,"total_pend":4605,"ice_conv":8783,"cbp_conv":1597,"total_conv":10380},{"date":"06/30/2024","ice_all":12831,"cbp_all":24678,"total_all":37509,"ice_other":750,"cbp_other":22247,"total_other":22997,"ice_pend":3578,"cbp_pend":881,"total_pend":4459,"ice_conv":8503,"cbp_conv":1550,"total_conv":10053},{"date":"06/16/2024","ice_all":12841,"cbp_all":25684,"total_all":38525,"ice_other":757,"cbp_other":23158,"total_other":23915,"ice_pend":3534,"cbp_pend":918,"total_pend":4452,"ice_conv":8550,"cbp_conv":1608,"total_conv":10158},{"date":"06/02/2024","ice_all":12479,"cbp_all":24881,"total_all":37360,"ice_other":780,"cbp_other":22466,"total_other":23246,"ice_pend":3432,"cbp_pend":879,"total_pend":4311,"ice_conv":8267,"cbp_conv":1536,"total_conv":9803},{"date":"05/19/2024","ice_all":12397,"cbp_all":24174,"total_all":36571,"ice_other":845,"cbp_other":21675,"total_other":22520,"ice_pend":3395,"cbp_pend":908,"total_pend":4303,"ice_conv":8157,"cbp_conv":1591,"total_conv":9748},{"date":"05/05/2024","ice_all":12336,"cbp_all":24267,"total_all":36603,"ice_other":896,"cbp_other":21679,"total_other":22575,"ice_pend":3234,"cbp_pend":912,"total_pend":4146,"ice_conv":8206,"cbp_conv":1676,"total_conv":9882},{"date":"04/21/2024","ice_all":12083,"cbp_all":22290,"total_all":34373,"ice_other":981,"cbp_other":19871,"total_other":20852,"ice_pend":3179,"cbp_pend":782,"total_pend":3961,"ice_conv":7923,"cbp_conv":1637,"total_conv":9560},{"date":"04/07/2024","ice_all":11803,"cbp_all":22777,"total_all":34580,"ice_other":915,"cbp_other":20286,"total_other":21201,"ice_pend":3054,"cbp_pend":776,"total_pend":3830,"ice_conv":7834,"cbp_conv":1715,"total_conv":9549},{"date":"03/24/2024","ice_all":11683,"cbp_all":25248,"total_all":36931,"ice_other":951,"cbp_other":22794,"total_other":23745,"ice_pend":2988,"cbp_pend":733,"total_pend":3721,"ice_conv":7744,"cbp_conv":1721,"total_conv":9465},{"date":"03/10/2024","ice_all":11488,"cbp_all":27623,"total_all":39111,"ice_other":1016,"cbp_other":25164,"total_other":26180,"ice_pend":2933,"cbp_pend":713,"total_pend":3646,"ice_conv":7539,"cbp_conv":1746,"total_conv":9285},{"date":"02/25/2024","ice_all":11287,"cbp_all":27888,"total_all":39175,"ice_other":1013,"cbp_other":25326,"total_other":26339,"ice_pend":2803,"cbp_pend":745,"total_pend":3548,"ice_conv":7471,"cbp_conv":1817,"total_conv":9288},{"date":"02/11/2024","ice_all":11237,"cbp_all":27021,"total_all":38258,"ice_other":1075,"cbp_other":24396,"total_other":25471,"ice_pend":2707,"cbp_pend":761,"total_pend":3468,"ice_conv":7455,"cbp_conv":1864,"total_conv":9319},{"date":"01/28/2024","ice_all":10955,"cbp_all":27543,"total_all":38498,"ice_other":1128,"cbp_other":24844,"total_other":25972,"ice_pend":2642,"cbp_pend":770,"total_pend":3412,"ice_conv":7185,"cbp_conv":1929,"total_conv":9114},{"date":"01/13/2024","ice_all":10879,"cbp_all":26903,"total_all":37782,"ice_other":1187,"cbp_other":24235,"total_other":25422,"ice_pend":2618,"cbp_pend":737,"total_pend":3355,"ice_conv":7074,"cbp_conv":1931,"total_conv":9005},{"date":"12/31/2023","ice_all":10870,"cbp_all":26261,"total_all":37131,"ice_other":1264,"cbp_other":23532,"total_other":24796,"ice_pend":2583,"cbp_pend":749,"total_pend":3332,"ice_conv":7023,"cbp_conv":1980,"total_conv":9003},{"date":"12/17/2023","ice_all":10388,"cbp_all":25875,"total_all":36263,"ice_other":954,"cbp_other":23258,"total_other":24212,"ice_pend":2406,"cbp_pend":709,"total_pend":3115,"ice_conv":7028,"cbp_conv":1908,"total_conv":8936},{"date":"12/03/2023","ice_all":10270,"cbp_all":26485,"total_all":36755,"ice_other":912,"cbp_other":23931,"total_other":24843,"ice_pend":2397,"cbp_pend":677,"total_pend":3074,"ice_conv":6961,"cbp_conv":1877,"total_conv":8838},{"date":"11/19/2023","ice_all":10098,"cbp_all":28915,"total_all":39013,"ice_other":895,"cbp_other":26457,"total_other":27352,"ice_pend":2304,"cbp_pend":675,"total_pend":2979,"ice_conv":6899,"cbp_conv":1783,"total_conv":8682},{"date":"11/05/2023","ice_all":9930,"cbp_all":29818,"total_all":39748,"ice_other":880,"cbp_other":27434,"total_other":28314,"ice_pend":2314,"cbp_pend":694,"total_pend":3008,"ice_conv":6736,"cbp_conv":1690,"total_conv":8426},{"date":"10/03/2023","ice_all":9967,"cbp_all":26878,"total_all":36845,"ice_other":993,"cbp_other":24641,"total_other":25634,"ice_pend":2306,"cbp_pend":707,"total_pend":3013,"ice_conv":6668,"cbp_conv":1530,"total_conv":8198},{"date":"09/24/2023","ice_all":9404,"cbp_all":25885,"total_all":35289,"ice_other":460,"cbp_other":23789,"total_other":24249,"ice_pend":2323,"cbp_pend":643,"total_pend":2966,"ice_conv":6621,"cbp_conv":1453,"total_conv":8074},{"date":"09/10/2023","ice_all":9411,"cbp_all":26178,"total_all":35589,"ice_other":456,"cbp_other":24179,"total_other":24635,"ice_pend":2328,"cbp_pend":614,"total_pend":2942,"ice_conv":6627,"cbp_conv":1385,"total_conv":8012},{"date":"08/27/2023","ice_all":9624,"cbp_all":23119,"total_all":32743,"ice_other":475,"cbp_other":21169,"total_other":21644,"ice_pend":2414,"cbp_pend":580,"total_pend":2994,"ice_conv":6735,"cbp_conv":1370,"total_conv":8105},{"date":"08/13/2023","ice_all":9903,"cbp_all":20281,"total_all":30184,"ice_other":491,"cbp_other":18334,"total_other":18825,"ice_pend":2579,"cbp_pend":542,"total_pend":3121,"ice_conv":6833,"cbp_conv":1405,"total_conv":8238},{"date":"07/30/2023","ice_all":10400,"cbp_all":20038,"total_all":30438,"ice_other":571,"cbp_other":18120,"total_other":18691,"ice_pend":2769,"cbp_pend":556,"total_pend":3325,"ice_conv":7060,"cbp_conv":1362,"total_conv":8422},{"date":"07/16/2023","ice_all":10268,"cbp_all":20796,"total_all":31064,"ice_other":550,"cbp_other":18780,"total_other":19330,"ice_pend":2609,"cbp_pend":621,"total_pend":3230,"ice_conv":7109,"cbp_conv":1395,"total_conv":8504},{"date":"07/02/2023","ice_all":9682,"cbp_all":20321,"total_all":30003,"ice_other":497,"cbp_other":18452,"total_other":18949,"ice_pend":2408,"cbp_pend":614,"total_pend":3022,"ice_conv":6777,"cbp_conv":1255,"total_conv":8032},{"date":"06/18/2023","ice_all":9595,"cbp_all":20018,"total_all":29613,"ice_other":490,"cbp_other":18196,"total_other":18686,"ice_pend":2327,"cbp_pend":586,"total_pend":2913,"ice_conv":6778,"cbp_conv":1236,"total_conv":8014},{"date":"06/04/2023","ice_all":9221,"cbp_all":20693,"total_all":29914,"ice_other":486,"cbp_other":18838,"total_other":19324,"ice_pend":2191,"cbp_pend":560,"total_pend":2751,"ice_conv":6544,"cbp_conv":1295,"total_conv":7839},{"date":"05/21/2023","ice_all":9434,"cbp_all":17896,"total_all":27330,"ice_other":493,"cbp_other":16212,"total_other":16705,"ice_pend":2222,"cbp_pend":471,"total_pend":2693,"ice_conv":6719,"cbp_conv":1213,"total_conv":7932},{"date":"05/07/2023","ice_all":9431,"cbp_all":11862,"total_all":21293,"ice_other":512,"cbp_other":10432,"total_other":10944,"ice_pend":2177,"cbp_pend":332,"total_pend":2509,"ice_conv":6742,"cbp_conv":1098,"total_conv":7840},{"date":"04/23/2023","ice_all":9820,"cbp_all":15124,"total_all":24944,"ice_other":540,"cbp_other":13614,"total_other":14154,"ice_pend":2287,"cbp_pend":380,"total_pend":2667,"ice_conv":6993,"cbp_conv":1130,"total_conv":8123},{"date":"04/09/2023","ice_all":9777,"cbp_all":15976,"total_all":25753,"ice_other":530,"cbp_other":14354,"total_other":14884,"ice_pend":2184,"cbp_pend":396,"total_pend":2580,"ice_conv":7063,"cbp_conv":1226,"total_conv":8289},{"date":"03/26/2023","ice_all":9521,"cbp_all":17377,"total_all":26898,"ice_other":511,"cbp_other":15774,"total_other":16285,"ice_pend":2151,"cbp_pend":412,"total_pend":2563,"ice_conv":6859,"cbp_conv":1191,"total_conv":8050},{"date":"03/12/2023","ice_all":9431,"cbp_all":18292,"total_all":27723,"ice_other":514,"cbp_other":16678,"total_other":17192,"ice_pend":2129,"cbp_pend":450,"total_pend":2579,"ice_conv":6788,"cbp_conv":1164,"total_conv":7952},{"date":"02/26/2023","ice_all":9112,"cbp_all":17898,"total_all":27010,"ice_other":486,"cbp_other":16353,"total_other":16839,"ice_pend":2071,"cbp_pend":444,"total_pend":2515,"ice_conv":6555,"cbp_conv":1101,"total_conv":7656},{"date":"02/12/2023","ice_all":8638,"cbp_all":17772,"total_all":26410,"ice_other":434,"cbp_other":16261,"total_other":16695,"ice_pend":2005,"cbp_pend":429,"total_pend":2434,"ice_conv":6199,"cbp_conv":1082,"total_conv":7281},{"date":"01/29/2023","ice_all":8296,"cbp_all":15874,"total_all":24170,"ice_other":372,"cbp_other":14360,"total_other":14732,"ice_pend":1888,"cbp_pend":403,"total_pend":2291,"ice_conv":6036,"cbp_conv":1111,"total_conv":7147},{"date":"01/15/2023","ice_all":8069,"cbp_all":12823,"total_all":20892,"ice_other":366,"cbp_other":11344,"total_other":11710,"ice_pend":1821,"cbp_pend":351,"total_pend":2172,"ice_conv":5882,"cbp_conv":1128,"total_conv":7010},{"date":"01/01/2023","ice_all":8112,"cbp_all":12394,"total_all":20506,"ice_other":359,"cbp_other":10858,"total_other":11217,"ice_pend":1852,"cbp_pend":407,"total_pend":2259,"ice_conv":5901,"cbp_conv":1129,"total_conv":7030},{"date":"12/18/2022","ice_all":8168,"cbp_all":14892,"total_all":23060,"ice_other":387,"cbp_other":13331,"total_other":13718,"ice_pend":1861,"cbp_pend":440,"total_pend":2301,"ice_conv":5920,"cbp_conv":1121,"total_conv":7041},{"date":"12/04/2022","ice_all":8218,"cbp_all":20808,"total_all":29026,"ice_other":436,"cbp_other":19211,"total_other":19647,"ice_pend":1935,"cbp_pend":478,"total_pend":2413,"ice_conv":5847,"cbp_conv":1119,"total_conv":6966},{"date":"11/20/2022","ice_all":8191,"cbp_all":21810,"total_all":30001,"ice_other":454,"cbp_other":20276,"total_other":20730,"ice_pend":1968,"cbp_pend":417,"total_pend":2385,"ice_conv":5769,"cbp_conv":1117,"total_conv":6886},{"date":"10/31/2022","ice_all":8199,"cbp_all":21785,"total_all":29984,"ice_other":476,"cbp_other":20300,"total_other":20776,"ice_pend":1982,"cbp_pend":413,"total_pend":2395,"ice_conv":5741,"cbp_conv":1072,"total_conv":6813},{"date":"09/25/2022","ice_all":7609,"cbp_all":17525,"total_all":25134,"ice_other":460,"cbp_other":16204,"total_other":16664,"ice_pend":1695,"cbp_pend":345,"total_pend":2040,"ice_conv":5454,"cbp_conv":976,"total_conv":6430},{"date":"09/10/2022","ice_all":7296,"cbp_all":18480,"total_all":25776,"ice_other":457,"cbp_other":17176,"total_other":17633,"ice_pend":1659,"cbp_pend":332,"total_pend":1991,"ice_conv":5180,"cbp_conv":972,"total_conv":6152},{"date":"08/15/2022","ice_all":6954,"cbp_all":17173,"total_all":24127,"ice_other":477,"cbp_other":15969,"total_other":16446,"ice_pend":1483,"cbp_pend":295,"total_pend":1778,"ice_conv":4994,"cbp_conv":909,"total_conv":5903},{"date":"07/31/2022","ice_all":6559,"cbp_all":16831,"total_all":23390,"ice_other":451,"cbp_other":15718,"total_other":16169,"ice_pend":1324,"cbp_pend":282,"total_pend":1606,"ice_conv":4784,"cbp_conv":831,"total_conv":5615},{"date":"07/17/2022","ice_all":6347,"cbp_all":16539,"total_all":22886,"ice_other":427,"cbp_other":15371,"total_other":15798,"ice_pend":1234,"cbp_pend":304,"total_pend":1538,"ice_conv":4686,"cbp_conv":864,"total_conv":5550},{"date":"07/05/2022","ice_all":6040,"cbp_all":17116,"total_all":23156,"ice_other":372,"cbp_other":15948,"total_other":16320,"ice_pend":1074,"cbp_pend":328,"total_pend":1402,"ice_conv":4594,"cbp_conv":840,"total_conv":5434},{"date":"06/19/2022","ice_all":5979,"cbp_all":17411,"total_all":23390,"ice_other":362,"cbp_other":16180,"total_other":16542,"ice_pend":1017,"cbp_pend":326,"total_pend":1343,"ice_conv":4600,"cbp_conv":905,"total_conv":5505},{"date":"06/05/2022","ice_all":5795,"cbp_all":18796,"total_all":24591,"ice_other":339,"cbp_other":17572,"total_other":17911,"ice_pend":980,"cbp_pend":347,"total_pend":1327,"ice_conv":4476,"cbp_conv":877,"total_conv":5353},{"date":"05/07/2022","ice_all":5398,"cbp_all":16883,"total_all":22281,"ice_other":321,"cbp_other":15713,"total_other":16034,"ice_pend":892,"cbp_pend":334,"total_pend":1226,"ice_conv":4185,"cbp_conv":836,"total_conv":5021},{"date":"04/24/2022","ice_all":5315,"cbp_all":14187,"total_all":19502,"ice_other":344,"cbp_other":13101,"total_other":13445,"ice_pend":829,"cbp_pend":348,"total_pend":1177,"ice_conv":4142,"cbp_conv":738,"total_conv":4880},{"date":"04/11/2022","ice_all":5212,"cbp_all":13634,"total_all":18846,"ice_other":394,"cbp_other":12741,"total_other":13135,"ice_pend":790,"cbp_pend":292,"total_pend":1082,"ice_conv":4028,"cbp_conv":601,"total_conv":4629},{"date":"03/27/2022","ice_all":5060,"cbp_all":15673,"total_all":20733,"ice_other":309,"cbp_other":14724,"total_other":15033,"ice_pend":709,"cbp_pend":370,"total_pend":1079,"ice_conv":4042,"cbp_conv":579,"total_conv":4621},{"date":"03/13/2022","ice_all":5007,"cbp_all":15139,"total_all":20146,"ice_other":204,"cbp_other":14201,"total_other":14405,"ice_pend":710,"cbp_pend":339,"total_pend":1049,"ice_conv":4093,"cbp_conv":599,"total_conv":4692},{"date":"02/27/2022","ice_all":4889,"cbp_all":13095,"total_all":17984,"ice_other":195,"cbp_other":12141,"total_other":12336,"ice_pend":657,"cbp_pend":325,"total_pend":982,"ice_conv":4037,"cbp_conv":629,"total_conv":4666},{"date":"02/13/2022","ice_all":4911,"cbp_all":15037,"total_all":19948,"ice_other":203,"cbp_other":14019,"total_other":14222,"ice_pend":632,"cbp_pend":367,"total_pend":999,"ice_conv":4076,"cbp_conv":651,"total_conv":4727},{"date":"01/16/2022","ice_all":4721,"cbp_all":16165,"total_all":20886,"ice_other":217,"cbp_other":15285,"total_other":15502,"ice_pend":580,"cbp_pend":270,"total_pend":850,"ice_conv":3924,"cbp_conv":610,"total_conv":4534},{"date":"01/02/2022","ice_all":4658,"cbp_all":17410,"total_all":22068,"ice_other":210,"cbp_other":16527,"total_other":16737,"ice_pend":580,"cbp_pend":280,"total_pend":860,"ice_conv":3868,"cbp_conv":603,"total_conv":4471},{"date":"12/19/2021","ice_all":4629,"cbp_all":15994,"total_all":20623,"ice_other":242,"cbp_other":15150,"total_other":15392,"ice_pend":575,"cbp_pend":220,"total_pend":795,"ice_conv":3812,"cbp_conv":624,"total_conv":4436},{"date":"12/05/2021","ice_all":4762,"cbp_all":17190,"total_all":21952,"ice_other":248,"cbp_other":16214,"total_other":16462,"ice_pend":609,"cbp_pend":322,"total_pend":931,"ice_conv":3905,"cbp_conv":654,"total_conv":4559},{"date":"11/21/2021","ice_all":4710,"cbp_all":17728,"total_all":22438,"ice_other":272,"cbp_other":16848,"total_other":17120,"ice_pend":592,"cbp_pend":260,"total_pend":852,"ice_conv":3846,"cbp_conv":620,"total_conv":4466},{"date":"10/01/2021","ice_all":4996,"cbp_all":17133,"total_all":22129,"ice_other":523,"cbp_other":16217,"total_other":16740,"ice_pend":525,"cbp_pend":327,"total_pend":852,"ice_conv":3948,"cbp_conv":589,"total_conv":4537},{"date":"09/16/2021","ice_all":4623,"cbp_all":16943,"total_all":21566,"ice_other":180,"cbp_other":16062,"total_other":16242,"ice_pend":478,"cbp_pend":293,"total_pend":771,"ice_conv":3965,"cbp_conv":588,"total_conv":4553},{"date":"09/13/2021","ice_all":4537,"cbp_all":18477,"total_all":23014,"ice_other":194,"cbp_other":17569,"total_other":17763,"ice_pend":482,"cbp_pend":326,"total_pend":808,"ice_conv":3861,"cbp_conv":582,"total_conv":4443},{"date":"08/24/2021","ice_all":4589,"cbp_all":20573,"total_all":25162,"ice_other":248,"cbp_other":19584,"total_other":19832,"ice_pend":446,"cbp_pend":389,"total_pend":835,"ice_conv":3895,"cbp_conv":600,"total_conv":4495},{"date":"08/06/2021","ice_all":4555,"cbp_all":20971,"total_all":25526,"ice_other":248,"cbp_other":19805,"total_other":20053,"ice_pend":426,"cbp_pend":545,"total_pend":971,"ice_conv":3881,"cbp_conv":621,"total_conv":4502},{"date":"07/22/2021","ice_all":4548,"cbp_all":22223,"total_all":26771,"ice_other":236,"cbp_other":21018,"total_other":21254,"ice_pend":439,"cbp_pend":639,"total_pend":1078,"ice_conv":3873,"cbp_conv":566,"total_conv":4439},{"date":"07/08/2021","ice_all":4604,"cbp_all":22613,"total_all":27217,"ice_other":258,"cbp_other":21409,"total_other":21667,"ice_pend":424,"cbp_pend":693,"total_pend":1117,"ice_conv":3922,"cbp_conv":511,"total_conv":4433},{"date":"06/24/2021","ice_all":4668,"cbp_all":21554,"total_all":26222,"ice_other":306,"cbp_other":20417,"total_other":20723,"ice_pend":422,"cbp_pend":678,"total_pend":1100,"ice_conv":3940,"cbp_conv":459,"total_conv":4399},{"date":"06/11/2021","ice_all":4605,"cbp_all":19858,"total_all":24463,"ice_other":257,"cbp_other":18831,"total_other":19088,"ice_pend":433,"cbp_pend":604,"total_pend":1037,"ice_conv":3915,"cbp_conv":423,"total_conv":4338},{"date":"05/28/2021","ice_all":4667,"cbp_all":16852,"total_all":21519,"ice_other":250,"cbp_other":15916,"total_other":16166,"ice_pend":437,"cbp_pend":534,"total_pend":971,"ice_conv":3980,"cbp_conv":402,"total_conv":4382},{"date":"05/13/2021","ice_all":4825,"cbp_all":14216,"total_all":19041,"ice_other":298,"cbp_other":13567,"total_other":13865,"ice_pend":448,"cbp_pend":238,"total_pend":686,"ice_conv":4079,"cbp_conv":411,"total_conv":4490},{"date":"05/03/2021","ice_all":4883,"cbp_all":10814,"total_all":15697,"ice_other":255,"cbp_other":10222,"total_other":10477,"ice_pend":485,"cbp_pend":211,"total_pend":696,"ice_conv":4143,"cbp_conv":381,"total_conv":4524},{"date":"04/14/2021","ice_all":5306,"cbp_all":9830,"total_all":15136,"ice_other":331,"cbp_other":9214,"total_other":9545,"ice_pend":586,"cbp_pend":240,"total_pend":826,"ice_conv":4389,"cbp_conv":376,"total_conv":4765},{"date":"03/31/2021","ice_all":5775,"cbp_all":8139,"total_all":13914,"ice_other":270,"cbp_other":7548,"total_other":7818,"ice_pend":720,"cbp_pend":199,"total_pend":919,"ice_conv":4785,"cbp_conv":392,"total_conv":5177},{"date":"03/17/2021","ice_all":6879,"cbp_all":7173,"total_all":14052,"ice_other":437,"cbp_other":6506,"total_other":6943,"ice_pend":1030,"cbp_pend":222,"total_pend":1252,"ice_conv":5412,"cbp_conv":445,"total_conv":5857},{"date":"02/25/2021","ice_all":8351,"cbp_all":4907,"total_all":13258,"ice_other":478,"cbp_other":4144,"total_other":4622,"ice_pend":1655,"cbp_pend":235,"total_pend":1890,"ice_conv":6218,"cbp_conv":528,"total_conv":6746},{"date":"02/11/2021","ice_all":9421,"cbp_all":4674,"total_all":14095,"ice_other":523,"cbp_other":3904,"total_other":4427,"ice_pend":2105,"cbp_pend":201,"total_pend":2306,"ice_conv":6793,"cbp_conv":569,"total_conv":7362},{"date":"01/22/2021","ice_all":9879,"cbp_all":4316,"total_all":14195,"ice_other":526,"cbp_other":3527,"total_other":4053,"ice_pend":2333,"cbp_pend":211,"total_pend":2544,"ice_conv":7020,"cbp_conv":578,"total_conv":7598},{"date":"01/07/2021","ice_all":10710,"cbp_all":4734,"total_all":15444,"ice_other":589,"cbp_other":3802,"total_other":4391,"ice_pend":2623,"cbp_pend":241,"total_pend":2864,"ice_conv":7498,"cbp_conv":691,"total_conv":8189},{"date":"12/30/2020","ice_all":10789,"cbp_all":4561,"total_all":15350,"ice_other":604,"cbp_other":3664,"total_other":4268,"ice_pend":2600,"cbp_pend":210,"total_pend":2810,"ice_conv":7585,"cbp_conv":687,"total_conv":8272},{"date":"12/10/2020","ice_all":11011,"cbp_all":4761,"total_all":15772,"ice_other":557,"cbp_other":3819,"total_other":4376,"ice_pend":2701,"cbp_pend":247,"total_pend":2948,"ice_conv":7753,"cbp_conv":695,"total_conv":8448},{"date":"11/26/2020","ice_all":11229,"cbp_all":4846,"total_all":16075,"ice_other":559,"cbp_other":3918,"total_other":4477,"ice_pend":2737,"cbp_pend":229,"total_pend":2966,"ice_conv":7933,"cbp_conv":699,"total_conv":8632},{"date":"11/14/2020","ice_all":11503,"cbp_all":5131,"total_all":16634,"ice_other":566,"cbp_other":4163,"total_other":4729,"ice_pend":2751,"cbp_pend":223,"total_pend":2974,"ice_conv":8186,"cbp_conv":745,"total_conv":8931},{"date":"09/18/2020","ice_all":13432,"cbp_all":6586,"total_all":20018,"ice_other":694,"cbp_other":5200,"total_other":5894,"ice_pend":3074,"cbp_pend":277,"total_pend":3351,"ice_conv":9664,"cbp_conv":1109,"total_conv":10773},{"date":"09/04/2020","ice_all":13509,"cbp_all":6980,"total_all":20489,"ice_other":682,"cbp_other":5422,"total_other":6104,"ice_pend":2964,"cbp_pend":272,"total_pend":3236,"ice_conv":9863,"cbp_conv":1286,"total_conv":11149},{"date":"08/21/2020","ice_all":13597,"cbp_all":7410,"total_all":21007,"ice_other":732,"cbp_other":5716,"total_other":6448,"ice_pend":2915,"cbp_pend":272,"total_pend":3187,"ice_conv":9950,"cbp_conv":1422,"total_conv":11372},{"date":"08/08/2020","ice_all":13437,"cbp_all":7681,"total_all":21118,"ice_other":754,"cbp_other":5930,"total_other":6684,"ice_pend":2830,"cbp_pend":283,"total_pend":3113,"ice_conv":9853,"cbp_conv":1468,"total_conv":11321},{"date":"08/01/2020","ice_all":13441,"cbp_all":8105,"total_all":21546,"ice_other":770,"cbp_other":6244,"total_other":7014,"ice_pend":2777,"cbp_pend":305,"total_pend":3082,"ice_conv":9894,"cbp_conv":1556,"total_conv":11450},{"date":"07/25/2020","ice_all":13501,"cbp_all":8383,"total_all":21884,"ice_other":789,"cbp_other":6471,"total_other":7260,"ice_pend":2794,"cbp_pend":320,"total_pend":3114,"ice_conv":9918,"cbp_conv":1592,"total_conv":11510},{"date":"07/18/2020","ice_all":13295,"cbp_all":8847,"total_all":22142,"ice_other":799,"cbp_other":6867,"total_other":7666,"ice_pend":2758,"cbp_pend":327,"total_pend":3085,"ice_conv":9738,"cbp_conv":1653,"total_conv":11391},{"date":"07/11/2020","ice_all":13359,"cbp_all":8981,"total_all":22340,"ice_other":799,"cbp_other":6978,"total_other":7777,"ice_pend":2755,"cbp_pend":316,"total_pend":3071,"ice_conv":9805,"cbp_conv":1687,"total_conv":11492},{"date":"07/04/2020","ice_all":13332,"cbp_all":9247,"total_all":22579,"ice_other":816,"cbp_other":7140,"total_other":7956,"ice_pend":2702,"cbp_pend":329,"total_pend":3031,"ice_conv":9814,"cbp_conv":1778,"total_conv":11592},{"date":"06/27/2020","ice_all":13484,"cbp_all":9321,"total_all":22805,"ice_other":872,"cbp_other":7205,"total_other":8077,"ice_pend":2763,"cbp_pend":333,"total_pend":3096,"ice_conv":9849,"cbp_conv":1783,"total_conv":11632},{"date":"06/20/2020","ice_all":13641,"cbp_all":9788,"total_all":23429,"ice_other":898,"cbp_other":7594,"total_other":8492,"ice_pend":2797,"cbp_pend":363,"total_pend":3160,"ice_conv":9946,"cbp_conv":1831,"total_conv":11777},{"date":"06/13/2020","ice_all":13914,"cbp_all":10127,"total_all":24041,"ice_other":959,"cbp_other":7852,"total_other":8811,"ice_pend":2869,"cbp_pend":375,"total_pend":3244,"ice_conv":10086,"cbp_conv":1900,"total_conv":11986},{"date":"06/06/2020","ice_all":14125,"cbp_all":10588,"total_all":24713,"ice_other":992,"cbp_other":8285,"total_other":9277,"ice_pend":2936,"cbp_pend":370,"total_pend":3306,"ice_conv":10197,"cbp_conv":1933,"total_conv":12130},{"date":"05/30/2020","ice_all":14339,"cbp_all":11082,"total_all":25421,"ice_other":1021,"cbp_other":8748,"total_other":9769,"ice_pend":2982,"cbp_pend":391,"total_pend":3373,"ice_conv":10336,"cbp_conv":1943,"total_conv":12279},{"date":"05/23/2020","ice_all":14549,"cbp_all":11362,"total_all":25911,"ice_other":1053,"cbp_other":9015,"total_other":10068,"ice_pend":3014,"cbp_pend":394,"total_pend":3408,"ice_conv":10482,"cbp_conv":1953,"total_conv":12435},{"date":"05/16/2020","ice_all":14776,"cbp_all":11884,"total_all":26660,"ice_other":1104,"cbp_other":9503,"total_other":10607,"ice_pend":3062,"cbp_pend":392,"total_pend":3454,"ice_conv":10610,"cbp_conv":1989,"total_conv":12599},{"date":"05/09/2020","ice_all":15405,"cbp_all":12503,"total_all":27908,"ice_other":1161,"cbp_other":10040,"total_other":11201,"ice_pend":3231,"cbp_pend":408,"total_pend":3639,"ice_conv":11013,"cbp_conv":2055,"total_conv":13068},{"date":"05/02/2020","ice_all":15676,"cbp_all":13189,"total_all":28865,"ice_other":1225,"cbp_other":10678,"total_other":11903,"ice_pend":3339,"cbp_pend":440,"total_pend":3779,"ice_conv":11112,"cbp_conv":2071,"total_conv":13183},{"date":"04/25/2020","ice_all":15855,"cbp_all":13820,"total_all":29675,"ice_other":1277,"cbp_other":11283,"total_other":12560,"ice_pend":3452,"cbp_pend":445,"total_pend":3897,"ice_conv":11126,"cbp_conv":2092,"total_conv":13218},{"date":"04/18/2020","ice_all":16171,"cbp_all":14566,"total_all":30737,"ice_other":1343,"cbp_other":11944,"total_other":13287,"ice_pend":3590,"cbp_pend":480,"total_pend":4070,"ice_conv":11238,"cbp_conv":2142,"total_conv":13380},{"date":"04/11/2020","ice_all":16874,"cbp_all":15435,"total_all":32309,"ice_other":1460,"cbp_other":12669,"total_other":14129,"ice_pend":3897,"cbp_pend":509,"total_pend":4406,"ice_conv":11517,"cbp_conv":2257,"total_conv":13774},{"date":"03/21/2020","ice_all":19253,"cbp_all":18805,"total_all":38058,"ice_other":2058,"cbp_other":15954,"total_other":18012,"ice_pend":4704,"cbp_pend":560,"total_pend":5264,"ice_conv":12491,"cbp_conv":2291,"total_conv":14782},{"date":"02/29/2020","ice_all":18897,"cbp_all":19640,"total_all":38537,"ice_other":2041,"cbp_other":16798,"total_other":18839,"ice_pend":4675,"cbp_pend":554,"total_pend":5229,"ice_conv":12181,"cbp_conv":2288,"total_conv":14469},{"date":"02/08/2020","ice_all":18679,"cbp_all":20743,"total_all":39422,"ice_other":2003,"cbp_other":17771,"total_other":19774,"ice_pend":4565,"cbp_pend":619,"total_pend":5184,"ice_conv":12111,"cbp_conv":2353,"total_conv":14464},{"date":"01/04/2020","ice_all":17981,"cbp_all":23650,"total_all":41631,"ice_other":1691,"cbp_other":20396,"total_other":22087,"ice_pend":4462,"cbp_pend":711,"total_pend":5173,"ice_conv":11828,"cbp_conv":2543,"total_conv":14371},{"date":"12/21/2019","ice_all":17887,"cbp_all":24046,"total_all":41933,"ice_other":1808,"cbp_other":20837,"total_other":22645,"ice_pend":4301,"cbp_pend":692,"total_pend":4993,"ice_conv":11778,"cbp_conv":2517,"total_conv":14295},{"date":"11/30/2019","ice_all":18298,"cbp_all":26562,"total_all":44860,"ice_other":1844,"cbp_other":23242,"total_other":25086,"ice_pend":4439,"cbp_pend":696,"total_pend":5135,"ice_conv":12015,"cbp_conv":2624,"total_conv":14639},{"date":"10/26/2019","ice_all":18730,"cbp_all":30689,"total_all":49419,"ice_other":1952,"cbp_other":26670,"total_other":28622,"ice_pend":4390,"cbp_pend":813,"total_pend":5203,"ice_conv":12388,"cbp_conv":3206,"total_conv":15594},{"date":"09/30/2019","ice_all":18881,"cbp_all":32041,"total_all":50922,"ice_other":1926,"cbp_other":27517,"total_other":29443,"ice_pend":4412,"cbp_pend":947,"total_pend":5359,"ice_conv":12543,"cbp_conv":3577,"total_conv":16120},{"date":"09/21/2019","ice_all":18170,"cbp_all":33132,"total_all":51302,"ice_other":1862,"cbp_other":28404,"total_other":30266,"ice_pend":4328,"cbp_pend":1013,"total_pend":5341,"ice_conv":11980,"cbp_conv":3715,"total_conv":15695},{"date":"08/31/2019","ice_all":18101,"cbp_all":34829,"total_all":52930,"ice_other":1841,"cbp_other":29577,"total_other":31418,"ice_pend":4146,"cbp_pend":1169,"total_pend":5315,"ice_conv":12114,"cbp_conv":4083,"total_conv":16197},{"date":"08/03/2019","ice_all":18468,"cbp_all":37186,"total_all":55654,"ice_other":1658,"cbp_other":31827,"total_other":33485,"ice_pend":4249,"cbp_pend":1244,"total_pend":5493,"ice_conv":12561,"cbp_conv":4115,"total_conv":16676},{"date":"06/01/2019","ice_all":19060,"cbp_all":33405,"total_all":52465,"ice_other":1772,"cbp_other":27895,"total_other":29667,"ice_pend":4410,"cbp_pend":1163,"total_pend":5573,"ice_conv":12878,"cbp_conv":4347,"total_conv":17225},{"date":"05/04/2019","ice_all":19549,"cbp_all":30096,"total_all":49645,"ice_other":1797,"cbp_other":24625,"total_other":26422,"ice_pend":4571,"cbp_pend":1115,"total_pend":5686,"ice_conv":13181,"cbp_conv":4356,"total_conv":17537}]
|
requirements.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
gradio, pandas, plotly, requests
|
streamlit_app.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import backend as be
|
3 |
+
import footnotes
|
4 |
+
|
5 |
+
st.title("US Immigration Enforcement Data")
|
6 |
+
|
7 |
+
graph_tab, data_tab, about_tab = st.tabs(["📈 Graphs", "📋 Data", "ℹ️ About"])
|
8 |
+
with graph_tab:
|
9 |
+
col1, col2, col3 = st.columns(3)
|
10 |
+
with col1:
|
11 |
+
dataset = st.selectbox("Dataset", ["Arresting Authority", "Criminality"])
|
12 |
+
with col2:
|
13 |
+
display = st.selectbox("Display", ["Count", "Percent"])
|
14 |
+
with col3:
|
15 |
+
# In the original dataset the "Criminality" table has 3 tables. This lets
|
16 |
+
# you see how the criminality of detainees varies by arresting authority.
|
17 |
+
if dataset == "Criminality":
|
18 |
+
authority = st.selectbox("Arresting Authority", ["All", "ICE", "CBP"])
|
19 |
+
else:
|
20 |
+
authority = None
|
21 |
+
|
22 |
+
fig = be.get_graph(dataset, display, authority)
|
23 |
+
st.plotly_chart(fig, use_container_width=True)
|
24 |
+
# Each dataset has different footnotes.
|
25 |
+
st.markdown(footnotes.get_footnote(dataset), unsafe_allow_html=True)
|
26 |
+
with data_tab:
|
27 |
+
st.write(open("data.md").read())
|
28 |
+
df = be.get_detention_data()
|
29 |
+
st.dataframe(df, hide_index=True)
|
30 |
+
st.download_button(
|
31 |
+
label="Download as CSV",
|
32 |
+
data=df.to_csv(index=False),
|
33 |
+
file_name="ice_detention_data.csv",
|
34 |
+
mime="text/csv",
|
35 |
+
)
|
36 |
+
with about_tab:
|
37 |
+
st.write(open("about.md").read())
|
38 |
+
|
39 |
+
st.markdown(
|
40 |
+
"""
|
41 |
+
---
|
42 |
+
:small[Created by [Ari Lamstein](https://arilamstein.com/).
|
43 |
+
View the source code
|
44 |
+
[here](https://github.com/arilamstein/immigration_enforcement).]
|
45 |
+
"""
|
46 |
+
)
|