Skip to content

Commit

Permalink
interactive function setter
Browse files Browse the repository at this point in the history
  • Loading branch information
pjamesjoyce committed Feb 16, 2017
1 parent 5d5fd43 commit 3cd9f69
Show file tree
Hide file tree
Showing 17 changed files with 1,636 additions and 317 deletions.
1,414 changes: 1,414 additions & 0 deletions OrderedDict_database_export.csv

Large diffs are not rendered by default.

Binary file added ParameterSet_15-02-17.xlsx
Binary file not shown.
Binary file added ParameterSet_15-02-17v2.xlsx
Binary file not shown.
Binary file added ParameterSet_OrderedDict_input_file.xlsx
Binary file not shown.
Binary file modified lcopt/__pycache__/io.cpython-35.pyc
Binary file not shown.
Binary file not shown.
Binary file modified lcopt/__pycache__/model.cpython-35.pyc
Binary file not shown.
4 changes: 2 additions & 2 deletions lcopt/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def get_exchange_from_database(name, database):
return None

# partial function to get the item from the default database
get_exchange = partial(get_exchange_from_database, database=defaultDatabase)
#get_exchange = partial(get_exchange_from_database, database=defaultDatabase)

# check if something already exists
def exists_in_specific_database(code, database):
Expand All @@ -33,7 +33,7 @@ def exists_in_specific_database(code, database):
return False

# partial function to find an item in the default database
exists_in_database = partial(exists_in_specific_database, database = defaultDatabase)
#exists_in_database = partial(exists_in_specific_database, database = defaultDatabase)

# get an item from the database in the exchange format
def get_exchange_name_from_database(code, database):
Expand Down
112 changes: 112 additions & 0 deletions lcopt/ipython_interactive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from ipywidgets import widgets
from IPython.display import display

class IFS():
def __init__(self, modelInstance):
self.modelInstance = modelInstance
self.db = self.modelInstance.database['items']
self.processes = list(filter(lambda x:self.db[x]['type'] == 'process', self.db))


self.process_options = {self.db[x]['name'] : x for x in self.processes}
self.dropdownProcess = widgets.Dropdown(description='Choose a process', options=self.process_options)
self.dropdownInput = widgets.Dropdown(description='Choose an input')

self.textParameterFunction = widgets.Text(description="Enter function here")
self.buttonSave = widgets.Button(description='Save')

self.defaultProcess = self.process_options[list(self.process_options.keys())[0]]
self.chosenProcess = self.defaultProcess
self.chosenProcessOutputCode = self.output_code(self.chosenProcess)
self.chosenInput = None
self.chosenParameterId = None

self.dropdownProcess.observe(self.handle_event)
self.dropdownInput.observe(self.handle_event)
self.textParameterFunction.observe(self.handle_event)
self.buttonSave.on_click(self.button_click)

self.dropdownInput.options = self.get_input_list(self.defaultProcess)

display(self.dropdownProcess, self.dropdownInput,self.textParameterFunction, self.buttonSave)

def output_code(self, process_id):

exchanges = self.modelInstance.database['items'][process_id]['exchanges']

production_filter = lambda x:x['type'] == 'production'

code = list(filter(production_filter, exchanges))[0]['input'][1]

return code


def get_parameter_id(self):
#print('getting parameter id')
try:
code_tuple = (self.chosenInput[1], self.chosenProcessOutputCode)
#print (code_tuple)
self.chosenParameterId = self.modelInstance.parameter_map[code_tuple]
#print(self.chosenParameterId)

return self.chosenParameterId
except:
print('not working')


def get_input_list(self, process = None):
if process == None:
process = self.chosenProcess

exchanges = self.db[process]['exchanges']
input_filter = lambda x:x['type']=='technosphere'
inputs = list(filter(input_filter, exchanges))
input_codes = [x['input'] for x in inputs]
input_names = [self.modelInstance.get_name(x[1]) for x in input_codes]
new_options = dict(zip(input_names, input_codes))
return new_options

def handle_event(self, event):
if event['type'] == 'change' and event['name'] == 'value':
if event['owner'] == self.dropdownProcess:
#print ('Event from dropdownProcess')
#print ('setting chosenProcess to {}'.format(event['new']))
self.chosenProcess = event['new']
self.chosenProcessOutputCode = self.output_code(event['new'])

#self.dropdownProcess.disabled=True

