jnaiman commited on
Commit
13a4cc8
·
1 Parent(s): 9052957

reorg for multipage

Browse files
Hello.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+
4
+ st.set_page_config(
5
+ page_title="Hello",
6
+ page_icon="👋",
7
+ )
8
+
9
+ st.sidebar.success("Select a Page")
10
+
11
+ st.header('Multi-page Apps')
12
+
13
+ st.markdown("""
14
+ So far our apps have been rather long and have many parts! We can organize this a bit better by building [multi-page apps](https://docs.streamlit.io/get-started/tutorials/create-a-multipage-app).
15
+ """)
16
+
17
+ st.subheader('Reorganize our App')
18
+
19
+ st.markdown("""We need to do several things including:
20
+ * Rename our app file to something that starts with a capital letter
21
+ * Make sure this is the name that is in the `README.md` file
22
+ * Add in some page info on our "main" page
23
+ * Add in a sidebar on our main page to view all pages
24
+ * Add in a `pages` directory
25
+ * Add pages with the correct format to the `pages` directory
26
+ * Reorganize our page into this new format
27
+ """)
28
+
29
+ st.write("Let's get to each of these!")
30
+
31
+ st.subheader('Step 1: Create our "landing" page')
32
+
33
+ st.markdown("""
34
+ First, let's rename our `app.py` file to `Hello.py`.
35
+
36
+ Then, we need to make sure this is also updated in our `README.md` file.
37
+
38
+ We can then start running our script with `streamlit run Hello.py`.
39
+ """)
40
+
41
+ st.subheader('Step 2: Add some page info to our "landing" page')
42
+
43
+ st.markdown("""Now, let's add in some page info for this landing page:
44
+ """)
45
+ st.code("""
46
+ st.set_page_config(
47
+ page_title="Hello",
48
+ page_icon="👋",
49
+ )
50
+ """)
51
+
52
+ st.markdown("""Finally, let's add a sidebar to display all our pages:""")
53
+ st.code("""
54
+ st.sidebar.success("Select a Page")
55
+ """)
56
+ st.markdown("**Make sure both of these last items are at the top of your `Hello.py` file!**")
57
+
58
+ st.subheader('Step 3: Create pages')
59
+
60
+ st.markdown("""First, create a folder called `pages/`.
61
+
62
+ Then, create four pages:
63
+ 1. `1_Data_Introduction.py`
64
+ 1. `2_Widget_Exploration.py`
65
+ 1. `3_Altair_Plots.py`
66
+ 1. `4_Other_Tools.py`
67
+
68
+ **NOTE: The formatting here of the file names is specific!** It determines their order and how they appear on the sidebar.
69
+
70
+ Each page will need to have:
71
+ 1. A `set_page_config` call, including a title and an icon
72
+ 1. A message displayed on page selection with a `sidebar.header` call
73
+ """)
74
+
75
+ st.markdown("""
76
+ Once this is done, we can then move the items from our original `app.py` file to each page.
77
+ """)
78
+
README.md CHANGED
@@ -1,11 +1,11 @@
1
  ---
2
- title: Prep notebook -- My Streamlit App
3
  emoji: 🏢
4
  colorFrom: blue
5
  colorTo: gray
6
  sdk: streamlit
7
- sdk_version: 1.36.0
8
- app_file: app.py
9
  pinned: false
10
  license: mit
11
  ---
 
1
  ---
2
+ title: Prep notebook -- My Multi-page Streamlit App (Day 2)
3
  emoji: 🏢
4
  colorFrom: blue
5
  colorTo: gray
6
  sdk: streamlit
7
+ sdk_version: 1.39.0
8
+ app_file: Hello.py
9
  pinned: false
10
  license: mit
11
  ---
app.py CHANGED
@@ -1,12 +1,4 @@
1
 
2
-
3
-
4
- # day 2/3 -- "grab bag" of other things
5
- # multi-page apps? ==> maybe day 2? ==> does this work with HF apps??
6
- # Week 12 -- https://docs.streamlit.io/develop/tutorials/databases <- touch on but say we'll be just doing csv files
7
- # Week 12 -- embedding streamlit spaces on other webpages? wait until Jekyll? https://huggingface.co/docs/hub/en/spaces-sdks-streamlit#embed-streamlit-spaces-on-other-webpages
8
-
9
-
10
  #######################################################
11
  # 1. Getting setup -- using our HF template
12
  #######################################################
@@ -109,7 +101,7 @@ st.pyplot(fig)
109
  st.write('''The requirements.txt file contains all the packages needed
110
  for our app to run. These include (for our application):''')
