axiom-coding-agent-setup 1.0.10 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/agent-browser/SKILL.md +55 -0
- package/.agents/skills/developing-with-streamlit/SKILL.md +220 -0
- package/.agents/skills/developing-with-streamlit/skills/building-streamlit-chat-ui/SKILL.md +195 -0
- package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/SKILL.md +233 -0
- package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/packaged-components.md +212 -0
- package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/state-sync.md +149 -0
- package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/theme-css-variables.md +243 -0
- package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/troubleshooting.md +121 -0
- package/.agents/skills/developing-with-streamlit/skills/building-streamlit-dashboards/SKILL.md +147 -0
- package/.agents/skills/developing-with-streamlit/skills/building-streamlit-multipage-apps/SKILL.md +218 -0
- package/.agents/skills/developing-with-streamlit/skills/choosing-streamlit-selection-widgets/SKILL.md +139 -0
- package/.agents/skills/developing-with-streamlit/skills/connecting-streamlit-to-snowflake/SKILL.md +188 -0
- package/.agents/skills/developing-with-streamlit/skills/creating-streamlit-themes/SKILL.md +486 -0
- package/.agents/skills/developing-with-streamlit/skills/displaying-streamlit-data/SKILL.md +199 -0
- package/.agents/skills/developing-with-streamlit/skills/improving-streamlit-design/SKILL.md +191 -0
- package/.agents/skills/developing-with-streamlit/skills/optimizing-streamlit-performance/SKILL.md +323 -0
- package/.agents/skills/developing-with-streamlit/skills/organizing-streamlit-code/SKILL.md +91 -0
- package/.agents/skills/developing-with-streamlit/skills/setting-up-streamlit-environment/SKILL.md +128 -0
- package/.agents/skills/developing-with-streamlit/skills/using-streamlit-cli/SKILL.md +165 -0
- package/.agents/skills/developing-with-streamlit/skills/using-streamlit-custom-components/SKILL.md +170 -0
- package/.agents/skills/developing-with-streamlit/skills/using-streamlit-layouts/SKILL.md +229 -0
- package/.agents/skills/developing-with-streamlit/skills/using-streamlit-markdown/SKILL.md +207 -0
- package/.agents/skills/developing-with-streamlit/skills/using-streamlit-session-state/SKILL.md +144 -0
- package/.agents/skills/developing-with-streamlit/templates/.gitattributes +3 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/README.md +188 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-companies/pyproject.toml +12 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-companies/streamlit_app.py +365 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute/pyproject.toml +12 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute/streamlit_app.py +461 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/.streamlit/secrets.toml.example +20 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/pyproject.toml +11 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/snowflake.yml +18 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/streamlit_app.py +527 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-feature-usage/pyproject.toml +12 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-feature-usage/streamlit_app.py +307 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics/pyproject.toml +12 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics/streamlit_app.py +426 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/.streamlit/secrets.toml.example +20 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/pyproject.toml +11 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/snowflake.yml +18 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/streamlit_app.py +463 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-seattle-weather/pyproject.toml +12 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-seattle-weather/streamlit_app.py +252 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers/pyproject.toml +12 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers/streamlit_app.py +342 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/.streamlit/secrets.toml.example +20 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/pyproject.toml +11 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/snowflake.yml +18 -0
- package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/streamlit_app.py +384 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/README.md +128 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_configs/dracula.toml +39 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_configs/github.toml +37 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_configs/minimal.toml +39 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_configs/nord.toml +39 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_configs/snowflake.toml +42 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_configs/solarized-light.toml +38 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_configs/spotify.toml +34 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_configs/stripe.toml +35 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_shared/streamlit_app.py +336 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/_templates/pyproject.toml.tmpl +12 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/dracula/.streamlit/config.toml +39 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/dracula/pyproject.toml +10 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/dracula/streamlit_app.py +337 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/github/.streamlit/config.toml +37 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/github/pyproject.toml +10 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/github/streamlit_app.py +337 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/manage.py +332 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/minimal/.streamlit/config.toml +39 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/minimal/pyproject.toml +10 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/minimal/streamlit_app.py +337 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/nord/.streamlit/config.toml +39 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/nord/pyproject.toml +10 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/nord/streamlit_app.py +337 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/.streamlit/config.toml +42 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/pyproject.toml +10 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/streamlit_app.py +337 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/.streamlit/config.toml +38 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/pyproject.toml +10 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/streamlit_app.py +337 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/spotify/.streamlit/config.toml +34 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/spotify/pyproject.toml +10 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/spotify/streamlit_app.py +337 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/stripe/.streamlit/config.toml +35 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/stripe/pyproject.toml +10 -0
- package/.agents/skills/developing-with-streamlit/templates/themes/stripe/streamlit_app.py +337 -0
- package/.agents/skills/fastapi/SKILL.md +436 -0
- package/.agents/skills/fastapi/references/dependencies.md +142 -0
- package/.agents/skills/fastapi/references/other-tools.md +76 -0
- package/.agents/skills/fastapi/references/streaming.md +105 -0
- package/.agents/skills/frontend-design/LICENSE.txt +177 -0
- package/.agents/skills/frontend-design/SKILL.md +42 -0
- package/.agents/skills/gradio/SKILL.md +84 -0
- package/.agents/skills/gradio/references/api-signatures.md +115 -0
- package/.agents/skills/gradio/references/event-listeners.md +130 -0
- package/.agents/skills/gradio/references/examples.md +613 -0
- package/.agents/skills/project-design/SKILL.md +207 -0
- package/.agents/skills/project-design/references/ARCHITECTURE.md +641 -0
- package/.agents/skills/project-design/references/PROJECT_PLAN.md +316 -0
- package/.agents/skills/skill-creator/LICENSE.txt +202 -0
- package/.agents/skills/skill-creator/SKILL.md +485 -0
- package/.agents/skills/skill-creator/agents/analyzer.md +274 -0
- package/.agents/skills/skill-creator/agents/comparator.md +202 -0
- package/.agents/skills/skill-creator/agents/grader.md +223 -0
- package/.agents/skills/skill-creator/assets/eval_review.html +146 -0
- package/.agents/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.agents/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.agents/skills/skill-creator/references/schemas.md +430 -0
- package/.agents/skills/skill-creator/scripts/__init__.py +0 -0
- package/.agents/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.agents/skills/skill-creator/scripts/generate_report.py +326 -0
- package/.agents/skills/skill-creator/scripts/improve_description.py +247 -0
- package/.agents/skills/skill-creator/scripts/package_skill.py +136 -0
- package/.agents/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/.agents/skills/skill-creator/scripts/run_eval.py +310 -0
- package/.agents/skills/skill-creator/scripts/run_loop.py +328 -0
- package/.agents/skills/skill-creator/scripts/utils.py +47 -0
- package/.agents/skills/ui-ux-pro-max/SKILL.md +659 -0
- package/.agents/skills/ui-ux-pro-max/data +1 -0
- package/.agents/skills/ui-ux-pro-max/scripts +1 -0
- package/.env.axiom +8 -0
- package/AGENTS.md +2 -1
- package/README.md +20 -3
- package/bin/cli.js +12 -1
- package/opencode.json +7 -4
- package/package.json +1 -1
- package/plugin/oh-my-openagent.json +198 -0
- package/plugin/oh-my-openagent.md +49 -0
- package/skills-lock.json +42 -0
- package/.agents/skills/n8n-patterns/SKILL.md +0 -272
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import streamlit as st
|
|
2
|
+
import altair as alt
|
|
3
|
+
import vega_datasets
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
full_df = vega_datasets.data("seattle_weather")
|
|
7
|
+
|
|
8
|
+
st.set_page_config(
|
|
9
|
+
# Title and icon for the browser's tab bar:
|
|
10
|
+
page_title="Seattle Weather",
|
|
11
|
+
page_icon=":mostly_sunny:",
|
|
12
|
+
# Make the content take up the width of the page:
|
|
13
|
+
layout="wide",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
# Seattle Weather
|
|
19
|
+
|
|
20
|
+
Let's explore the [classic Seattle Weather
|
|
21
|
+
dataset](https://altair-viz.github.io/case_studies/exploring-weather.html)!
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
"" # Add a little vertical space. Same as st.write("").
|
|
25
|
+
""
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
## 2015 Summary
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
""
|
|
32
|
+
|
|
33
|
+
df_2015 = full_df[full_df["date"].dt.year == 2015]
|
|
34
|
+
df_2014 = full_df[full_df["date"].dt.year == 2014]
|
|
35
|
+
|
|
36
|
+
max_temp_2015 = df_2015["temp_max"].max()
|
|
37
|
+
max_temp_2014 = df_2014["temp_max"].max()
|
|
38
|
+
|
|
39
|
+
min_temp_2015 = df_2015["temp_min"].min()
|
|
40
|
+
min_temp_2014 = df_2014["temp_min"].min()
|
|
41
|
+
|
|
42
|
+
max_wind_2015 = df_2015["wind"].max()
|
|
43
|
+
max_wind_2014 = df_2014["wind"].max()
|
|
44
|
+
|
|
45
|
+
min_wind_2015 = df_2015["wind"].min()
|
|
46
|
+
min_wind_2014 = df_2014["wind"].min()
|
|
47
|
+
|
|
48
|
+
max_prec_2015 = df_2015["precipitation"].max()
|
|
49
|
+
max_prec_2014 = df_2014["precipitation"].max()
|
|
50
|
+
|
|
51
|
+
min_prec_2015 = df_2015["precipitation"].min()
|
|
52
|
+
min_prec_2014 = df_2014["precipitation"].min()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
with st.container(horizontal=True, gap="medium"):
|
|
56
|
+
cols = st.columns(2, gap="medium", width=300)
|
|
57
|
+
|
|
58
|
+
with cols[0]:
|
|
59
|
+
st.metric(
|
|
60
|
+
"Max temperature",
|
|
61
|
+
f"{max_temp_2015:0.1f}C",
|
|
62
|
+
delta=f"{max_temp_2015 - max_temp_2014:0.1f}C",
|
|
63
|
+
width="content",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
with cols[1]:
|
|
67
|
+
st.metric(
|
|
68
|
+
"Min temperature",
|
|
69
|
+
f"{min_temp_2015:0.1f}C",
|
|
70
|
+
delta=f"{min_temp_2015 - min_temp_2014:0.1f}C",
|
|
71
|
+
width="content",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
cols = st.columns(2, gap="medium", width=300)
|
|
75
|
+
|
|
76
|
+
with cols[0]:
|
|
77
|
+
st.metric(
|
|
78
|
+
"Max precipitation",
|
|
79
|
+
f"{max_prec_2015:0.1f}mm",
|
|
80
|
+
delta=f"{max_prec_2015 - max_prec_2014:0.1f}mm",
|
|
81
|
+
width="content",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
with cols[1]:
|
|
85
|
+
st.metric(
|
|
86
|
+
"Min precipitation",
|
|
87
|
+
f"{min_prec_2015:0.1f}mm",
|
|
88
|
+
delta=f"{min_prec_2015 - min_prec_2014:0.1f}mm",
|
|
89
|
+
width="content",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
cols = st.columns(2, gap="medium", width=300)
|
|
93
|
+
|
|
94
|
+
with cols[0]:
|
|
95
|
+
st.metric(
|
|
96
|
+
"Max wind",
|
|
97
|
+
f"{max_wind_2015:0.1f}m/s",
|
|
98
|
+
delta=f"{max_wind_2015 - max_wind_2014:0.1f}m/s",
|
|
99
|
+
width="content",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
with cols[1]:
|
|
103
|
+
st.metric(
|
|
104
|
+
"Min wind",
|
|
105
|
+
f"{min_wind_2015:0.1f}m/s",
|
|
106
|
+
delta=f"{min_wind_2015 - min_wind_2014:0.1f}m/s",
|
|
107
|
+
width="content",
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
weather_icons = {
|
|
111
|
+
"sun": "sunny",
|
|
112
|
+
"snow": "weather_snowy",
|
|
113
|
+
"rain": "rainy",
|
|
114
|
+
"fog": "foggy",
|
|
115
|
+
"drizzle": "rainy",
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
cols = st.columns(2, gap="large")
|
|
119
|
+
|
|
120
|
+
with cols[0]:
|
|
121
|
+
weather_name = (
|
|
122
|
+
full_df["weather"].value_counts().head(1).reset_index()["weather"][0]
|
|
123
|
+
)
|
|
124
|
+
st.metric(
|
|
125
|
+
"Most common weather",
|
|
126
|
+
f":material/{weather_icons[weather_name]}: {weather_name.upper()}",
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
with cols[1]:
|
|
130
|
+
weather_name = (
|
|
131
|
+
full_df["weather"].value_counts().tail(1).reset_index()["weather"][0]
|
|
132
|
+
)
|
|
133
|
+
st.metric(
|
|
134
|
+
"Least common weather",
|
|
135
|
+
f":material/{weather_icons[weather_name]}: {weather_name.upper()}",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
""
|
|
139
|
+
""
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
## Compare different years
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
YEARS = full_df["date"].dt.year.unique()
|
|
146
|
+
selected_years = st.pills(
|
|
147
|
+
"Years to compare", YEARS, default=YEARS, selection_mode="multi"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if not selected_years:
|
|
151
|
+
st.warning("You must select at least 1 year.", icon=":material/warning:")
|
|
152
|
+
|
|
153
|
+
df = full_df[full_df["date"].dt.year.isin(selected_years)]
|
|
154
|
+
|
|
155
|
+
cols = st.columns([3, 1])
|
|
156
|
+
|
|
157
|
+
with cols[0].container(border=True, height="stretch"):
|
|
158
|
+
"### 🌡️ Temperature"
|
|
159
|
+
|
|
160
|
+
st.altair_chart(
|
|
161
|
+
alt.Chart(df)
|
|
162
|
+
.mark_bar(width=1)
|
|
163
|
+
.encode(
|
|
164
|
+
alt.X("monthdate(date):T").title("date"),
|
|
165
|
+
alt.Y("temp_max:Q").title("temperature range (C)"),
|
|
166
|
+
alt.Y2("temp_min:Q"),
|
|
167
|
+
alt.Color("year(date):N").title("year"),
|
|
168
|
+
alt.XOffset("year(date):N"),
|
|
169
|
+
tooltip=[
|
|
170
|
+
alt.Tooltip("monthdate(date):T", title="Date"),
|
|
171
|
+
alt.Tooltip("temp_max:Q", title="Max Temp (C)"),
|
|
172
|
+
alt.Tooltip("temp_min:Q", title="Min Temp (C)"),
|
|
173
|
+
alt.Tooltip("year(date):N", title="Year"),
|
|
174
|
+
],
|
|
175
|
+
)
|
|
176
|
+
.configure_legend(orient="bottom")
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
with cols[1].container(border=True, height="stretch"):
|
|
180
|
+
"### Weather distribution"
|
|
181
|
+
|
|
182
|
+
st.altair_chart(
|
|
183
|
+
alt.Chart(df)
|
|
184
|
+
.mark_arc()
|
|
185
|
+
.encode(
|
|
186
|
+
alt.Theta("count()"),
|
|
187
|
+
alt.Color("weather:N"),
|
|
188
|
+
)
|
|
189
|
+
.configure_legend(orient="bottom")
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
cols = st.columns(2)
|
|
194
|
+
|
|
195
|
+
with cols[0].container(border=True, height="stretch"):
|
|
196
|
+
"### 💨 Wind"
|
|
197
|
+
|
|
198
|
+
# Prepare data for st.line_chart - pivot by year
|
|
199
|
+
wind_df = df.copy()
|
|
200
|
+
wind_df["month_day"] = wind_df["date"].dt.strftime("%m-%d")
|
|
201
|
+
wind_df["year"] = wind_df["date"].dt.year
|
|
202
|
+
|
|
203
|
+
# Calculate 14-day rolling average per year
|
|
204
|
+
wind_pivot = wind_df.pivot_table(
|
|
205
|
+
index="month_day",
|
|
206
|
+
columns="year",
|
|
207
|
+
values="wind",
|
|
208
|
+
aggfunc="mean"
|
|
209
|
+
).sort_index()
|
|
210
|
+
|
|
211
|
+
st.line_chart(wind_pivot, height=300)
|
|
212
|
+
|
|
213
|
+
with cols[1].container(border=True, height="stretch"):
|
|
214
|
+
"### 🌧️ Precipitation"
|
|
215
|
+
|
|
216
|
+
st.altair_chart(
|
|
217
|
+
alt.Chart(df)
|
|
218
|
+
.mark_bar()
|
|
219
|
+
.encode(
|
|
220
|
+
alt.X("month(date):O").title("month"),
|
|
221
|
+
alt.Y("sum(precipitation):Q").title("precipitation (mm)"),
|
|
222
|
+
alt.Color("year(date):N").title("year"),
|
|
223
|
+
tooltip=[
|
|
224
|
+
alt.Tooltip("month(date):O", title="Month"),
|
|
225
|
+
alt.Tooltip("sum(precipitation):Q", title="Precipitation (mm)"),
|
|
226
|
+
alt.Tooltip("year(date):N", title="Year"),
|
|
227
|
+
],
|
|
228
|
+
)
|
|
229
|
+
.configure_legend(orient="bottom")
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
cols = st.columns(2)
|
|
233
|
+
|
|
234
|
+
with cols[0].container(border=True, height="stretch"):
|
|
235
|
+
"### Monthly weather breakdown"
|
|
236
|
+
""
|
|
237
|
+
|
|
238
|
+
st.altair_chart(
|
|
239
|
+
alt.Chart(df)
|
|
240
|
+
.mark_bar()
|
|
241
|
+
.encode(
|
|
242
|
+
alt.X("month(date):O", title="month"),
|
|
243
|
+
alt.Y("count():Q", title="days").stack("normalize"),
|
|
244
|
+
alt.Color("weather:N"),
|
|
245
|
+
)
|
|
246
|
+
.configure_legend(orient="bottom")
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
with cols[1].container(border=True, height="stretch"):
|
|
250
|
+
"### Raw data"
|
|
251
|
+
|
|
252
|
+
st.dataframe(df)
|
package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers/pyproject.toml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "dashboard-stock-peers"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Stock peer analysis dashboard: easily compare stocks against others in their peer group"
|
|
5
|
+
requires-python = ">=3.11"
|
|
6
|
+
dependencies = [
|
|
7
|
+
"altair>=5.5.0",
|
|
8
|
+
"pandas>=2.2.3",
|
|
9
|
+
"snowflake-connector-python>=3.3.0",
|
|
10
|
+
"streamlit[snowflake]>=1.54.0",
|
|
11
|
+
"yfinance>=0.2.55",
|
|
12
|
+
]
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import streamlit as st
|
|
2
|
+
import yfinance as yf
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import altair as alt
|
|
5
|
+
|
|
6
|
+
st.set_page_config(
|
|
7
|
+
page_title="Stock peer analysis dashboard",
|
|
8
|
+
page_icon=":chart_with_upwards_trend:",
|
|
9
|
+
layout="wide",
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
# :material/query_stats: Stock peer analysis
|
|
14
|
+
|
|
15
|
+
Easily compare stocks against others in their peer group.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
"" # Add some space.
|
|
19
|
+
|
|
20
|
+
cols = st.columns([1, 3])
|
|
21
|
+
# Will declare right cell later to avoid showing it when no data.
|
|
22
|
+
|
|
23
|
+
STOCKS = [
|
|
24
|
+
"AAPL",
|
|
25
|
+
"ABBV",
|
|
26
|
+
"ACN",
|
|
27
|
+
"ADBE",
|
|
28
|
+
"ADP",
|
|
29
|
+
"AMD",
|
|
30
|
+
"AMGN",
|
|
31
|
+
"AMT",
|
|
32
|
+
"AMZN",
|
|
33
|
+
"APD",
|
|
34
|
+
"AVGO",
|
|
35
|
+
"AXP",
|
|
36
|
+
"BA",
|
|
37
|
+
"BK",
|
|
38
|
+
"BKNG",
|
|
39
|
+
"BMY",
|
|
40
|
+
"BRK.B",
|
|
41
|
+
"BSX",
|
|
42
|
+
"C",
|
|
43
|
+
"CAT",
|
|
44
|
+
"CI",
|
|
45
|
+
"CL",
|
|
46
|
+
"CMCSA",
|
|
47
|
+
"COST",
|
|
48
|
+
"CRM",
|
|
49
|
+
"CSCO",
|
|
50
|
+
"CVX",
|
|
51
|
+
"DE",
|
|
52
|
+
"DHR",
|
|
53
|
+
"DIS",
|
|
54
|
+
"DUK",
|
|
55
|
+
"ELV",
|
|
56
|
+
"EOG",
|
|
57
|
+
"EQR",
|
|
58
|
+
"FDX",
|
|
59
|
+
"GD",
|
|
60
|
+
"GE",
|
|
61
|
+
"GILD",
|
|
62
|
+
"GOOG",
|
|
63
|
+
"GOOGL",
|
|
64
|
+
"HD",
|
|
65
|
+
"HON",
|
|
66
|
+
"HUM",
|
|
67
|
+
"IBM",
|
|
68
|
+
"ICE",
|
|
69
|
+
"INTC",
|
|
70
|
+
"ISRG",
|
|
71
|
+
"JNJ",
|
|
72
|
+
"JPM",
|
|
73
|
+
"KO",
|
|
74
|
+
"LIN",
|
|
75
|
+
"LLY",
|
|
76
|
+
"LMT",
|
|
77
|
+
"LOW",
|
|
78
|
+
"MA",
|
|
79
|
+
"MCD",
|
|
80
|
+
"MDLZ",
|
|
81
|
+
"META",
|
|
82
|
+
"MMC",
|
|
83
|
+
"MO",
|
|
84
|
+
"MRK",
|
|
85
|
+
"MSFT",
|
|
86
|
+
"NEE",
|
|
87
|
+
"NFLX",
|
|
88
|
+
"NKE",
|
|
89
|
+
"NOW",
|
|
90
|
+
"NVDA",
|
|
91
|
+
"ORCL",
|
|
92
|
+
"PEP",
|
|
93
|
+
"PFE",
|
|
94
|
+
"PG",
|
|
95
|
+
"PLD",
|
|
96
|
+
"PM",
|
|
97
|
+
"PSA",
|
|
98
|
+
"REGN",
|
|
99
|
+
"RTX",
|
|
100
|
+
"SBUX",
|
|
101
|
+
"SCHW",
|
|
102
|
+
"SLB",
|
|
103
|
+
"SO",
|
|
104
|
+
"SPGI",
|
|
105
|
+
"T",
|
|
106
|
+
"TJX",
|
|
107
|
+
"TMO",
|
|
108
|
+
"TSLA",
|
|
109
|
+
"TXN",
|
|
110
|
+
"UNH",
|
|
111
|
+
"UNP",
|
|
112
|
+
"UPS",
|
|
113
|
+
"V",
|
|
114
|
+
"VZ",
|
|
115
|
+
"WFC",
|
|
116
|
+
"WM",
|
|
117
|
+
"WMT",
|
|
118
|
+
"XOM",
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
DEFAULT_STOCKS = ["AAPL", "MSFT", "GOOGL", "NVDA", "AMZN", "TSLA", "META"]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def stocks_to_str(stocks):
|
|
125
|
+
return ",".join(stocks)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
if "tickers_input" not in st.session_state:
|
|
129
|
+
st.session_state.tickers_input = st.query_params.get(
|
|
130
|
+
"stocks", stocks_to_str(DEFAULT_STOCKS)
|
|
131
|
+
).split(",")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# Callback to update query param when input changes
|
|
135
|
+
def update_query_param():
|
|
136
|
+
if st.session_state.tickers_input:
|
|
137
|
+
st.query_params["stocks"] = stocks_to_str(st.session_state.tickers_input)
|
|
138
|
+
else:
|
|
139
|
+
st.query_params.pop("stocks", None)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
top_left_cell = cols[0].container(
|
|
143
|
+
border=True, height="stretch", vertical_alignment="center"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
with top_left_cell:
|
|
147
|
+
# Selectbox for stock tickers
|
|
148
|
+
tickers = st.multiselect(
|
|
149
|
+
"Stock tickers",
|
|
150
|
+
options=sorted(set(STOCKS) | set(st.session_state.tickers_input)),
|
|
151
|
+
default=st.session_state.tickers_input,
|
|
152
|
+
placeholder="Choose stocks to compare. Example: NVDA",
|
|
153
|
+
accept_new_options=True,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Time horizon selector
|
|
157
|
+
horizon_map = {
|
|
158
|
+
"1 Month": "1mo",
|
|
159
|
+
"3 Months": "3mo",
|
|
160
|
+
"6 Months": "6mo",
|
|
161
|
+
"1 Year": "1y",
|
|
162
|
+
"5 Years": "5y",
|
|
163
|
+
"10 Years": "10y",
|
|
164
|
+
"20 Years": "20y",
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
with top_left_cell:
|
|
168
|
+
# Buttons for picking time horizon
|
|
169
|
+
horizon = st.pills(
|
|
170
|
+
"Time horizon",
|
|
171
|
+
options=list(horizon_map.keys()),
|
|
172
|
+
default="6 Months",
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
tickers = [t.upper() for t in tickers]
|
|
176
|
+
|
|
177
|
+
# Update query param when text input changes
|
|
178
|
+
if tickers:
|
|
179
|
+
st.query_params["stocks"] = stocks_to_str(tickers)
|
|
180
|
+
else:
|
|
181
|
+
# Clear the param if input is empty
|
|
182
|
+
st.query_params.pop("stocks", None)
|
|
183
|
+
|
|
184
|
+
if not tickers:
|
|
185
|
+
top_left_cell.info("Pick some stocks to compare", icon=":material/info:")
|
|
186
|
+
st.stop()
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
right_cell = cols[1].container(
|
|
190
|
+
border=True, height="stretch", vertical_alignment="center"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@st.cache_resource(show_spinner=False, ttl="6h")
|
|
195
|
+
def load_data(tickers, period):
|
|
196
|
+
tickers_obj = yf.Tickers(tickers)
|
|
197
|
+
data = tickers_obj.history(period=period)
|
|
198
|
+
if data is None:
|
|
199
|
+
raise RuntimeError("YFinance returned no data.")
|
|
200
|
+
return data["Close"]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
# Load the data
|
|
204
|
+
try:
|
|
205
|
+
data = load_data(tickers, horizon_map[horizon])
|
|
206
|
+
except yf.exceptions.YFRateLimitError as e:
|
|
207
|
+
st.warning("YFinance is rate-limiting us :(\nTry again later.")
|
|
208
|
+
load_data.clear() # Remove the bad cache entry.
|
|
209
|
+
st.stop()
|
|
210
|
+
|
|
211
|
+
empty_columns = data.columns[data.isna().all()].tolist()
|
|
212
|
+
|
|
213
|
+
if empty_columns:
|
|
214
|
+
st.error(f"Error loading data for the tickers: {', '.join(empty_columns)}.")
|
|
215
|
+
st.stop()
|
|
216
|
+
|
|
217
|
+
# Normalize prices (start at 1)
|
|
218
|
+
normalized = data.div(data.iloc[0])
|
|
219
|
+
|
|
220
|
+
latest_norm_values = {normalized[ticker].iat[-1]: ticker for ticker in tickers}
|
|
221
|
+
max_norm_value = max(latest_norm_values.items())
|
|
222
|
+
min_norm_value = min(latest_norm_values.items())
|
|
223
|
+
|
|
224
|
+
bottom_left_cell = cols[0].container(
|
|
225
|
+
border=True, height="stretch", vertical_alignment="center"
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
with bottom_left_cell:
|
|
229
|
+
cols = st.columns(2)
|
|
230
|
+
cols[0].metric(
|
|
231
|
+
"Best stock",
|
|
232
|
+
max_norm_value[1],
|
|
233
|
+
delta=f"{round(max_norm_value[0] * 100)}%",
|
|
234
|
+
width="content",
|
|
235
|
+
)
|
|
236
|
+
cols[1].metric(
|
|
237
|
+
"Worst stock",
|
|
238
|
+
min_norm_value[1],
|
|
239
|
+
delta=f"{round(min_norm_value[0] * 100)}%",
|
|
240
|
+
width="content",
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
# Plot normalized prices
|
|
245
|
+
with right_cell:
|
|
246
|
+
st.altair_chart(
|
|
247
|
+
alt.Chart(
|
|
248
|
+
normalized.reset_index().melt(
|
|
249
|
+
id_vars=["Date"], var_name="Stock", value_name="Normalized price"
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
.mark_line()
|
|
253
|
+
.encode(
|
|
254
|
+
alt.X("Date:T"),
|
|
255
|
+
alt.Y("Normalized price:Q").scale(zero=False),
|
|
256
|
+
alt.Color("Stock:N"),
|
|
257
|
+
)
|
|
258
|
+
.properties(height=400)
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
""
|
|
262
|
+
""
|
|
263
|
+
|
|
264
|
+
# Plot individual stock vs peer average
|
|
265
|
+
"""
|
|
266
|
+
## Individual stocks vs peer average
|
|
267
|
+
|
|
268
|
+
For the analysis below, the "peer average" when analyzing stock X always
|
|
269
|
+
excludes X itself.
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
if len(tickers) <= 1:
|
|
273
|
+
st.warning("Pick 2 or more tickers to compare them")
|
|
274
|
+
st.stop()
|
|
275
|
+
|
|
276
|
+
NUM_COLS = 4
|
|
277
|
+
cols = st.columns(NUM_COLS)
|
|
278
|
+
|
|
279
|
+
for i, ticker in enumerate(tickers):
|
|
280
|
+
# Calculate peer average (excluding current stock)
|
|
281
|
+
peers = normalized.drop(columns=[ticker])
|
|
282
|
+
peer_avg = peers.mean(axis=1)
|
|
283
|
+
|
|
284
|
+
# Create DataFrame with peer average.
|
|
285
|
+
plot_data = pd.DataFrame(
|
|
286
|
+
{
|
|
287
|
+
"Date": normalized.index,
|
|
288
|
+
ticker: normalized[ticker],
|
|
289
|
+
"Peer average": peer_avg,
|
|
290
|
+
}
|
|
291
|
+
).melt(id_vars=["Date"], var_name="Series", value_name="Price")
|
|
292
|
+
|
|
293
|
+
chart = (
|
|
294
|
+
alt.Chart(plot_data)
|
|
295
|
+
.mark_line()
|
|
296
|
+
.encode(
|
|
297
|
+
alt.X("Date:T"),
|
|
298
|
+
alt.Y("Price:Q").scale(zero=False),
|
|
299
|
+
alt.Color(
|
|
300
|
+
"Series:N",
|
|
301
|
+
scale=alt.Scale(domain=[ticker, "Peer average"], range=["red", "gray"]),
|
|
302
|
+
legend=alt.Legend(orient="bottom"),
|
|
303
|
+
),
|
|
304
|
+
alt.Tooltip(["Date", "Series", "Price"]),
|
|
305
|
+
)
|
|
306
|
+
.properties(title=f"{ticker} vs peer average", height=300)
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
cell = cols[(i * 2) % NUM_COLS].container(border=True)
|
|
310
|
+
cell.write("")
|
|
311
|
+
cell.altair_chart(chart)
|
|
312
|
+
|
|
313
|
+
# Create Delta chart
|
|
314
|
+
plot_data = pd.DataFrame(
|
|
315
|
+
{
|
|
316
|
+
"Date": normalized.index,
|
|
317
|
+
"Delta": normalized[ticker] - peer_avg,
|
|
318
|
+
}
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
chart = (
|
|
322
|
+
alt.Chart(plot_data)
|
|
323
|
+
.mark_area()
|
|
324
|
+
.encode(
|
|
325
|
+
alt.X("Date:T"),
|
|
326
|
+
alt.Y("Delta:Q").scale(zero=False),
|
|
327
|
+
)
|
|
328
|
+
.properties(title=f"{ticker} minus peer average", height=300)
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
cell = cols[(i * 2 + 1) % NUM_COLS].container(border=True)
|
|
332
|
+
cell.write("")
|
|
333
|
+
cell.altair_chart(chart)
|
|
334
|
+
|
|
335
|
+
""
|
|
336
|
+
""
|
|
337
|
+
|
|
338
|
+
"""
|
|
339
|
+
## Raw data
|
|
340
|
+
"""
|
|
341
|
+
|
|
342
|
+
data
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Copy this file to secrets.toml and fill in your credentials
|
|
2
|
+
# NEVER commit secrets.toml to version control — it contains sensitive
|
|
3
|
+
# credentials that would be exposed in your repository.
|
|
4
|
+
#
|
|
5
|
+
# To find your account and host values, run:
|
|
6
|
+
# snow connection list
|
|
7
|
+
# Look for the "account" and "host" fields in your connection config.
|
|
8
|
+
|
|
9
|
+
[connections.snowflake]
|
|
10
|
+
account = "<YOUR_ACCOUNT>" # e.g., "ORGNAME-ACCTNAME" from `snow connection list`
|
|
11
|
+
host = "<YOUR_HOST>" # e.g., "myaccount.snowflakecomputing.com" (required for private link / internal accounts)
|
|
12
|
+
user = "<YOUR_USER>"
|
|
13
|
+
authenticator = "externalbrowser" # Opens browser for SSO login
|
|
14
|
+
warehouse = "<YOUR_WAREHOUSE>"
|
|
15
|
+
database = "<YOUR_DATABASE>"
|
|
16
|
+
schema = "<YOUR_SCHEMA>"
|
|
17
|
+
|
|
18
|
+
# Alternative: use password instead of SSO (less secure)
|
|
19
|
+
# password = "<YOUR_PASSWORD>"
|
|
20
|
+
# Remove the authenticator line above if using password
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "dashboard-stock-peers-snowflake"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Stock peer analysis dashboard with Snowflake connection"
|
|
5
|
+
requires-python = ">=3.11"
|
|
6
|
+
dependencies = [
|
|
7
|
+
"altair>=5.5.0",
|
|
8
|
+
"pandas>=2.2.3",
|
|
9
|
+
"snowflake-connector-python>=3.3.0",
|
|
10
|
+
"streamlit[snowflake]>=1.54.0",
|
|
11
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
definition_version: 2
|
|
2
|
+
entities:
|
|
3
|
+
DASHBOARD_STOCK_PEERS_SNOWFLAKE:
|
|
4
|
+
type: streamlit
|
|
5
|
+
identifier:
|
|
6
|
+
name: DASHBOARD_STOCK_PEERS_SNOWFLAKE
|
|
7
|
+
database: <FROM_CONNECTION> # Use: snow connection list
|
|
8
|
+
schema: <FROM_CONNECTION>
|
|
9
|
+
query_warehouse: <FROM_CONNECTION>
|
|
10
|
+
runtime_name: SYSTEM$ST_CONTAINER_RUNTIME_PY3_11
|
|
11
|
+
# List available: SHOW EXTERNAL ACCESS INTEGRATIONS;
|
|
12
|
+
# Common: PYPI_ACCESS_INTEGRATION (verify exists)
|
|
13
|
+
external_access_integrations:
|
|
14
|
+
- <YOUR_PYPI_INTEGRATION>
|
|
15
|
+
main_file: streamlit_app.py
|
|
16
|
+
artifacts:
|
|
17
|
+
- streamlit_app.py
|
|
18
|
+
- pyproject.toml
|