-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathstatic_charts.qmd
More file actions
250 lines (172 loc) · 8.43 KB
/
static_charts.qmd
File metadata and controls
250 lines (172 loc) · 8.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
---
title: "Static Charts"
filters:
- whitphx/stlite
---
## Displaying charts made with matplotlib
When we want to display static charts, we will often be using the `matplotlib` library.
:::{.callout-tip}
We can use the `st.pyplot()` component to display charts created using matplotlib.
Note that certain other non-graph outputs still use matplotlib's plotting systems - for example, outputs from the `wordcloud` library and the `geopandas` plot method are still technically matplotlib plots. For those, we can use `st.pyplot()` too! This will be covered more in a later chapter.
:::
Below, we create a very simple scatterplot of a dataset.
:::{.callout-note}
We have created the `fig` and `ax` objects by beginning by creating a single subplot with the `plt.subplots` function.
This is sometimes referred to as the object-oriented way of writing matplotlib code.
With this method, we then use one of the matplotlib commands, like scatter or bar, and tell it to plot onto the `ax` object we created.
We can then modify this object using any of the standard matplotlib commands we have become familiar with, such as changing the axis labels.
:::
The final step to ensure the plot is actually displayed is to pass the `fig` variable to `st.pyplot`.
```{python}
#| eval: false
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt # <1>
from palmerpenguins import load_penguins # <2>
penguins = load_penguins() # <3>
fig, ax = plt.subplots(figsize=(15,10)) # <4>
plt.scatter( # <5>
x=penguins["body_mass_g"], # <6>
y=penguins["bill_length_mm"]
)
plt.title("Penguin Body Mass (g) versus Bill Length (mm)") # <7>
ax.set_xlabel("Body Mass (g)") # <8>
ax.set_ylabel("Bill Length (mm)")
st.pyplot(fig) # <9>
```
1. We import the pyplot module of matplotlib using the standard alias 'plt'
2. We also load in a function from a package that gives us easy access to a dataset of penguin body measurements.
3. We use the load_penguins() function, which returns a pandas dataframe, and assign this to the `penguins` variable.
4. We then use the `plt.subplots` function. By just passing in the named argument `figsize` we get a single blank plot that is relatively 1.5x wider than it is long. The tuple - the two numbers within brackets, separated by a comma - is the width and height of the image. Notice on the left of the = we have `fig, ax` rather than a single variable name; this is because `plt.subplots` returns two variables, and this means we can easily access both of these. We always write `fig, ax` in the same order - this is just a standard matplotlib convention.
5. Now we use our chosen plotting function - in this case, we want a scatterplot.
6. We pass in the values to use for our x column - our horizontal axis - using the format `dataframe_variable["column_name"]`, which passes in our list of values as a pandas *series*. For these purposes, the pandas series is effectively a fancy list - it will primarily just contain the value for that column for each row in the dataframe. We repeat this for our y (vertical) axis.
7. We pass in a string to use as the title of the graph with the `plt.title()` function.
8. We can then use various methods of our `ax` variable to update things such as the x and y axis labels.
9. Finally, we pass the completed figure to the `st.pyplot()` function, which will make sure it gets displayed in our app.
:::{.callout-note}
Note that we don't have to specify the axis we are plotting on within our `plt.scatter()` call (i.e. we don't include `ax=ax` as one of the arguments) - it's sufficient to just pass in the data we want to plot, and matplotlib will automatically select the appropriate axis.
:::
```{stlite-python}
import micropip
await micropip.install("setuptools")
await micropip.install("palmerpenguins")
await micropip.install("matplotlib")
import streamlit as st
import pandas as pd
from palmerpenguins import load_penguins
from matplotlib import pyplot as plt
penguins = load_penguins()
fig, ax = plt.subplots(figsize=(15,10))
plt.scatter(x=penguins["body_mass_g"], y=penguins["bill_length_mm"])
plt.title("Penguin Body Mass (g) versus Bill Length (mm)")
ax.set_xlabel("Body Mass (g)")
ax.set_ylabel("Bill Length (mm)")
st.pyplot(fig)
```
## An alternative way of displaying charts made with matplotlib
Instead of using the `st.pyplot()` function, we may find it easier in some cases to save the output figure and serve that to the user using the `st.image()` function instead.
```{python}
#| eval: false
import streamlit as st
import pandas as pd
from matplotlib import pyplot as plt
# import matplotlib.pyplot as plt
from palmerpenguins import load_penguins
penguins = load_penguins()
fig, ax = plt.subplots(figsize=(15,10))
plt.scatter(
x=penguins["body_mass_g"],
y=penguins["bill_length_mm"]
)
plt.title("Penguin Body Mass (g) versus Bill Length (mm)")
ax.set_xlabel("Body Mass (g)")
ax.set_ylabel("Bill Length (mm)")
filename = 'penguins_scatter_method_1.png' # <1>
plt.savefig(filename) # <2>
st.image(filename) # <3>
```
1. We set a filename string, including the file extension of .png
2. Next we save the file to local storage - it will save in the same folder relative to our Streamlit app script.
3. Finally, we use `st.image()` to display the image file we have just created.
:::{.callout-note}
We could also write the last 3 lines of code above as
```{python}
#| eval: false
plt.savefig('penguins_scatter_method_1.png')
st.image('penguins_scatter_method_1.png')
```
though more care must then be taken to ensure that the names are identical! Generally it is better to define the `filename` variable to reduce repetition.
:::
You can see that functionally this appears nearly identical to what we do above!
```{stlite-python}
import micropip
await micropip.install("setuptools")
await micropip.install("palmerpenguins")
import streamlit as st
import pandas as pd
from matplotlib import pyplot as plt
# import matplotlib.pyplot as plt
from palmerpenguins import load_penguins
penguins = load_penguins()
fig, ax = plt.subplots(figsize=(15,10))
plt.scatter(
x=penguins["body_mass_g"],
y=penguins["bill_length_mm"]
)
plt.title("Penguin Body Mass (g) versus Bill Length (mm)")
ax.set_xlabel("Body Mass (g)")
ax.set_ylabel("Bill Length (mm)")
filename = 'penguins_scatter_method_1.png'
plt.savefig(filename)
st.image(filename)
```
## Making use of the available space
Many streamlit components have a parameter called `use_container_width`.
When set to `True` in something like `st.pyplot`, it ensures the output is rescaled to use the maximum available width of the screen.
The parameter is set to `False` by default, which will result in outputs often not optimally using the available space.
:::{.callout-tip}
This can become particularly valuable when we start to explore layout options like columns later in the book.
:::
```{python}
#| eval: false
import streamlit as st
import pandas as pd
# import matplotlib.pyplot as plt
from matplotlib import pyplot as plt
from palmerpenguins import load_penguins
penguins = load_penguins()
fig, ax = plt.subplots(figsize=(15,10))
plt.scatter(x=penguins["body_mass_g"], y=penguins["bill_length_mm"])
plt.title("Penguin Body Mass (g) versus Bill Length (mm)")
ax.set_xlabel("Body Mass (g)")
ax.set_ylabel("Bill Length (mm)")
st.subheader("use_container_width=False") # <1>
st.pyplot(fig) # <2>
st.subheader("use_container_width=True") # <3>
st.pyplot(fig, use_container_width=True) # <4>
```
1. Let's make ourselves a subheader so we can tell the two outputted plots apart
2. First, we use `st.pyplot` without the `use_container_width` argument specified. If not specified, this defaults to `False`.
3. Now let's add another subheader.
4. This time, we pass in the same figure to `st.pyplot`, but this time we specify the `use_container_width` parameter to be `True`.
Take a look at the impact this has in the live version of the app below.
```{stlite-python}
import micropip
await micropip.install("setuptools")
await micropip.install("palmerpenguins")
import streamlit as st
import pandas as pd
# import matplotlib.pyplot as plt
from matplotlib import pyplot as plt
from palmerpenguins import load_penguins
penguins = load_penguins()
fig, ax = plt.subplots(figsize=(15,10))
plt.scatter(x=penguins["body_mass_g"], y=penguins["bill_length_mm"])
plt.title("Penguin Body Mass (g) versus Bill Length (mm)")
ax.set_xlabel("Body Mass (g)")
ax.set_ylabel("Bill Length (mm)")
st.subheader("use_container_width=False")
st.pyplot(fig)
st.subheader("use_container_width=True")
st.pyplot(fig, use_container_width=True)
```