111
  st.code('''
112
- streamlit
113
  altair
114
  numpy
115
  pandas
@@ -119,6 +111,8 @@ matplotlib
119
  # NOTE: for any package you want to use in your app.py file, you must include it in
120
  # the requirements.txt file!
121
 
 
 
122
  ### 3.3 Push these changes to HF -- README.md ###
123
 
124
  # While we're doing this, let's also take a look at the README.md file!
@@ -132,12 +126,13 @@ emoji: 🏢
132
  colorFrom: blue
133
  colorTo: gray
134
  sdk: streamlit
135
- sdk_version: 1.36.0
136
  app_file: app.py
137
  pinned: false
138
  license: mit
139
  ---
140
  ''')
 
141
 
142
  # Some important things to note here:
143
 
@@ -232,9 +227,6 @@ Note here that we made use of text highlight [colors](https://docs.streamlit.io/
232
 
233
  st.subheader('Connecting Widgets and Plots')
234
 
235
- st.markdown("""
236
- We can also
237
- """)
238
 
239
  st.markdown("""
240
  There are actually [many types of charts](https://docs.streamlit.io/develop/api-reference/charts)
@@ -303,7 +295,7 @@ fig.tight_layout()
303
  fig.savefig(buf, format="png")
304
  st.image(buf, width = 500) # can mess around with width, figsize/etc
305
 
306
- st.write("Now, let's make this interactive")
307
  st.markdown("""We'll first use the [multiselect](https://docs.streamlit.io/develop/api-reference/widgets/st.multiselect)
308
  tool in order to allow for multiple state selection. """)
309
 
@@ -403,44 +395,38 @@ if len(states_selected2) > 0: # here we set a default value for the slider, so n
403
  fig2.savefig(buf2, format="png")
404
  fig_col2.image(buf2, width = 400) # changed here to fit better
405
  else:
406
- fig2,ax2 = plt.subplots(figsize=(4,8)) # this changed
407
- extent2 = [bins.min(), bins.max(), 0, len(table.index)]
408
- ax2.imshow(table.values, cmap='hot', interpolation='nearest', extent=extent2)
409
- ax2.set_yticks(range(len(table.index)))
410
- ax2.set_yticklabels(table.index)
411
-
412
- buf2 = BytesIO()
413
- fig2.tight_layout()
414
- fig2.savefig(buf2, format="png")
415
- fig_col2.image(buf2, width = 500) # can mess around with width, figsize/etc
416
-
417
- # THEN: slider for range of student teacher ratios -- do the RANGE slider: https://docs.streamlit.io/develop/api-reference/widgets/st.slider
418
-
419
- # with st.expander('Favorite product by Gender within city'):
420
- # column1, column2 = st.columns([3,1])
421
-
422
- # # Allow the user to select a gender.
423
- # selected_gender = st.radio('What is your Gender:', df.gender.unique(), index = 0)
424
-
425
- # # Apply gender filter.
426
- # gender_product = df[df['gender'] == selected_gender]
427
 
428
- # # Allow the user to select a city.
429
- # select_city = column2.selectbox('Select City', df.sort_values('City').City.unique())
430
 
431
- # # Apply city filter
432
- # city_gender_product = gender_product[gender_product['City'] == select_city]
433
 
434
- # # Use the city_gender_product dataframe as it has filters for gender and city.
435
- # fig = px.histogram(city_gender_product.sort_values('product_line') ,x='product_line', y='gross_income', color = 'product_line',)
 
 
436
 
437
- # if selected_gender == 'Male':
438
- # st.write('What men buy most!')
439
- # else:
440
- # st.write('What female buy most!')
 
 
 
 
 
441
 
442
- # st.plotly_chart(fig, use_container_width=True)
 
 
 
443
 
444
- ################################################
445
- # 5. TODO Multi-page apps (?) this might be for next week/extra
446
- ################################################
 
 
 
 
 
1
 
 
 
 
 
 
 
 
 
2
  #######################################################
3
  # 1. Getting setup -- using our HF template
4
  #######################################################
 
101
  st.write('''The requirements.txt file contains all the packages needed
102
  for our app to run. These include (for our application):''')
103
  st.code('''
104
+ streamlit==1.39.0
105
  altair
106
  numpy
107
  pandas
 
111
  # NOTE: for any package you want to use in your app.py file, you must include it in
112
  # the requirements.txt file!
113
 
114
+ # Note #2: we specified a version of streamlit so we can use some specific widgets
115
+
116
  ### 3.3 Push these changes to HF -- README.md ###
117
 
118
  # While we're doing this, let's also take a look at the README.md file!
 
126
  colorFrom: blue
127
  colorTo: gray
128
  sdk: streamlit
129
+ sdk_version: 1.39.0
130
  app_file: app.py
131
  pinned: false
132
  license: mit
133
  ---
134
  ''')
135
+ st.write("Note: the sdk version has to match what is in your requirements.txt (and with whatever widgets you want to be able to use).")
136
 
137
  # Some important things to note here:
138
 
 
227
 
228
  st.subheader('Connecting Widgets and Plots')
229
 
 
 
 
230
 
231
  st.markdown("""
232
  There are actually [many types of charts](https://docs.streamlit.io/develop/api-reference/charts)
 
295
  fig.savefig(buf, format="png")
296
  st.image(buf, width = 500) # can mess around with width, figsize/etc
297
 
298
+ st.write("Now, let's make this interactive.")
299
  st.markdown("""We'll first use the [multiselect](https://docs.streamlit.io/develop/api-reference/widgets/st.multiselect)
300
  tool in order to allow for multiple state selection. """)
301
 
 
395
  fig2.savefig(buf2, format="png")
396
  fig_col2.image(buf2, width = 400) # changed here to fit better
397
  else:
398
+ min_range = student_teacher_ratio_range[0] # added
399
+ max_range = student_teacher_ratio_range[1] # added
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
 
401
+ df_subset2 = df[(df['Student_teacher_ratio'] >= min_range) & (df['Student_teacher_ratio']<=max_range)] # changed
 
402
 
403
+ # just 10 bins over the full range --> changed
404
+ bins2 = 10 #np.linspace(df['Student_teacher_ratio'].min(),df['Student_teacher_ratio'].max(), 10)
405
 
406
+ # make pivot table -- changed
407
+ table_sub2 = df_subset2.pivot_table(index='State',
408
+ columns=pd.cut(df_subset2['Student_teacher_ratio'], bins2),
409
+ aggfunc='size')
410
 
411
+ base_size = 4
412
+ fig2,ax2 = plt.subplots(figsize=(base_size,2*base_size)) # this changed too for different size
413
+ extent2 = [df_subset2['Student_teacher_ratio'].min(),
414
+ df_subset2['Student_teacher_ratio'].max(),
415
+ 0, len(table_sub2.index)]
416
+ ax2.imshow(table_sub2.values, cmap='hot', interpolation='nearest', extent=extent2)
417
+ ax2.set_yticks(range(len(table_sub2.index)))
418
+ ax2.set_yticklabels(table_sub2.index)
419
+ #ax2.set_xticklabels()
420
 
421
+ buf2 = BytesIO()
422
+ fig2.tight_layout()
423
+ fig2.savefig(buf2, format="png")
424
+ fig_col2.image(buf2, width = 400) # changed here to fit better
425
 
426
+ st.header('Push final page to HF')
427
+ st.markdown("""When ready, do:""")
428
+ st.code("""
429
+ git add -A
430
+ git commit -m "final push of day 1"
431
+ git push
432
+ """)
pages/1_Data_Introduction.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ st.set_page_config(page_title="Introduction to Data", page_icon=":1234:") # not sure what this adds?
4
+ st.sidebar.header("Introduction to Data")
5
+
6
+ st.title('Info about our Dataset')
7
+ mobility_url = 'https://raw.githubusercontent.com/UIUC-iSchool-DataViz/is445_data/main/mobility.csv'
8
+
9
+ st.write("Here is where we could give some background about our dataset.")
10
+ st.write("This would be a good place to include links, references, and images.")
11
+
12
+ import pandas as pd
13
+ df = pd.read_csv(mobility_url)
14
+
15
+ # There are a few ways to show the dataframe if we want our viewer to see the table:
16
+ #df
17
+ st.write(df)
pages/2_Widget_Exploration.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ st.set_page_config(page_title="Widget Exploration", page_icon=":1234:")
4
+ st.sidebar.header("Widget Exploration")
5
+
6
+ st.title('Widget Exploration')
7
+
8
+ st.write("""In a "real" app, we probably wouldn't
9
+ publish our explorations, but here it is a nice excuse to use pages here :smiley:.""")
10
+
11
+
12
+ st.write("How great are you feeling right now?")
13
+ sentiment_mapping = ["one", "two", "three", "four", "five"] # map to these numers
14
+ selected = st.feedback("stars")
15
+ if selected is not None: # make sure we have a selection
16
+ st.markdown(f"You selected {sentiment_mapping[selected]} star(s).")
17
+ if selected < 1:
18
+ st.markdown('Sorry to hear you are so sad :(')
19
+ elif selected < 3:
20
+ st.markdown('A solid medium is great!')
21
+ else:
22
+ st.markdown('Fantastic you are having such a great day!')
23
+
24
+ st.subheader('Radio Buttons')
25
+
26
+ st.markdown("""
27
+ Let's try out a [radio button](https://docs.streamlit.io/develop/api-reference/widgets/st.radio) example.
28
+ """)
29
+
30
+ favoriteViz = st.radio(
31
+ "What's your visualization tool so far?",
32
+ [":rainbow[Streamlit]", "vega-lite :sparkles:", "matplotlib :material/Home:"],
33
+ captions=[
34
+ "New and cool!",
35
+ "So sparkly.",
36
+ "Familiar and comforting.",
37
+ ],
38
+ )
39
+
40
+ if favoriteViz == ":rainbow[Streamlit]":
41
+ st.write("You selected Streamlit!")
42
+ else:
43
+ st.write("You didn't select Streamlit but that's ok, Data Viz still likes you :grin:")
44
+
45
+ st.header('Connecting Plots and Widgets')
46
+
47
+ import pandas as pd
48
+ import numpy as np
49
+ import matplotlib.pyplot as plt
50
+ from io import BytesIO
51
+
52
+
53
+ df = pd.read_csv("https://raw.githubusercontent.com/UIUC-iSchool-DataViz/is445_data/main/mobility.csv")
54
+
55
+ # vertical alignment so they end up side by side
56
+ fig_col2, controls_col2 = st.columns([2,1], vertical_alignment='center')
57
+
58
+ bins = np.linspace(df['Student_teacher_ratio'].min(),df['Student_teacher_ratio'].max(), 10)
59
+ table = df.pivot_table(index='State', columns=pd.cut(df['Student_teacher_ratio'], bins), aggfunc='size')
60
+
61
+ # multi-select
62
+ states_selected2 = controls_col2.multiselect('Which states do you want to view?',
63
+ table.index.values)#, key='unik1155')
64
+ # had to pass unique key to have double widgets with same value
65
+
66
+ # range slider -- added
67
+ student_teacher_ratio_range = controls_col2.slider("Range of student teacher ratio:",
68
+ df['Student_teacher_ratio'].min(),
69
+ df['Student_teacher_ratio'].max(),
70
+ (0.25*df['Student_teacher_ratio'].mean(),
71
+ 0.75*df['Student_teacher_ratio'].mean()))
72
+
73
+ # note all the "2's" here, probably will just update the original one
74
+ if len(states_selected2) > 0: # here we set a default value for the slider, so no need to have a tag
75
+ min_range = student_teacher_ratio_range[0] # added
76
+ max_range = student_teacher_ratio_range[1] # added
77
+
78
+ df_subset2 = df[(df['State'].isin(states_selected2)) & (df['Student_teacher_ratio'] >= min_range) & (df['Student_teacher_ratio']<=max_range)] # changed
79
+
80
+ # just 10 bins over the full range --> changed
81
+ bins2 = 10 #np.linspace(df['Student_teacher_ratio'].min(),df['Student_teacher_ratio'].max(), 10)
82
+
83
+ # make pivot table -- changed
84
+ table_sub2 = df_subset2.pivot_table(index='State',
85
+ columns=pd.cut(df_subset2['Student_teacher_ratio'], bins2),
86
+ aggfunc='size')
87
+
88
+ base_size = 4
89
+ fig2,ax2 = plt.subplots(figsize=(base_size,2*base_size)) # this changed too for different size
90
+ extent2 = [df_subset2['Student_teacher_ratio'].min(),
91
+ df_subset2['Student_teacher_ratio'].max(),
92
+ 0, len(table_sub2.index)]
93
+ ax2.imshow(table_sub2.values, cmap='hot', interpolation='nearest', extent=extent2)
94
+ ax2.set_yticks(range(len(table_sub2.index)))
95
+ ax2.set_yticklabels(table_sub2.index)
96
+ #ax2.set_xticklabels()
97
+
98
+ buf2 = BytesIO()
99
+ fig2.tight_layout()
100
+ fig2.savefig(buf2, format="png")
101
+ fig_col2.image(buf2, width = 400) # changed here to fit better
102
+ else:
103
+ min_range = student_teacher_ratio_range[0] # added
104
+ max_range = student_teacher_ratio_range[1] # added
105
+
106
+ df_subset2 = df[(df['Student_teacher_ratio'] >= min_range) & (df['Student_teacher_ratio']<=max_range)] # changed
107
+
108
+ # just 10 bins over the full range --> changed
109
+ bins2 = 10 #np.linspace(df['Student_teacher_ratio'].min(),df['Student_teacher_ratio'].max(), 10)
110
+
111
+ # make pivot table -- changed
112
+ table_sub2 = df_subset2.pivot_table(index='State',
113
+ columns=pd.cut(df_subset2['Student_teacher_ratio'], bins2),
114
+ aggfunc='size')
115
+
116
+ base_size = 4
117
+ fig2,ax2 = plt.subplots(figsize=(base_size,2*base_size)) # this changed too for different size
118
+ extent2 = [df_subset2['Student_teacher_ratio'].min(),
119
+ df_subset2['Student_teacher_ratio'].max(),
120
+ 0, len(table_sub2.index)]
121
+ ax2.imshow(table_sub2.values, cmap='hot', interpolation='nearest', extent=extent2)
122
+ ax2.set_yticks(range(len(table_sub2.index)))
123
+ ax2.set_yticklabels(table_sub2.index)
124
+ #ax2.set_xticklabels()
125
+
126
+ buf2 = BytesIO()
127
+ fig2.tight_layout()
128
+ fig2.savefig(buf2, format="png")
129
+ fig_col2.image(buf2, width = 400) # changed here to fit better
pages/3_Altair_Plots.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ st.set_page_config(page_title="Altair Plots", page_icon=":1234:")
4
+ st.sidebar.header("Altair Plots")
5
+
6
+ st.title('Altair Plots!')
7
+ st.write("""This is probably the main page we'd be showing in a "real" app.""")
8
+
9
+ # Let's start by copying things we did last time
10
+ import streamlit as st
11
+ import altair as alt
12
+
13
+ # Let's recall a plot that we made with Altair in Jupyterlab:
14
+ # Make sure we copy the URL as well!
15
+ mobility_url = 'https://raw.githubusercontent.com/UIUC-iSchool-DataViz/is445_data/main/mobility.csv'
16
+
17
+ scatters = alt.Chart(mobility_url).mark_point().encode(
18
+ x='Mobility:Q', # "Q for quantiative"
19
+ #y='Population:Q',
20
+ y=alt.Y('Population:Q', scale=alt.Scale(type='log')),
21
+ color=alt.Color('Income:Q', scale=alt.Scale(scheme='sinebow'),bin=alt.Bin(maxbins=5))
22
+ )
23
+
24
+ brush = alt.selection_interval(encodings=['x','y'])
25
+
26
+ chart1 = alt.Chart(mobility_url).mark_rect().encode(
27
+ alt.X("Student_teacher_ratio:Q", bin=alt.Bin(maxbins=10)),
28
+ alt.Y("State:O"),
29
+ alt.Color("count()")
30
+ ).properties(
31
+ height=400
32
+ ).add_params(
33
+ brush
34
+ )
35
+
36
+ chart2 = alt.Chart(mobility_url).mark_bar().encode(
37
+ alt.X("Mobility:Q", bin=True,axis=alt.Axis(title='Mobility Score')),
38
+ alt.Y('count()', axis=alt.Axis(title='Mobility Score Distribution'))
39
+ ).transform_filter(
40
+ brush
41
+ )
42
+
43
+ chart = (chart1.properties(width=300) | chart2.properties(width=300))
44
+
45
+ tab1, tab2 = st.tabs(["Mobility interactive", "Scatter plot"])
46
+
47
+ with tab1:
48
+ st.altair_chart(chart, theme=None, use_container_width=True)
49
+ with tab2:
50
+ st.altair_chart(scatters, theme=None, use_container_width=True)
pages/4_Other_Tools.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ st.set_page_config(page_title="Other Tools", page_icon=":1234:")
4
+ st.sidebar.header("Other Tools")
5
+
6
+ st.title("Other cool things to check out")
7
+
8
+ st.markdown(""" While we won't have time to cover everything, a few things you might want to check out later:
9
+ 1. You can connect databases to Streamlit [like AWS, MongoDB, etc](https://docs.streamlit.io/develop/tutorials/databases)
10
+ 1. You can embed Streamlit Spaces [within other webpages](https://huggingface.co/docs/hub/en/spaces-sdks-streamlit#embed-streamlit-spaces-on-other-webpages)
11
+ 1. If you have models hosted on HuggingFace, you can build [apps that use those models](https://huggingface.co/blog/streamlit-spaces) (like LLMs) and let others use them.
12
+ """)
requirements.txt CHANGED
@@ -1,4 +1,4 @@
1
- streamlit
2
  altair
3
  numpy
4
  pandas
 
1
+ streamlit==1.39.0
2
  altair
3
  numpy
4
  pandas