new_options = self.get_input_list()

self.dropdownInput.options=new_options

#display(self.dropdownInput)
elif event['owner'] == self.dropdownInput:
#print ('Event from dropdownInput')
#print ('setting chosenInput to {}'.format(event['new']))
self.chosenInput = event['new']

parameter_id = self.get_parameter_id()
try:
self.textParameterFunction.description = parameter_id
self.textParameterFunction.disabled=False
except:
self.textParameterFunction.description = "parameter_id"
self.textParameterFunction.disabled=True

#elif event['owner'] == self.textParameterFunction:
#print('event from textParameterFunction')
#print(event)

def button_click(self, button):
new_function = self.textParameterFunction.value
parameter = self.modelInstance.params[self.chosenParameterId]
parameter['function'] = new_function

self.dropdownProcess.close()
self.dropdownInput.close()
self.textParameterFunction.close()
button.close()

print('Updated function for {} ({}) to be {}'.format(parameter['description'], self.chosenParameterId, new_function))

90 changes: 78 additions & 12 deletions lcopt/model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from lcopt.io import *
from lcopt.ipython_interactive import IFS
from functools import partial
from collections import OrderedDict
import numpy as np
Expand All @@ -7,6 +8,7 @@
import random
from copy import deepcopy
import pandas as pd
import xlsxwriter
from flask import Flask, request, render_template
import webbrowser
import warnings
Expand Down Expand Up @@ -113,7 +115,7 @@ def __init__(self, name = hex(random.getrandbits(128))[2:-1], load = None):
self.name = name

# set up the database, parameter dictionaries, the matrix and the names of the exchanges
self.database = {'items': {}, 'name': '{}_Database'.format(self.name)}
self.database = {'items': OrderedDict(), 'name': '{}_Database'.format(self.name)}
self.external_databases = []
self.params = OrderedDict()
self.ext_params = []
Expand Down Expand Up @@ -181,7 +183,7 @@ def create_product (self, name, location ='GLO', unit='kg', **kwargs):
"""create a new product with md5 hash id in the model instances database"""
new_product = item_factory(name=name, location=location, unit=unit, type='product', **kwargs)

if not exists_in_database(new_product['code']):
if not self.exists_in_database(new_product['code']):
self.add_to_database(new_product)
print ('{} added to database'.format(name))
return self.get_exchange(name)
Expand All @@ -197,7 +199,7 @@ def create_process(self, name, exchanges, location ='GLO', unit='kg'):
exc_name = e.pop('name', None)
exc_type = e.pop('type', None)

this_exchange = get_exchange(exc_name)
this_exchange = self.get_exchange(exc_name)

if this_exchange == None:
my_unit = e.pop('unit', unit)
Expand Down Expand Up @@ -286,6 +288,9 @@ def add_parameter(self, param_name, description = None, default = 0):
self.ext_params.append({'name':param_name, 'description': description, 'default': default})
else:
print('{} already exists - choose a different name'.format(param_name))

def edit_function(self):
function_editor = IFS(self)

def create_parameter_set(self):
p_set = OrderedDict()
Expand All @@ -298,16 +303,38 @@ def create_parameter_set(self):
print("{} is determined by a function".format(p[k]['description']))

for e in self.ext_params:
p_set['e_{}'.format(e[0])] = float(input("value for {} > ".format(e[1])))
p_set['{}'.format(e['name'])] = float(input("value for {} > ".format(e['description'])))

self.parameter_sets[p_set_name] = p_set


def generate_parameter_set_excel_file(self):
p_set = []
p_set_name = "ParameterSet_{}_input_file.xlsx".format(self.name)
p = self.params
for k in p.keys():
if p[k]['function'] == None:
p_set.append({'id':k, 'name': p[k]['description'], 'value': '', 'unit':p[k]['unit']})
else:
print("{} is determined by a function".format(p[k]['description']))

for e in self.ext_params:
p_set.append({'id':'{}'.format(e['name']), 'type':'external', 'name': e['description'], 'value': e['default'], 'unit':''})

df = pd.DataFrame(p_set)

writer = pd.ExcelWriter(p_set_name, engine='xlsxwriter')

df.to_excel(writer, sheet_name=self.name, columns = ['name', 'unit', 'id', 'value'],index= False, merge_cells = False)

return p_set_name

# convert parameter sets into matrices

def parse_function(self, function, parameter_set):

