Skip to content

Commit 296f766

Browse files
update for lecture 9
1 parent f4239d2 commit 296f766

File tree

8 files changed

+375
-37
lines changed

8 files changed

+375
-37
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
/_freeze/
66
_quarto_internal_scss_error.scss
77
.DS_Store
8-
*/.DS_Store
8+
*/.DS_Store
9+
.web/

assignments/assignment-2.qmd

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ In this excercise, you will create a program that is able to redact secret infor
3232
```{python}
3333
# Secret information redactor
3434
# TODO: Create a program that is able to redact secret information in a text.
35-
# Your code here
35+
# YOUR CODE HERE
3636
```
3737

3838
# Dice roll simulator
@@ -41,10 +41,17 @@ In this excercise, you will create a program that is able to simulate dice rolls
4141
```{python}
4242
# Dice roll simulator
4343
# TODO: Create a program that is able to simulate a dice roll.
44-
# Your code here
44+
# YOUR CODE HERE
4545
```
4646

4747
# Regression analysis
48+
49+
:::{.callout-note}
50+
51+
You will either have to to this excercise or the next one about dashboards.
52+
53+
:::
54+
4855
In this excercise, you will create a program that performs linear regression on a dataset with housing prices. The dataset can be found in the git repository under `assignments/hamburg_housing_prices.csv`. The dataset contains the following columns:
4956

5057
- Price: The price of the house in Euros.
@@ -58,5 +65,27 @@ Your task is to perform a **linear regression analysis** on the dataset and to p
5865
```{python}
5966
# Regression analysis
6067
# TODO: Create a program that performs linear regression analysis on the dataset.
61-
# Your code here
68+
# YOUR CODE HERE
69+
```
70+
71+
# Dashboards
72+
73+
:::{.callout-note}
74+
75+
You will either have to to this excercise or the previous one about regression analysis.
76+
77+
:::
78+
79+
In this exercise, you will create a program that visualizes a data set of your choice in a dashboard. For this excercise, you can choose any data set of your interest. The data should be visualized in a dashboard with at least two plots. You can use one of the dashboard libraries we discussed in the lecture.
80+
81+
:::{.callout-note}
82+
83+
The dashboard should be programmed in a separate file I can call for evaluation.
84+
85+
:::
86+
87+
```{python}
88+
# Dashboards
89+
# TODO: Create a program that visualizes a data set of your choice in a dashboard.
90+
# YOUR CODE HERE
6291
```
File renamed without changes.

