Skip to content

Commit

Permalink
Added GUI for defining Balmorel geography (#13)
Browse files Browse the repository at this point in the history
* Added eel dashboard

* Made copy button

* Added environments file

* Updated environments

* Upgraded to 0.3.5

* Added geofilemaker GUI and new GUI class

* Made a small example of the geographic file maker GUI

* Corrected versions

* Removed .yml file because we made a .yaml
  • Loading branch information
Mathias157 authored Sep 22, 2024
1 parent d07cd32 commit eb8ded0
Show file tree
Hide file tree
Showing 17 changed files with 506 additions and 34 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ src/*
examples/files/DE.inc
__pycache__
output
config
config
build
11 changes: 9 additions & 2 deletions docs/get_started/examples.md → docs/examples.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@

## Examples
# Examples
The following notebooks provide examples on how to use pybalmorel for pre-processing, post-processing and for executing Balmorel scenarios:
- [Pre-Processing](https://github.com/Mathias157/pybalmorel/blob/master/examples/PreProcessing.ipynb)
- [Execution](https://github.com/Mathias157/pybalmorel/blob/master/examples/Execution.ipynb)
- [Post-Processing](https://github.com/Mathias157/pybalmorel/blob/master/examples/PostProcessing.ipynb)

The next pages also include some code snippets on how to use various functions.

```{toctree}
:maxdepth: 1
examples/geofilemaker.md
```
16 changes: 16 additions & 0 deletions docs/examples/geofilemaker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Defining Geography

pybalmorel includes a GUI to interactively define nodes in Balmorel's hierarchical geographic structure comprising countries, regions and areas.
```python
from pybalmorel import GUI
GUI.geofilemaker()
```

The video below illustrates how it works.
:::{figure} ../img/geoset_generator_example.gif
:name: geofilemaker
:alt: How to use the 'geofilemaker' GUI.
:width: 100%
:align: center
How to use the 'geofilemaker' GUI.
:::
3 changes: 2 additions & 1 deletion docs/get_started.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Get Started

An installation instruction.

```{toctree}
:maxdepth: 1
get_started/installation.md
get_started/examples.md
```
14 changes: 7 additions & 7 deletions docs/get_started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ channels:
- conda-forge
dependencies:
- python >= 3.9
- pandas >= 2.1.4
- matplotlib >= 3.9.0
- geopandas >= 0.14.4
- ipywidgets >= 8.1.3
- ipykernel
- pandas>=2.1.4
- matplotlib>=3.9.0
- geopandas>=1.0.1
- ipywidgets>=8.1.3
- pip
- pip:
- gamsapi[transfer] >= 45.0.0
- pybalmorel
- gamsapi[transfer]>=45.0.0
- eel>=0.17.0
- pybalmorel==0.3.6
```
Binary file added docs/img/geoset_generator_example.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Get started [here](get_started.md).
:hidden:
get_started
examples
```

```{toctree}
Expand Down
14 changes: 14 additions & 0 deletions environment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: pybalmorel
channels:
- conda-forge
dependencies:
- python >= 3.9
- pandas>=2.1.4
- matplotlib>=3.9.0
- geopandas>=1.0.1
- ipywidgets>=8.1.3
- pip
- pip:
- gamsapi[transfer]>=45.0.0
- eel>=0.17.0
- pybalmorel==0.3.6
14 changes: 0 additions & 14 deletions environment.yml

This file was deleted.

32 changes: 28 additions & 4 deletions examples/PreProcessing.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
"outputs": [],
"source": [
"### 0.1 Use development scripts or the package installed from pip\n",
"use_development = True\n",
"use_development = False\n",
"if use_development:\n",
" import sys\n",
" import os\n",
" # Adjust the sys.path to include the project root directory\n",
" project_root = os.path.abspath(os.path.join(os.path.dirname(\"__file__\"), '..'))\n",
" if project_root not in sys.path:\n",
" sys.path.insert(0, project_root)\n",
" from src.pybalmorel import IncFile\n",
" from src.pybalmorel import IncFile, GUI\n",
"else:\n",
" from pybalmorel import IncFile"
]
Expand All @@ -40,7 +40,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -65,6 +65,30 @@
"# Save .inc file to path (will save as ./Balmorel/sc1/data/DE.inc)\n",
"DE.save()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## GUI for Generating Geographic .inc Files\n",
"\n",
"Will generate the necessary geographic files:\n",
"- CCCRRRAAA.inc\n",
"- CCC.inc\n",
"- RRR.inc\n",
"- AAA.inc\n",
"- CCCRRR.inc\n",
"- RRRAAA.inc"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"GUI.geofilemaker()"
]
}
],
"metadata": {
Expand All @@ -83,7 +107,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.11"
"version": "3.12.6"
}
},
"nbformat": 4,
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "pybalmorel"
version = "0.3.5"
version = "0.3.6"
maintainers = [
{ name="Mathias Berg Rosendal", email="[email protected]"},
{ name="Théodore Le Nalinec"},
Expand All @@ -17,7 +17,7 @@ classifiers = [
"Operating System :: OS Independent",
]
dependencies = ['pandas>=2.1.4', 'matplotlib>=3.9.0', 'geopandas>=0.14.4',
'gamsapi[transfer]>=45.0.0', 'ipywidgets>=8.1.3']
'gamsapi[transfer]>=45.0.0', 'ipywidgets>=8.1.3', 'eel>=0.17.0']

[project.urls]
Repository = "https://github.com/Mathias157/pybalmorel"
Expand Down
4 changes: 2 additions & 2 deletions src/pybalmorel/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from . import formatting, utils
from .classes import IncFile, MainResults, Balmorel
from .classes import IncFile, MainResults, Balmorel, GUI

__all__ = [IncFile, MainResults, Balmorel]
__all__ = [IncFile, MainResults, Balmorel, GUI]
28 changes: 27 additions & 1 deletion src/pybalmorel/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from matplotlib.axes import Axes
from .utils import symbol_to_df
from .interactive.interactive_functions import interactive_bar_chart
from .interactive.dashboard.eel_dashboard import interactive_geofilemaker
from .plotting.production_profile import plot_profile
from .plotting.maps_balmorel import plot_map

Expand Down Expand Up @@ -391,4 +392,29 @@ def load_incfiles(self,
model_db.run()

# Store the database (will take some minutes)
self.input_data[scenario] = model_db.get_out_db()
self.input_data[scenario] = model_db.get_out_db()


class GUI:
def __init__(self) -> None:
pass

# Interactive bar chart plotting
def bar_chart(self, MainResults_instance):
"""Interactive GUI to plot bar charts from MainResults
Args:
MainResults_instance (class): Loaded MainResults
Returns:
None: An interactive GUI is opened to plot bar charts
"""
return interactive_bar_chart(MainResults_instance)

def geofilemaker():
"""Opens a GUI to interactively generate necessary .inc files for Balmorel geography
Returns:
None: An interactive GUI to generate geographic .inc files
"""
return interactive_geofilemaker()
87 changes: 87 additions & 0 deletions src/pybalmorel/interactive/dashboard/eel_dashboard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#%%
import eel
import ast
from pybalmorel import IncFile
import pkg_resources
import os

# 1.0 Other functions
def get_wkdir():
return os.path.abspath('.')

# 1.1 Create .inc Files
def create_incfile(unique_processing):
"""The general wrapper for creating and saving .inc files,
because the creating of the IncFile class and saving it is the same everytime.
The unique processing of the .body content differs, however.
Args:
unique_processing (func): The unique processing per case
**incfile_kwargs: Keyword arguments to pass to IncFile
"""
def wrapper(**kwargs):
inc_file = IncFile(name=kwargs['name'], prefix=kwargs['prefix'],
suffix=kwargs['suffix'], path=kwargs['path'])
unique_processing(inc_file, kwargs['geo_nodes'])
inc_file.save()
return wrapper

## 1.1.1 CCC, RRR or AAA
@create_incfile
def create_sets(inc_file: IncFile, geo_nodes_layer2: dict):
inc_file.body += '\n'.join(list(geo_nodes_layer2.keys()))

## 1.1.2 CCCRRRAAA
@create_incfile
def create_CCCRRRAAA(inc_file: IncFile, geo_nodes: dict):
for key in geo_nodes.keys():
inc_file.body += '\n* %s:\n' % key.capitalize()
inc_file.body += '\n'.join(geo_nodes[key].keys())

## 1.1.3 CCCRRR or RRRAAA
@create_incfile
def create_setconnection(inc_file: IncFile, geo_nodes_layer1: dict):
for node in geo_nodes_layer1.keys():
if len(geo_nodes_layer1[node]) != 0:
inc_file.body += f'\n{node} . '
inc_file.body += f'\n{node} . '.join(geo_nodes_layer1[node])


# 1.2 Create .inc Files
def create_incfiles(output: str, path: str):
geo_nodes = ast.literal_eval(output) # Convert output to dict
prefix = """SET CCC(CCCRRRAAA) 'All countries'
/\n"""
create_sets(geo_nodes=geo_nodes['countries'], name='CCC', prefix=prefix, suffix="\n/;", path=path)

prefix = """SET RRR(CCCRRRAAA) 'All regions'
/\n"""
create_sets(geo_nodes=geo_nodes['regions'], name='RRR', prefix=prefix, suffix="\n/;", path=path)

prefix = """SET AAA(CCCRRRAAA) 'All areas'
/\n"""
create_sets(geo_nodes=geo_nodes['areas'], name='AAA', prefix=prefix, suffix="\n/;", path=path)

prefix = """* All sets that are related to Geographical resolution
SET CCCRRRAAA 'All geographical entities (CCC + RRR + AAA)'
/"""
create_CCCRRRAAA(geo_nodes=geo_nodes, name='CCCRRRAAA', prefix=prefix, suffix="\n/;", path=path)

prefix="""SET CCCRRR(CCC,RRR) "Regions in countries"
/"""
create_setconnection(geo_nodes=geo_nodes['countries'], name='CCCRRR', prefix=prefix, suffix="\n/;", path=path)

prefix="""SET RRRAAA(RRR,AAA) "Areas in regions"
/"""
create_setconnection(geo_nodes=geo_nodes['regions'], name='RRRAAA', prefix=prefix, suffix="\n/;", path=path)

def interactive_geofilemaker():

# Get working directory and package directory
static_path = pkg_resources.resource_filename(__name__, 'static')
index_path = pkg_resources.resource_filename(__name__, 'static/index.html')

eel.init(static_path)
eel.expose(get_wkdir)
eel.expose(create_incfiles)
eel.start(index_path)
Loading

0 comments on commit eb8ded0

Please sign in to comment.