int_param_re_pattern = "(p_\d{1,}_\d{1,})"
ext_param_re_pattern = "(e_[\d\w_]{1,})"
ext_param_re_pattern = "([\d\w_]{1,})"

int_param_re = re.compile(int_param_re_pattern)
ext_param_re = re.compile(ext_param_re_pattern)
Expand Down Expand Up @@ -355,9 +382,9 @@ def list_parameters_as_df(self):

for i, e in enumerate(self.ext_params):
row = {}
row['id'] = e[0]
row['id'] = e['name']
row['coords'] = "n/a"
row['description'] = e[1]
row['description'] = e['description']
row['function'] = "n/a"

to_df.append(row)
Expand Down Expand Up @@ -429,6 +456,9 @@ def database_to_SimaPro_csv(self):

created_exchanges = []

project_input_params = []
project_calc_params = []

for k in processes:
item = db[k]

Expand All @@ -437,6 +467,13 @@ def database_to_SimaPro_csv(self):
current['id'] = (self.name.replace(" ", "") + "XXXXXXXX")[:8] + ('00000000000' + str(randint(1,99999999999)))[-11:]
current['unit'] = item['unit']
current['exchanges'] = []

process_params = []

production_filter = lambda x:x['type'] == 'production'

output_code = list(filter(production_filter, item['exchanges']))[0]['input'][1]


for e in item['exchanges']:

Expand All @@ -447,9 +484,14 @@ def database_to_SimaPro_csv(self):

formatted_name = self.get_name(this_code)
this_exchange['formatted_name'] = formatted_name

# TODO: Make the amount look for parameters
this_exchange['amount'] = e['amount']

param_key = (this_code, output_code)
#param_check = (formatted_name, item['name'])
this_param = self.parameter_map[param_key]

process_params.append(this_param)

this_exchange['amount'] = this_param #e['amount']

this_exchange['unit'] = self.get_unit(this_code)

Expand All @@ -461,6 +503,18 @@ def database_to_SimaPro_csv(self):
current['output_name']=name

created_exchanges.append(name)


#process parameters

for p in process_params:
if self.params[p]['function'] == None:
project_input_params.append({'name':p, 'comment':self.params[p]['description']})
else:
project_calc_params.append({'name':p, 'comment':self.params[p]['description'], 'formula':self.params[p]['function']})




csv_args['processes'].append(current)

Expand Down Expand Up @@ -511,6 +565,18 @@ def database_to_SimaPro_csv(self):

#print(csv_args)
#print(created_exchanges)

csv_args['project']={}

#NOTE - currently external parameters can only be constants

csv_args['project']['calculated_parameters']=project_calc_params

#add the external parameters to the input parameter list
for p in self.ext_params:
project_input_params.append({'name':p['name'], 'comment':p['description'], 'default':p['default']})

csv_args['project']['input_parameters']=project_input_params

env = Environment(
loader=PackageLoader('lcopt', 'templates'),
Expand Down Expand Up @@ -547,7 +613,7 @@ def parameter_setup():
print("{} is determined by a function".format(p[k]['description']))

for e in self.ext_params:
parameters.append({'id':'e_{}'.format(e[0]), 'type':'external', 'name': e[1], 'value': '', 'unit':'?'})
parameters.append({'id':'{}'.format(e['name']), 'type':'external', 'name': e['description'], 'value': e['default'], 'unit':'?'})

return render_template('index.html',
title = 'Parameter set',
Expand All @@ -573,7 +639,7 @@ def parameter_parsing():
shutdown_server()
return 'Server shutting down... Please close this tab'

if __name__ == 'lcopt_geo.model':
if __name__ == 'lcopt.model':
url = 'http://127.0.0.1:5000'
webbrowser.open_new(url)
app.run(debug=False)
2 changes: 1 addition & 1 deletion lcopt/templates/ProjectParameters.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Project Input parameters
{% for param in project.input_parameters %}{{param.name}} {{param.default}} Undefined 1 0 0 No {{param.comment}}
{% for param in project.input_parameters %}{{param.name}} {{param.default|default('1', true)}} Undefined 1 0 0 No {{param.comment}}
{% endfor %}
End

Expand Down
9 changes: 9 additions & 0 deletions lcopt/templates/sandbox.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
</head>
<body>
Hello World!
</body>
</html>
Empty file.

0 comments on commit 3cd9f69

Please sign in to comment.