part-09/dashboards/stocks_panel.py

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import panel as pn
2+
import yfinance as yf
3+
from bokeh.plotting import figure
4+
from bokeh.models import HoverTool, CrosshairTool
5+
from datetime import datetime
6+
import pandas as pd
7+
8+
# Enable Panel extensions
9+
pn.extension(sizing_mode="stretch_width")
10+
11+
# Cache function for data loading
12+
@pn.cache(ttl=3600)
13+
def load_data(ticker_symbol):
14+
try:
15+
stock = yf.Ticker(ticker_symbol)
16+
df = stock.history(period="2y")
17+
if df.empty:
18+
raise ValueError("No data available for this ticker")
19+
return df, None
20+
except Exception as e:
21+
return None, str(e)
22+
23+
def create_candlestick_plot(df, ticker_symbol):
24+
# Create Bokeh figure
25+
p = figure(
26+
width=800,
27+
height=400,
28+
title=f'{ticker_symbol} Stock Price',
29+
x_axis_type='datetime',
30+
tools='pan,wheel_zoom,box_zoom,reset,save'
31+
)
32+
33+
# Add hover tool with formatters
34+
hover = HoverTool(
35+
tooltips=[
36+
('Date', '@x{%F}'),
37+
('Open', '$@{Open}{0,0.00}'),
38+
('High', '$@{High}{0,0.00}'),
39+
('Low', '$@{Low}{0,0.00}'),
40+
('Close', '$@{Close}{0,0.00}')
41+
],
42+
formatters={"@x": "datetime"}
43+
)
44+
45+
# Add tools
46+
p.add_tools(hover)
47+
p.add_tools(CrosshairTool())
48+
p.add_tools(CrosshairTool())
49+
50+
# Calculate candlestick colors
51+
inc = df.Close > df.Open
52+
dec = df.Open > df.Close
53+
54+
# Add candlestick chart
55+
p.segment(df.index, df.High, df.index, df.Low, color="black")
56+
p.vbar(
57+
x=df.index[inc],
58+
top=df.Open[inc],
59+
bottom=df.Close[inc],
60+
width=24*60*60*1000, # One day in milliseconds
61+
fill_color="green",
62+
line_color="green"
63+
)
64+
p.vbar(
65+
x=df.index[dec],
66+
top=df.Open[dec],
67+
bottom=df.Close[dec],
68+
width=24*60*60*1000,
69+
fill_color="red",
70+
line_color="red"
71+
)
72+
73+
return p
74+
75+
def create_volume_plot(df):
76+
# Create volume subplot
77+
v = figure(
78+
width=800,
79+
height=200,
80+
x_axis_type='datetime',
81+
title='Volume'
82+
)
83+
84+
v.vbar(
85+
x=df.index,
86+
top=df.Volume,
87+
width=24*60*60*1000,
88+
color='gray',
89+
alpha=0.5
90+
)
91+
92+
return v
93+
94+
# Create error text widget with visibility control
95+
error_text = pn.widgets.StaticText(name='Error', styles={'color': 'red'}, visible=False)
96+
97+
def update_plots(event):
98+
# Show loading indicator
99+
loading.visible = True
100+
error_text.visible = False # Hide error message at start
101+
error_text.value = ""
102+
103+
try:
104+
# Validate ticker symbol
105+
if not ticker.value or len(ticker.value) < 1:
106+
raise ValueError("Please enter a valid ticker symbol")
107+
108+
# Get data
109+
df, error = load_data(ticker.value)
110+
if error:
111+
raise ValueError(error)
112+
113+
days = int(timeframe.value[1])
114+
filtered_df = df.iloc[-days:]
115+
116+
# Update plots
117+
main_plot.object = create_candlestick_plot(filtered_df, ticker.value)
118+
volume_plot.object = create_volume_plot(filtered_df)
119+
120+
# Update metrics with better formatting using iloc
121+
latest_close = filtered_df['Close'].iloc[-1]
122+
prev_close = filtered_df['Close'].iloc[-2]
123+
daily_change_val = ((latest_close - prev_close) / prev_close * 100)
124+
125+
current_price.value = f"${latest_close:.2f}"
126+
daily_change.value = f"{daily_change_val:+.2f}%" # Added plus sign for positive values
127+
highest_price.value = f"${filtered_df['High'].max():.2f}"
128+
lowest_price.value = f"${filtered_df['Low'].min():.2f}"
129+
130+
# Style daily change based on value
131+
daily_change.styles = {'color': 'green' if daily_change_val > 0 else 'red'}
132+
133+
except Exception as e:
134+
error_text.value = str(e)
135+
error_text.visible = True # Only show when there's an error
136+
error_text.styles = {'color': 'red'}
137+
finally:
138+
loading.visible = False
139+
140+
# Create widgets
141+
ticker = pn.widgets.TextInput(
142+
name='Stock Ticker',
143+
value='REMEDY.HE',
144+
)
145+
timeframe = pn.widgets.Select(
146+
name='Timeframe',
147+
options=[
148+
('1 Month', 30),
149+
('3 Months', 90),
150+
('6 Months', 180),
151+
('1 Year', 365),
152+
('2 Years', 730)
153+
],
154+
value=('1 Month', 30)
155+
)
156+
157+
# Create additional widgets
158+
loading = pn.indicators.LoadingSpinner(value=True, size=25)
159+
160+
# Update metrics styling
161+
current_price = pn.widgets.StaticText(name='Current Price', styles={'font-weight': 'bold'})
162+
daily_change = pn.widgets.StaticText(name='Daily Change', styles={'font-weight': 'bold'})
163+
highest_price = pn.widgets.StaticText(name='Highest Price')
164+
lowest_price = pn.widgets.StaticText(name='Lowest Price')
165+
error_text = pn.widgets.StaticText(name='Error', styles={'color': 'red'})
166+
167+
# Update layout with loading indicator
168+
metrics = pn.Row(
169+
pn.Column(current_price, daily_change),
170+
pn.Column(highest_price, lowest_price),
171+
loading
172+
)
173+
174+
# Create plot panes (initially empty)
175+
main_plot = pn.pane.Bokeh()
176+
volume_plot = pn.pane.Bokeh()
177+
178+
# Watch for changes
179+
ticker.param.watch(update_plots, 'value')
180+
timeframe.param.watch(update_plots, 'value')
181+
182+
# Layout
183+
sidebar = pn.Column(
184+
pn.pane.Markdown('# Settings'),
185+
ticker,
186+
timeframe,
187+
width=300
188+
)
189+
190+
metrics = pn.Row(
191+
pn.Column(current_price, daily_change),
192+
pn.Column(highest_price),
193+
pn.Column(lowest_price)
194+
)
195+
196+
main_content = pn.Column(
197+
pn.pane.Markdown('# Stock Price Analysis'),
198+
main_plot,
199+
volume_plot,
200+
metrics,
201+
error_text, # It will only be visible when there's an error
202+
pn.pane.Markdown('---\nData provided by Yahoo Finance')
203+
)
204+
205+
# Create template
206+
template = pn.template.FastListTemplate(
207+
title='Stock Analyzer',
208+
sidebar=[sidebar],
209+
main=[main_content],
210+
)
211+
212+
# Initial update
213+
update_plots(None)
214+
215+
# Serve the dashboard
216+
template.servable()

0 commit comments

Comments
 (0)