Spaces:
Sleeping
Sleeping
MarcSkovMadsen
commited on
Update app.py
Browse files
app.py
CHANGED
@@ -1,108 +1,95 @@
|
|
1 |
import panel as pn
|
2 |
-
import pandas as pd
|
3 |
-
import hvplot.pandas
|
4 |
|
5 |
-
pn.extension("
|
6 |
|
7 |
-
|
8 |
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
"padding": "10px",
|
13 |
-
}
|
14 |
|
15 |
-
|
|
|
16 |
|
17 |
-
|
|
|
|
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
return pd.read_csv("https://assets.holoviz.org/panel/tutorials/turbines.csv.gz")
|
22 |
|
23 |
-
|
|
|
|
|
|
|
|
|
24 |
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
top_manufacturers = (
|
29 |
-
source_data.groupby("t_manu").p_cap.sum().sort_values().iloc[-10:].index.to_list()
|
30 |
-
)
|
31 |
|
32 |
-
|
33 |
-
data = source_data[(source_data.t_manu == t_manu) & (source_data.p_year <= year)]
|
34 |
-
return data
|
35 |
|
36 |
-
|
|
|
|
|
37 |
|
38 |
-
|
39 |
-
|
40 |
-
value="Vestas",
|
41 |
-
options=sorted(top_manufacturers),
|
42 |
-
description="The name of the manufacturer",
|
43 |
-
)
|
44 |
-
p_year = pn.widgets.IntSlider(name="Year", value=max_year, start=min_year, end=max_year)
|
45 |
-
|
46 |
-
# Transform Data 2
|
47 |
-
|
48 |
-
df = pn.rx(filter_data)(t_manu=t_manu, year=p_year)
|
49 |
-
count = df.rx.len()
|
50 |
-
total_capacity = df.t_cap.sum()
|
51 |
-
avg_capacity = df.t_cap.mean()
|
52 |
-
avg_rotor_diameter = df.t_rd.mean()
|
53 |
-
|
54 |
-
# Plot Data
|
55 |
-
|
56 |
-
fig = (
|
57 |
-
df[["p_year", "t_cap"]].groupby("p_year").sum() / 10**6
|
58 |
-
).hvplot.bar(
|
59 |
-
title="Capacity Change",
|
60 |
-
rot=90,
|
61 |
-
ylabel="Capacity (MW)",
|
62 |
-
xlabel="Year",
|
63 |
-
xlim=(min_year, max_year),
|
64 |
-
color=ACCENT,
|
65 |
-
)
|
66 |
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
format="{value:,.1f}",
|
77 |
-
styles=styles,
|
78 |
-
),
|
79 |
-
pn.indicators.Number(
|
80 |
-
value=avg_capacity/1e3,
|
81 |
-
name="Avg. Capacity (MW)",
|
82 |
-
format="{value:,.1f}",
|
83 |
-
styles=styles,
|
84 |
-
),
|
85 |
-
pn.indicators.Number(
|
86 |
-
value=avg_rotor_diameter,
|
87 |
-
name="Avg. Rotor Diameter (m)",
|
88 |
-
format="{value:,.1f}",
|
89 |
-
styles=styles,
|
90 |
-
),
|
91 |
-
)
|
92 |
|
93 |
-
|
94 |
-
|
95 |
|
96 |
-
# Layout Data
|
97 |
|
98 |
-
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
)
|
101 |
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
).servable()
|
|
|
1 |
import panel as pn
|
|
|
|
|
2 |
|
3 |
+
pn.extension(sizing_mode="stretch_width", design="material")
|
4 |
|
5 |
+
BUTTON_WIDTH = 125
|
6 |
|
7 |
+
# We use intslider to avoid teaching users pn.rx. Is that a good thing?
|
8 |
+
state_changed_count = pn.widgets.IntInput()
|
9 |
+
tasks = pn.Column()
|
|
|
|
|
10 |
|
11 |
+
def update_state_changed_count(*args):
|
12 |
+
state_changed_count.value += 1
|
13 |
|
14 |
+
def remove_task(task, *args):
|
15 |
+
index = tasks.index(task)
|
16 |
+
tasks.pop(index)
|
17 |
|
18 |
+
def remove_all_tasks(*args):
|
19 |
+
tasks.clear()
|
|
|
20 |
|
21 |
+
def create_task(text):
|
22 |
+
state = pn.widgets.Checkbox(align="center", sizing_mode="fixed")
|
23 |
+
content = pn.pane.Markdown(text)
|
24 |
+
remove = pn.widgets.Button(width=BUTTON_WIDTH, icon="trash", sizing_mode="fixed")
|
25 |
+
task = pn.Row(state, content, remove, sizing_mode="stretch_width")
|
26 |
|
27 |
+
pn.bind(remove_task, task, remove, watch=True)
|
28 |
+
# We have to bind the below after the above!
|
29 |
+
pn.bind(update_state_changed_count, state, remove, watch=True)
|
|
|
|
|
|
|
30 |
|
31 |
+
return task
|
|
|
|
|
32 |
|
33 |
+
def add_task(text, *args):
|
34 |
+
if not text:
|
35 |
+
return
|
36 |
|
37 |
+
new_task = create_task(text)
|
38 |
+
tasks.append(new_task)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
|
40 |
+
return tasks
|
41 |
+
|
42 |
+
def get_state(*args):
|
43 |
+
total_tasks = len(tasks)
|
44 |
+
completed_tasks = sum(check[0].value for check in tasks)
|
45 |
+
return f"{completed_tasks} of {total_tasks} tasks completed"
|
46 |
+
|
47 |
+
def can_add(value_input):
|
48 |
+
return not bool(value_input)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
+
def has_tasks(*args):
|
51 |
+
return len(tasks) > 0
|
52 |
|
|
|
53 |
|
54 |
+
add_task("Inspect the blades")
|
55 |
+
add_task("Inspect the nacelle")
|
56 |
+
add_task("Tighten the bolts")
|
57 |
+
|
58 |
+
text_input = pn.widgets.TextInput(name="Task", placeholder="Enter a task")
|
59 |
+
|
60 |
+
submit_task = pn.widgets.Button(
|
61 |
+
name="Add",
|
62 |
+
align="center",
|
63 |
+
button_type="primary",
|
64 |
+
width=BUTTON_WIDTH,
|
65 |
+
sizing_mode="fixed",
|
66 |
+
disabled=pn.bind(can_add, text_input.param.value_input)
|
67 |
+
)
|
68 |
+
clear = pn.widgets.Button(
|
69 |
+
name="Remove All",
|
70 |
+
button_type="primary",
|
71 |
+
button_style="outline",
|
72 |
+
width=BUTTON_WIDTH,
|
73 |
+
sizing_mode="fixed",
|
74 |
+
visible=pn.bind(has_tasks, state_changed_count)
|
75 |
)
|
76 |
|
77 |
+
def reset_text_input(*args):
|
78 |
+
text_input.value = text_input.value_input = ""
|
79 |
+
|
80 |
+
pn.bind(add_task, text_input, submit_task, watch=True)
|
81 |
+
pn.bind(reset_text_input, text_input, submit_task, watch=True)
|
82 |
+
pn.bind(remove_all_tasks, clear, watch=True)
|
83 |
+
# We have to bind the below after the above!
|
84 |
+
pn.bind(update_state_changed_count, text_input, submit_task, clear, watch=True)
|
85 |
+
|
86 |
+
status_report = pn.bind(get_state, state_changed_count, tasks.param.objects)
|
87 |
+
|
88 |
+
pn.Column(
|
89 |
+
"## WTG Task List",
|
90 |
+
status_report,
|
91 |
+
pn.Row(text_input, submit_task),
|
92 |
+
tasks,
|
93 |
+
pn.Row(pn.Spacer(), clear),
|
94 |
+
max_width=500,
|
95 |
).servable()
|