TiMBA-Charts 0.1.1__py3-none-any.whl
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.
- Toolbox/Input/Additional_Information/reformate_fao_data.py +20 -0
- Toolbox/__init__.py +0 -0
- Toolbox/classes/__init__.py +0 -0
- Toolbox/classes/dashboard.py +362 -0
- Toolbox/classes/import_data.py +243 -0
- Toolbox/classes/model_analysis.py +305 -0
- Toolbox/classes/scenario_plots.py +382 -0
- Toolbox/cli/__init__.py +0 -0
- Toolbox/cli/cli.py +26 -0
- Toolbox/parameters/default_parameters.py +5 -0
- Toolbox/parameters/paths.py +11 -0
- Toolbox/toolbox.py +33 -0
- timba_charts-0.1.1.dist-info/METADATA +147 -0
- timba_charts-0.1.1.dist-info/RECORD +18 -0
- timba_charts-0.1.1.dist-info/WHEEL +5 -0
- timba_charts-0.1.1.dist-info/entry_points.txt +2 -0
- timba_charts-0.1.1.dist-info/licenses/COPYING +661 -0
- timba_charts-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
fao = pd.read_csv('Forestry_subsetted_Data_reformatted.csv')
|
|
4
|
+
|
|
5
|
+
h_commodity = pd.read_csv('commodity_info.csv', encoding="ISO-8859-1")
|
|
6
|
+
h_commodity = h_commodity[['GFPM_Code','FAO-Code']]
|
|
7
|
+
h_commodity.columns = ['GFPM_Code_Commodity','FAO_Code_commodity']
|
|
8
|
+
|
|
9
|
+
h_country = pd.read_csv('country_info.csv', encoding="ISO-8859-1")
|
|
10
|
+
h_country = h_country[['Country-Code', 'FAOCou-Code']]
|
|
11
|
+
h_country.columns = ['GFPM_Code_Country','FAO_Code_Country']
|
|
12
|
+
|
|
13
|
+
fao_commodity = fao.merge(right=h_commodity, how='left',left_on='Item_Codes',right_on='FAO_Code_commodity').dropna()
|
|
14
|
+
fao_final = fao_commodity.merge(right=h_country, how='left',left_on='Area_Codes',right_on='FAO_Code_Country').dropna()
|
|
15
|
+
fao_final = fao_final.reset_index(drop=True)
|
|
16
|
+
|
|
17
|
+
fao_final_o5 = fao_final[fao_final.GFPM_Code_Country == 'o5']
|
|
18
|
+
print(fao_final_o5)
|
|
19
|
+
|
|
20
|
+
fao_final.to_csv('FAO_Data_py.csv')
|
Toolbox/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import plotly.graph_objects as go
|
|
2
|
+
import dash
|
|
3
|
+
import dash_bootstrap_components as dbc
|
|
4
|
+
from dash import dcc, html
|
|
5
|
+
from dash.dependencies import Input, Output, State
|
|
6
|
+
import webbrowser
|
|
7
|
+
from threading import Timer
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import numpy as np
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
import plotly.express as px
|
|
12
|
+
import textwrap
|
|
13
|
+
|
|
14
|
+
PACKAGEDIR = Path(__file__).parent.parent.absolute()
|
|
15
|
+
|
|
16
|
+
class DashboardPlotter:
|
|
17
|
+
|
|
18
|
+
def __init__(self, data):
|
|
19
|
+
self.data = data
|
|
20
|
+
self.app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
|
|
21
|
+
self.start = self.data['year'].min()
|
|
22
|
+
self.end = self.data['year'].max()
|
|
23
|
+
self.color_list = [
|
|
24
|
+
'#2A4D69', # Dunkelblau
|
|
25
|
+
'#4B8BBE', # Hellblau
|
|
26
|
+
'#D35400', # Dunkelorange
|
|
27
|
+
'#AAB7B8', # Grau
|
|
28
|
+
'#9B59B6', # Lila
|
|
29
|
+
'#2980B9', # Blau
|
|
30
|
+
'#27AE60', # Grün
|
|
31
|
+
'#6C757D', # Dunkelgrau
|
|
32
|
+
'#F1C40F', # Senfgelb
|
|
33
|
+
'#E67E22', # Orange
|
|
34
|
+
]
|
|
35
|
+
self.create_layout()
|
|
36
|
+
self.create_callbacks()
|
|
37
|
+
|
|
38
|
+
def create_layout(self):
|
|
39
|
+
dropdown_style = {'height': '30px','marginBottom': '10px'}
|
|
40
|
+
self.app.layout = dbc.Container([
|
|
41
|
+
dbc.Row([
|
|
42
|
+
dbc.Col(width=5), # Leere Spalte für den linken Rand
|
|
43
|
+
dbc.Col(
|
|
44
|
+
html.Img(src="https://raw.githubusercontent.com/TI-Forest-Sector-Modelling/TiMBA/ToolBox_implementation_cm/images/timba_dashboard_logo.png",
|
|
45
|
+
style={'height': '90px', 'width': 'auto'}),
|
|
46
|
+
width=1
|
|
47
|
+
),
|
|
48
|
+
dbc.Col(
|
|
49
|
+
#html.H1("TiMBA Dashboard", className="text-center mb-4"), width=10
|
|
50
|
+
)
|
|
51
|
+
]),
|
|
52
|
+
dbc.Row([
|
|
53
|
+
dbc.Col([
|
|
54
|
+
dbc.Card([
|
|
55
|
+
dbc.CardBody([
|
|
56
|
+
html.H4("Filters", className="card-title"),
|
|
57
|
+
dcc.Dropdown(id='region-dropdown',
|
|
58
|
+
options=[{'label': i, 'value': i} for i in sorted(self.data['ISO3'].dropna().unique())],
|
|
59
|
+
multi=True,
|
|
60
|
+
placeholder="Select Country...",
|
|
61
|
+
style=dropdown_style),
|
|
62
|
+
dcc.Dropdown(id='continent-dropdown',
|
|
63
|
+
options=[{'label': i, 'value': i} for i in sorted(self.data['Continent'].dropna().unique())],
|
|
64
|
+
placeholder="Select Continent...",
|
|
65
|
+
multi=True,
|
|
66
|
+
style=dropdown_style),
|
|
67
|
+
dcc.Dropdown(id='domain-dropdown',
|
|
68
|
+
options=[{'label': i, 'value': i} for i in sorted(self.data['domain'].dropna().unique())],
|
|
69
|
+
placeholder="Select Domain...",
|
|
70
|
+
multi=True,
|
|
71
|
+
style=dropdown_style),
|
|
72
|
+
dcc.Dropdown(id='commodity-dropdown',
|
|
73
|
+
options=[{'label': i, 'value': i} for i in sorted(self.data['Commodity'].dropna().unique())],
|
|
74
|
+
placeholder="Select Commodity...",
|
|
75
|
+
multi=True,
|
|
76
|
+
style=dropdown_style),
|
|
77
|
+
dcc.Dropdown(id='commodity-group-dropdown',
|
|
78
|
+
options=[{'label': i, 'value': i} for i in self.data['Commodity_Group'].dropna().unique().tolist()],
|
|
79
|
+
placeholder="Select Commodity Group...",
|
|
80
|
+
multi=True,
|
|
81
|
+
style=dropdown_style),
|
|
82
|
+
dcc.Dropdown(id='scenario-filter',
|
|
83
|
+
options=[{'label': i, 'value': i} for i in self.data['Scenario'].unique()],
|
|
84
|
+
placeholder="Select Scenario...",
|
|
85
|
+
multi=True,
|
|
86
|
+
style=dropdown_style),
|
|
87
|
+
html.Button("Download CSV", id="btn_csv"),
|
|
88
|
+
dcc.Download(id="download-dataframe-csv"),
|
|
89
|
+
])
|
|
90
|
+
], className="mb-4", style={'white': 'white'}), #filter box
|
|
91
|
+
dbc.Card([
|
|
92
|
+
dbc.CardBody([
|
|
93
|
+
dcc.Graph(id='price-plot',
|
|
94
|
+
config={'toImageButtonOptions': {'format': 'png', 'filename': 'price_plot'}},
|
|
95
|
+
style={'height': '45vh','width':'46vh'})
|
|
96
|
+
])
|
|
97
|
+
], style={'white': 'white'}) #price box
|
|
98
|
+
], width=3),
|
|
99
|
+
dbc.Col([
|
|
100
|
+
dbc.Row([
|
|
101
|
+
dbc.Col([
|
|
102
|
+
dbc.Card([
|
|
103
|
+
dbc.CardBody([
|
|
104
|
+
dcc.Graph(id='quantity-plot',
|
|
105
|
+
config={'toImageButtonOptions': {'format': 'png', 'filename': 'quantity_plot'}},
|
|
106
|
+
style={'height': '84.5vh'})
|
|
107
|
+
])
|
|
108
|
+
], style={'backgroundColor': 'white'}) #mittelbox
|
|
109
|
+
], width=8), # Breite auf 8 reduziert
|
|
110
|
+
dbc.Col([
|
|
111
|
+
dbc.Card([
|
|
112
|
+
dbc.CardBody([
|
|
113
|
+
dcc.Graph(id='forstock-plot', # Geändert: ID auf 'forstock-plot'
|
|
114
|
+
config={'toImageButtonOptions': {'format': 'png'}},
|
|
115
|
+
style={'height': '39vh'})
|
|
116
|
+
])
|
|
117
|
+
], style={'backgroundColor': 'white', 'marginBottom': '20px'}), # Abstand hinzugefügt
|
|
118
|
+
dbc.Card([
|
|
119
|
+
dbc.CardBody([
|
|
120
|
+
html.H5("Filter for Worldmap", className="card-title"),
|
|
121
|
+
#html.H6("Scenario Filter", className="card-title"), # Titel für den Scenario-Filter
|
|
122
|
+
#html.H6("Year Filter", className="card-title"), # Titel für den Year-Filter
|
|
123
|
+
dcc.Dropdown(
|
|
124
|
+
id='year-filter',
|
|
125
|
+
options=[{'label': i, 'value': i} for i in sorted(self.data['year'].unique())],
|
|
126
|
+
placeholder="Select Year...",
|
|
127
|
+
style=dropdown_style
|
|
128
|
+
),
|
|
129
|
+
dcc.Graph(id='world-map', # Geändert: ID auf 'world-map'
|
|
130
|
+
config={'toImageButtonOptions': {'format': 'png'}},
|
|
131
|
+
style={'height': '31.75vh'})
|
|
132
|
+
])
|
|
133
|
+
], style={'backgroundColor': 'white'})
|
|
134
|
+
], width=4), # Breite auf 4 gesetzt
|
|
135
|
+
]),
|
|
136
|
+
], width=9)
|
|
137
|
+
])
|
|
138
|
+
], fluid=True, style={'backgroundColor': 'white'}) #gesamthintergrund
|
|
139
|
+
|
|
140
|
+
def create_callbacks(self):
|
|
141
|
+
@self.app.callback(
|
|
142
|
+
[Output('quantity-plot', 'figure'),
|
|
143
|
+
Output('price-plot', 'figure'),
|
|
144
|
+
Output('forstock-plot', 'figure')],
|
|
145
|
+
[Input('region-dropdown', 'value'),
|
|
146
|
+
Input('continent-dropdown', 'value'),
|
|
147
|
+
Input('domain-dropdown', 'value'),
|
|
148
|
+
Input('commodity-dropdown', 'value'),
|
|
149
|
+
Input('commodity-group-dropdown', 'value'),
|
|
150
|
+
Input('scenario-filter', 'value')]
|
|
151
|
+
)
|
|
152
|
+
def update_plots(region, continent, domain, commodity, commodity_group,scenario):
|
|
153
|
+
return self.update_plot_data(region, continent, domain, commodity, commodity_group,scenario)
|
|
154
|
+
|
|
155
|
+
@self.app.callback(
|
|
156
|
+
Output('world-map', 'figure'),
|
|
157
|
+
[Input('scenario-filter', 'value'),
|
|
158
|
+
Input('year-filter', 'value'),
|
|
159
|
+
Input('region-dropdown', 'value'),
|
|
160
|
+
Input('continent-dropdown', 'value'),
|
|
161
|
+
Input('domain-dropdown', 'value'),
|
|
162
|
+
Input('commodity-dropdown', 'value'),
|
|
163
|
+
Input('commodity-group-dropdown', 'value')]
|
|
164
|
+
)
|
|
165
|
+
def update_world_map(scenario, year, region, continent, domain, commodity, commodity_group):
|
|
166
|
+
return self.create_world_map(region, continent, domain, commodity, commodity_group, scenario, year)
|
|
167
|
+
|
|
168
|
+
@self.app.callback(
|
|
169
|
+
Output("download-dataframe-csv", "data"),
|
|
170
|
+
Input("btn_csv", "n_clicks"),
|
|
171
|
+
[State('region-dropdown', 'value'),
|
|
172
|
+
State('continent-dropdown', 'value'),
|
|
173
|
+
State('domain-dropdown', 'value'),
|
|
174
|
+
State('commodity-dropdown', 'value'),
|
|
175
|
+
State('commodity-group-dropdown', 'value'),
|
|
176
|
+
State('scenario-filter', 'value')], # Geändert von Input zu State
|
|
177
|
+
prevent_initial_call=True
|
|
178
|
+
)
|
|
179
|
+
def func(n_clicks, region, continent, domain, commodity, commodity_group, scenario):
|
|
180
|
+
if n_clicks is None:
|
|
181
|
+
raise dash.exceptions.PreventUpdate
|
|
182
|
+
filtered_data = self.filter_data(region, continent, domain, commodity, commodity_group, scenario)
|
|
183
|
+
return dcc.send_data_frame(filtered_data.to_csv, "filtered_data.csv")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def filter_data(self, region, continent, domain, commodity, commodity_group, scenario):
|
|
187
|
+
filtered_data = self.data
|
|
188
|
+
if region and isinstance(region, list):
|
|
189
|
+
filtered_data = filtered_data[filtered_data['ISO3'].isin(region)]
|
|
190
|
+
if continent and isinstance(continent, list):
|
|
191
|
+
filtered_data = filtered_data[filtered_data['Continent'].isin(continent)]
|
|
192
|
+
if domain and isinstance(domain, list):
|
|
193
|
+
filtered_data = filtered_data[filtered_data['domain'].isin(domain)]
|
|
194
|
+
if commodity and isinstance(commodity, list):
|
|
195
|
+
filtered_data = filtered_data[filtered_data['Commodity'].isin(commodity)]
|
|
196
|
+
if commodity_group and isinstance(commodity_group, list):
|
|
197
|
+
filtered_data = filtered_data[filtered_data['Commodity_Group'].isin(commodity_group)]
|
|
198
|
+
if scenario and isinstance(scenario, list):
|
|
199
|
+
filtered_data = filtered_data[filtered_data['Scenario'].isin(scenario)]
|
|
200
|
+
filtered_data = self.remove_extreme_outliers(df=filtered_data, col='price')
|
|
201
|
+
return filtered_data
|
|
202
|
+
|
|
203
|
+
def update_plot_data(self, region, continent, domain, commodity, commodity_group, scenario):
|
|
204
|
+
graphic_template='plotly_white'#'plotly_dark'#'plotly_white'
|
|
205
|
+
filtered_data = self.filter_data(region, continent, domain, commodity, commodity_group, scenario)
|
|
206
|
+
|
|
207
|
+
# Quantity plot
|
|
208
|
+
grouped_data_quantity = filtered_data.groupby(['year', 'Scenario']).sum().reset_index()
|
|
209
|
+
grouped_data_quantity = grouped_data_quantity[(grouped_data_quantity["year"] >= self.start) & (grouped_data_quantity["year"] <= self.end)]
|
|
210
|
+
fig_quantity = go.Figure()
|
|
211
|
+
for i, scenario in enumerate(grouped_data_quantity['Scenario'].unique()):
|
|
212
|
+
subset = grouped_data_quantity[grouped_data_quantity['Scenario'] == scenario]
|
|
213
|
+
color = self.color_list[i % len(self.color_list)]
|
|
214
|
+
dash = 'solid' if scenario in ['Historic Data'] else 'dash'
|
|
215
|
+
fig_quantity.add_trace(go.Scatter(x=subset['year'], y=subset['quantity'], mode='lines',
|
|
216
|
+
name=f'{scenario}', line=dict(color=color, dash=dash)))
|
|
217
|
+
title_quantity = self.generate_title(region, continent, domain, commodity, commodity_group)
|
|
218
|
+
title= "Quantity by Period and Scenario for " + title_quantity
|
|
219
|
+
fig_quantity.update_layout(
|
|
220
|
+
title='<br>'.join(textwrap.wrap(title, width=90)),
|
|
221
|
+
xaxis_title='Year',
|
|
222
|
+
yaxis_title='Quantity',
|
|
223
|
+
yaxis=dict(rangemode='nonnegative', zeroline=True, zerolinewidth=2, zerolinecolor='LightGrey'),
|
|
224
|
+
legend_title='Scenario',
|
|
225
|
+
legend=dict(orientation="h", yanchor="top", y=-0.1, xanchor="center", x=0.5),
|
|
226
|
+
margin=dict(l=35, r=35, t=60, b=90),
|
|
227
|
+
hovermode='x unified',
|
|
228
|
+
template=graphic_template
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
# Price plot
|
|
232
|
+
grouped_data_price = filtered_data.groupby(['year', 'Scenario']).mean().reset_index()
|
|
233
|
+
max_year = grouped_data_price['year'].max() + 0.5
|
|
234
|
+
|
|
235
|
+
fig_price = go.Figure()
|
|
236
|
+
for i, scenario in enumerate(grouped_data_price['Scenario'].unique()):
|
|
237
|
+
subset = grouped_data_price[grouped_data_price['Scenario'] == scenario]
|
|
238
|
+
color = self.color_list[i % len(self.color_list)]
|
|
239
|
+
fig_price.add_trace(go.Bar(x=subset['price'], y=subset['year'], orientation='h',
|
|
240
|
+
name=f'{scenario}', marker_color=color))
|
|
241
|
+
|
|
242
|
+
title_price = f'Price by Period and Scenario'
|
|
243
|
+
fig_price.update_layout(
|
|
244
|
+
title=title_price,
|
|
245
|
+
xaxis_title='Price',
|
|
246
|
+
yaxis_title='Year',
|
|
247
|
+
yaxis=dict(range=[2020-0.5, max_year]),
|
|
248
|
+
legend_title='Scenario',
|
|
249
|
+
template=graphic_template,
|
|
250
|
+
showlegend=False,
|
|
251
|
+
#legend=dict(orientation="h", yanchor="top", y=-0.25, xanchor="center", x=0.5),
|
|
252
|
+
margin=dict(l=35, r=60, t=50, b=5),
|
|
253
|
+
barmode='group'
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# ForStock plot
|
|
257
|
+
grouped_data_stock = filtered_data.drop(columns=['domain', 'price','quantity','CommodityCode','Commodity','Commodity_Group'])
|
|
258
|
+
grouped_data_stock = grouped_data_stock.drop_duplicates().reset_index(drop=True)
|
|
259
|
+
grouped_data_stock = grouped_data_stock.groupby(['year', 'Scenario']).agg({
|
|
260
|
+
'ForStock': 'sum',
|
|
261
|
+
}).reset_index()
|
|
262
|
+
grouped_data_stock = grouped_data_stock[grouped_data_stock.Scenario!='Historic Data']
|
|
263
|
+
fig_stock = go.Figure()
|
|
264
|
+
for i, scenario in enumerate(grouped_data_stock['Scenario'].unique()):
|
|
265
|
+
subset = grouped_data_stock[grouped_data_stock['Scenario'] == scenario]
|
|
266
|
+
color = self.color_list[i+1 % len(self.color_list)]
|
|
267
|
+
fig_stock.add_trace(go.Bar(x=subset['year'], y=subset['ForStock'],
|
|
268
|
+
name=f'{scenario}', marker_color=color))
|
|
269
|
+
|
|
270
|
+
min_year = 2020 - 1
|
|
271
|
+
max_year = grouped_data_stock['year'].max() + 0.5
|
|
272
|
+
|
|
273
|
+
min_val = grouped_data_stock['ForStock'].min() * 0.9
|
|
274
|
+
max_val = grouped_data_stock['ForStock'].max() * 1.1
|
|
275
|
+
|
|
276
|
+
fig_stock.update_layout(
|
|
277
|
+
title='Forest Stock by Year and Scenario',
|
|
278
|
+
xaxis_title='Year',
|
|
279
|
+
xaxis=dict(range=[min_year, max_year]),
|
|
280
|
+
yaxis=dict(range=[min_val, max_val]),
|
|
281
|
+
yaxis_title='ForStock',
|
|
282
|
+
template=graphic_template,
|
|
283
|
+
showlegend=False,
|
|
284
|
+
#legend=dict(orientation="h", yanchor="top", y=-0.35, xanchor="center", x=0.5),
|
|
285
|
+
margin=dict(l=50, r=50, t=40, b=5),
|
|
286
|
+
barmode='group'
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
return fig_quantity, fig_price, fig_stock
|
|
290
|
+
|
|
291
|
+
def generate_title(self, region, continent, domain, commodity, commodity_group):
|
|
292
|
+
title_parts = []
|
|
293
|
+
if region:
|
|
294
|
+
title_parts.append(f"{region}")
|
|
295
|
+
if continent:
|
|
296
|
+
title_parts.append(f"{continent}")
|
|
297
|
+
if domain:
|
|
298
|
+
title_parts.append(f"{domain}")
|
|
299
|
+
if commodity:
|
|
300
|
+
title_parts.append(f"{commodity}")
|
|
301
|
+
if commodity_group:
|
|
302
|
+
title_parts.append(f"{commodity_group}")
|
|
303
|
+
title = ", ".join(title_parts) if title_parts else "all data"
|
|
304
|
+
clean_title = title.replace("'", "").replace("[", "").replace("]", "")
|
|
305
|
+
return clean_title
|
|
306
|
+
|
|
307
|
+
def create_world_map(self, region, continent, domain, commodity, commodity_group, scenario=None, year=None):
|
|
308
|
+
filtered_data = self.filter_data(region, continent, domain, commodity, commodity_group, scenario)
|
|
309
|
+
if year:
|
|
310
|
+
filtered_data = filtered_data[filtered_data['year']==year]
|
|
311
|
+
country_data = filtered_data.groupby('ISO3')['quantity'].sum().reset_index()
|
|
312
|
+
country_data = country_data[country_data['quantity']>=0.001].reset_index()
|
|
313
|
+
|
|
314
|
+
fig = px.choropleth(
|
|
315
|
+
country_data,
|
|
316
|
+
locations="ISO3",
|
|
317
|
+
color="quantity",
|
|
318
|
+
hover_name="ISO3",
|
|
319
|
+
color_continuous_scale="Greens"
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
title = 'Worldmap for '+ self.generate_title(region, continent, domain, commodity, commodity_group)
|
|
323
|
+
fig.update_layout(
|
|
324
|
+
#title= '<br>'.join(textwrap.wrap(title, width=43)),
|
|
325
|
+
geo=dict(
|
|
326
|
+
showcoastlines=True,
|
|
327
|
+
coastlinecolor="LightGray",
|
|
328
|
+
showocean=False,
|
|
329
|
+
oceancolor="LightBlue",
|
|
330
|
+
projection_type='natural earth',
|
|
331
|
+
# Grenzen bestimmen
|
|
332
|
+
lonaxis_range=[-360, 360], # Längengradbereich
|
|
333
|
+
lataxis_range=[-55, 55], # Breitengradbereich
|
|
334
|
+
),
|
|
335
|
+
margin=dict(l=1, r=1, t=1, b=1), # Ränder minimieren
|
|
336
|
+
coloraxis_showscale=False # Legende entfernen
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
return fig
|
|
340
|
+
|
|
341
|
+
def get_last_historic_year(self):
|
|
342
|
+
historic_data = self.data[self.data['Scenario'] == 'Historic Data']
|
|
343
|
+
if not historic_data.empty:
|
|
344
|
+
return historic_data['year'].max()
|
|
345
|
+
else:
|
|
346
|
+
return self.data['year'].max()
|
|
347
|
+
|
|
348
|
+
def remove_extreme_outliers(self,df:pd.DataFrame,col:str,threshhold:float=50):
|
|
349
|
+
Q1 = df[col].quantile(0.25)
|
|
350
|
+
Q3 = df[col].quantile(0.75)
|
|
351
|
+
IQR = Q3 - Q1
|
|
352
|
+
outlier_threshold = threshhold * IQR
|
|
353
|
+
df.loc[df[col] >= outlier_threshold, col] = np.nan
|
|
354
|
+
return df
|
|
355
|
+
|
|
356
|
+
def open_browser(self):
|
|
357
|
+
webbrowser.open_new("http://localhost:8050")
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def run(self):
|
|
361
|
+
Timer(1, self.open_browser).start()
|
|
362
|
+
self.app.run(host='localhost', debug=False, dev_tools_ui=False, dev_tools_hot_reload=False, port=8050)
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import pickle
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import numpy as np
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import os
|
|
6
|
+
from enum import Enum
|
|
7
|
+
import pickle
|
|
8
|
+
import gzip
|
|
9
|
+
import Toolbox.parameters.paths as toolbox_paths
|
|
10
|
+
import Toolbox.parameters.default_parameters as toolbox_parameters
|
|
11
|
+
|
|
12
|
+
class import_pkl_data:
|
|
13
|
+
def __init__(self, num_files_to_read:int=10,
|
|
14
|
+
SCENARIOPATH:Path= toolbox_paths.SCINPUTPATH,
|
|
15
|
+
ADDINFOPATH:Path= toolbox_paths.AIINPUTPATH):
|
|
16
|
+
self.num_files_to_read = num_files_to_read
|
|
17
|
+
self.SCENARIOPATH = SCENARIOPATH
|
|
18
|
+
self.ADDINFOPATH = ADDINFOPATH
|
|
19
|
+
|
|
20
|
+
def open_pickle(self, src_filepath: str):
|
|
21
|
+
"""open pkl file
|
|
22
|
+
:param src_filepath: source path for pkl file
|
|
23
|
+
:return: object from pkl file
|
|
24
|
+
"""
|
|
25
|
+
import pickle
|
|
26
|
+
with open(src_filepath, "rb") as pkl_file:
|
|
27
|
+
obj = pickle.load(pkl_file)
|
|
28
|
+
return obj
|
|
29
|
+
|
|
30
|
+
def read_country_data(self):
|
|
31
|
+
"""read data additional information for country data
|
|
32
|
+
:return: country data
|
|
33
|
+
"""
|
|
34
|
+
country_data = pd.read_csv(self.ADDINFOPATH / toolbox_paths.COUNTRYINFO, encoding = "ISO-8859-1")
|
|
35
|
+
country_data = country_data[["Country-Code", "ContinentNew", "Country","ISO-Code"]]
|
|
36
|
+
country_data.columns = ["RegionCode","Continent", "Country","ISO3"]
|
|
37
|
+
country_data.Country = country_data.Country.astype("category")
|
|
38
|
+
country_data.Continent = country_data.Continent.astype("category")
|
|
39
|
+
country_data.ISO3 = country_data.ISO3.astype("category")
|
|
40
|
+
return country_data
|
|
41
|
+
|
|
42
|
+
def read_commodity_data(self):
|
|
43
|
+
"""read data additional information for commodity data
|
|
44
|
+
:return: commodity data
|
|
45
|
+
"""
|
|
46
|
+
commodity_data = pd.read_csv(self.ADDINFOPATH / toolbox_paths.COMMODITYINFO , encoding = "ISO-8859-1")
|
|
47
|
+
commodity_data = commodity_data[["Commodity","CommodityCode","Commodity_Group"]]
|
|
48
|
+
commodity_data.Commodity = commodity_data.Commodity.astype("category")
|
|
49
|
+
commodity_data.CommodityCode = commodity_data.CommodityCode.astype("category")
|
|
50
|
+
commodity_data.Commodity_Group = commodity_data.Commodity_Group.astype("category")
|
|
51
|
+
return commodity_data
|
|
52
|
+
|
|
53
|
+
def read_historic_data(self):
|
|
54
|
+
data = pd.read_csv(self.ADDINFOPATH / toolbox_paths.HISTINFO)
|
|
55
|
+
data = self.downcasting(data)
|
|
56
|
+
return data
|
|
57
|
+
|
|
58
|
+
def downcasting(self, data: pd.DataFrame):
|
|
59
|
+
data.RegionCode = data.RegionCode.astype("category")
|
|
60
|
+
data.CommodityCode = data.CommodityCode.astype("category")
|
|
61
|
+
data.domain = data.domain.astype("category")
|
|
62
|
+
data.price = data.price.astype("float32")
|
|
63
|
+
data.quantity = data.quantity.astype("float32")
|
|
64
|
+
data.Period = data.Period.astype("int16")
|
|
65
|
+
data.year = data.year.astype("int16")
|
|
66
|
+
data.Scenario = data.Scenario.astype("category")
|
|
67
|
+
data.Model = data.Model.astype("category")
|
|
68
|
+
return data
|
|
69
|
+
|
|
70
|
+
def add_consumption(self, data):
|
|
71
|
+
data["quantity"] = (data["quantity_ManufactureCost"] +
|
|
72
|
+
data["quantity_Supply"] -
|
|
73
|
+
data["quantity_TransportationExport"] +
|
|
74
|
+
data["quantity_TransportationImport"])
|
|
75
|
+
data.loc[data["quantity"] < 0, "quantity"] = 0
|
|
76
|
+
data["price"] = (((data["quantity_ManufactureCost"] * data["price_ManufactureCost"]) +
|
|
77
|
+
(data["quantity_Supply"] * data["price_Supply"]) -
|
|
78
|
+
(data["quantity_TransportationExport"] * data["price_TransportationExport"]) +
|
|
79
|
+
(data["quantity_TransportationImport"]* data["price_TransportationImport"]))/
|
|
80
|
+
data["quantity"])
|
|
81
|
+
data["price"] = 0
|
|
82
|
+
data["domain"] = "Consumption"
|
|
83
|
+
return data
|
|
84
|
+
|
|
85
|
+
def add_net_exports(self, data):
|
|
86
|
+
data["quantity"] = (data["quantity_TransportationExport"] -
|
|
87
|
+
data["quantity_TransportationImport"])
|
|
88
|
+
data["price"] = data["price_TransportationExport"]
|
|
89
|
+
data["domain"] = "Net Exports"
|
|
90
|
+
return data
|
|
91
|
+
|
|
92
|
+
def add_net_imports(self, data):
|
|
93
|
+
data["quantity"] = (data["quantity_TransportationImport"] -
|
|
94
|
+
data["quantity_TransportationExport"])
|
|
95
|
+
data["price"] = data["price_TransportationImport"]
|
|
96
|
+
data["domain"] = "Net Imports"
|
|
97
|
+
return data
|
|
98
|
+
|
|
99
|
+
def add_production(self, data):
|
|
100
|
+
data["quantity"] = (data["quantity_ManufactureCost"] + data["quantity_Supply"])
|
|
101
|
+
data["price"] = (((data["quantity_ManufactureCost"] * data["price_ManufactureCost"]) +
|
|
102
|
+
(data["quantity_Supply"] * data["price_Supply"])) / data["quantity"])
|
|
103
|
+
# if data["price"].mean() <=0:
|
|
104
|
+
# data["price"] = 0
|
|
105
|
+
data["domain"] = "Production"
|
|
106
|
+
return data
|
|
107
|
+
|
|
108
|
+
def concat_calc_domains(self,origin_data:pd.DataFrame,calc_data:pd.DataFrame):
|
|
109
|
+
calc_data = calc_data[['RegionCode','CommodityCode','Period','year','domain','price','quantity']].reset_index(drop=True)
|
|
110
|
+
result_df = pd.concat([origin_data, calc_data], axis=0).reset_index(drop=True)
|
|
111
|
+
return result_df
|
|
112
|
+
|
|
113
|
+
def add_calculated_domains(self,data:pd.DataFrame):
|
|
114
|
+
pivoted_price = data["data_periods"].pivot(index=["RegionCode", "CommodityCode", "Period", "year"],
|
|
115
|
+
columns="domain",
|
|
116
|
+
values="price").add_prefix("price_")
|
|
117
|
+
pivoted_quantity = data["data_periods"].pivot(index=["RegionCode", "CommodityCode", "Period", "year"],
|
|
118
|
+
columns="domain",
|
|
119
|
+
values="quantity").add_prefix("quantity_")
|
|
120
|
+
pivoted_df = pd.concat([pivoted_price, pivoted_quantity], axis=1).reset_index()
|
|
121
|
+
|
|
122
|
+
calculated_functions = [#"add_consumption",
|
|
123
|
+
"add_net_exports",
|
|
124
|
+
"add_net_imports",
|
|
125
|
+
#"add_production",
|
|
126
|
+
]
|
|
127
|
+
for method_name in calculated_functions:
|
|
128
|
+
calc_df = getattr(self, method_name)(data=pivoted_df)
|
|
129
|
+
data["data_periods"] = self.concat_calc_domains(origin_data=data["data_periods"], calc_data=calc_df)
|
|
130
|
+
|
|
131
|
+
return data["data_periods"]
|
|
132
|
+
|
|
133
|
+
def concat_scenarios(self, data: pd.DataFrame, sc_name:str, data_prev: pd.DataFrame, ID: int):
|
|
134
|
+
"""concat_scenarios, add scenario name from pkl file to data frames
|
|
135
|
+
:param data: dictionary of the data container
|
|
136
|
+
:param sc_name: scenario name from file name in dictionary
|
|
137
|
+
"""
|
|
138
|
+
data["data_periods"] = self.add_calculated_domains(data=data)
|
|
139
|
+
try:
|
|
140
|
+
for key in data: #loop through all data from datacontainer
|
|
141
|
+
data[key][toolbox_parameters.column_name_scenario] = sc_name
|
|
142
|
+
data[key][toolbox_parameters.column_name_model] = toolbox_parameters.model_name
|
|
143
|
+
#data[key][parameters.column_name_id.value] = ID
|
|
144
|
+
if data_prev != []:
|
|
145
|
+
data[key] = pd.concat([data_prev[key], data[key]], axis=0)
|
|
146
|
+
except KeyError:
|
|
147
|
+
pass
|
|
148
|
+
|
|
149
|
+
def combined_data(self):
|
|
150
|
+
"""loop trough all input files in input directory
|
|
151
|
+
"""
|
|
152
|
+
scenario_path = self.SCENARIOPATH
|
|
153
|
+
num_files_to_read = self.num_files_to_read
|
|
154
|
+
pkl_files = [
|
|
155
|
+
Path(scenario_path) / file
|
|
156
|
+
for file in os.listdir(scenario_path)
|
|
157
|
+
if file.endswith(".pkl")
|
|
158
|
+
]
|
|
159
|
+
sorted_files = sorted(pkl_files, key=lambda x: x.stat().st_mtime, reverse=True)
|
|
160
|
+
newest_files = sorted_files[:num_files_to_read]
|
|
161
|
+
|
|
162
|
+
data = []
|
|
163
|
+
data_prev = []
|
|
164
|
+
ID = 1
|
|
165
|
+
for scenario_files in newest_files:
|
|
166
|
+
src_filepath = scenario_path / scenario_files
|
|
167
|
+
print(src_filepath)
|
|
168
|
+
scenario_name = str(scenario_files)[str(scenario_files).rfind(toolbox_parameters.seperator_scenario_name)+3
|
|
169
|
+
:-4]
|
|
170
|
+
try:
|
|
171
|
+
with gzip.open(src_filepath,'rb') as f:
|
|
172
|
+
if type(f) == gzip.GzipFile:
|
|
173
|
+
data = pickle.load(f)
|
|
174
|
+
data['data_periods'] = data['data_periods'][['RegionCode','CommodityCode','Period','year','domain','price','quantity']]
|
|
175
|
+
self.concat_scenarios(data=data, sc_name=scenario_name, data_prev=data_prev, ID=ID)
|
|
176
|
+
except gzip.BadGzipFile:
|
|
177
|
+
pass
|
|
178
|
+
except pickle.UnpicklingError:
|
|
179
|
+
pass
|
|
180
|
+
except PermissionError:
|
|
181
|
+
pass
|
|
182
|
+
except ValueError:
|
|
183
|
+
pass
|
|
184
|
+
|
|
185
|
+
data_prev = data
|
|
186
|
+
ID += 1
|
|
187
|
+
|
|
188
|
+
data_prev["data_periods"] = self.downcasting(data_prev["data_periods"])
|
|
189
|
+
try:
|
|
190
|
+
data = self.read_historic_data()
|
|
191
|
+
except FileNotFoundError:
|
|
192
|
+
data = pd.DataFrame()
|
|
193
|
+
country_data = self.read_country_data()
|
|
194
|
+
commodity_data = self.read_commodity_data()
|
|
195
|
+
forest_data = data_prev['Forest']
|
|
196
|
+
forest_data = forest_data[['Scenario','RegionCode','Period','ForStock','ForArea']]
|
|
197
|
+
forest_data = forest_data.drop_duplicates(subset=['Scenario', 'RegionCode', 'Period'], keep='first')
|
|
198
|
+
data_prev["data_periods"] = pd.merge(data_prev["data_periods"], forest_data, how='left', on=['Scenario','RegionCode','Period'])
|
|
199
|
+
data_prev["data_periods"] = pd.concat([data_prev["data_periods"], data], axis=0)
|
|
200
|
+
data_prev["data_periods"] = pd.merge(data_prev["data_periods"], country_data, on="RegionCode", how="left")
|
|
201
|
+
data_prev["data_periods"] = pd.merge(data_prev["data_periods"], commodity_data, on="CommodityCode", how="left")
|
|
202
|
+
data_prev["data_periods"]["domain"] = data_prev["data_periods"]["domain"].replace({
|
|
203
|
+
'ManufactureCost': 'Manufacturing',
|
|
204
|
+
'TransportationExport': 'Export',
|
|
205
|
+
'TransportationImport': 'Import',
|
|
206
|
+
})
|
|
207
|
+
data_prev["data_periods"] = data_prev["data_periods"][['Model','Scenario','RegionCode','Continent','Country','ISO3',
|
|
208
|
+
'CommodityCode','Commodity','Commodity_Group','Period','year',
|
|
209
|
+
'domain','price','quantity',
|
|
210
|
+
'ForStock','ForArea',
|
|
211
|
+
]]
|
|
212
|
+
return data_prev
|
|
213
|
+
|
|
214
|
+
def read_forest_data_gfpm(self, country_data:pd.DataFrame):
|
|
215
|
+
for_data_gfpm = pd.read_csv(self.ADDINFOPATH / toolbox_paths.FORESTINFO, encoding = "ISO-8859-1")
|
|
216
|
+
|
|
217
|
+
rearranged_for_data = pd.melt(for_data_gfpm, id_vars=['domain','Country'], var_name='Year',value_name='for')
|
|
218
|
+
rearranged_for_data = rearranged_for_data.dropna()
|
|
219
|
+
rearranged_for_data['Year'] = rearranged_for_data['Year'].astype(int)
|
|
220
|
+
|
|
221
|
+
foreststock = pd.DataFrame()
|
|
222
|
+
for domain in rearranged_for_data.domain.unique():
|
|
223
|
+
rearranged_for_data_domain = rearranged_for_data[rearranged_for_data['domain'] == domain].reset_index(drop=True)
|
|
224
|
+
if domain == 'ForArea':
|
|
225
|
+
rearranged_for_data_domain['ForStock'] = foreststock
|
|
226
|
+
else:
|
|
227
|
+
foreststock = rearranged_for_data_domain['for']
|
|
228
|
+
forest_data = rearranged_for_data_domain[['Country', 'Year', 'for', 'ForStock']]
|
|
229
|
+
forest_data.columns = ['Country', 'Year', 'ForArea', 'ForStock']
|
|
230
|
+
forest_data = pd.merge(forest_data, country_data, on= 'Country')
|
|
231
|
+
|
|
232
|
+
period_mapping = {2017: 0, 2020: 1, 2025: 2, 2030: 3, 2035: 4, 2040: 5, 2045: 6, 2050: 7, 2055: 8, 2060: 9, 2065: 10}
|
|
233
|
+
forest_data['Period'] = forest_data['Year'].map(period_mapping)
|
|
234
|
+
|
|
235
|
+
forest_gfpm = forest_data[['RegionCode', 'Period', 'ForStock', 'ForArea']]
|
|
236
|
+
forest_gfpm[toolbox_parameters.column_name_scenario]= 'world500'
|
|
237
|
+
forest_data['Model'] = 'GFPM'
|
|
238
|
+
return forest_gfpm
|
|
239
|
+
|
|
240
|
+
if __name__ == "__main__":
|
|
241
|
+
import_pkl = import_pkl_data()
|
|
242
|
+
data = import_pkl.combined_data()
|
|
243
|
+
print(data['data_periods'])
|