From cad8fe5cd08a23327d88b0422aa794402698a09f Mon Sep 17 00:00:00 2001 From: pgleeson Date: Fri, 19 Apr 2024 14:05:22 +0100 Subject: [PATCH 1/5] Quick & dirty implementation of running xpp files in xppaut & plotting results --- pyneuroml/xppaut/__init__.py | 66 ++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/pyneuroml/xppaut/__init__.py b/pyneuroml/xppaut/__init__.py index 6c9f4822..c03ad7c7 100644 --- a/pyneuroml/xppaut/__init__.py +++ b/pyneuroml/xppaut/__init__.py @@ -6,6 +6,7 @@ import typing import argparse import logging +import os XPP_TIME = 'xpp_time' LEMS_TIME = 't' @@ -592,6 +593,55 @@ def main(args=None): cli(a=args) +def run_xpp_file(filename, plot): + import subprocess as sp + cmds = ['%s/xppaut'%os.environ["XPP_HOME"],filename, '-silent'] + cwd = os.getcwd() + try: + ret_string = sp.check_output( + cmds, cwd=cwd, shell=False, stderr=sp.STDOUT + ) + logger.info( + "Commands: %s completed successfully" % (cmds) + ) + if isinstance(ret_string, bytes): + ret_string = ret_string.decode("utf-8") # For Python 3... + + except sp.CalledProcessError as err: + logger.error( + "CalledProcessError running commands: %s in %s (return code: %s), output:\n%s" + % (cmds, cwd, err.returncode, err.output), + ) + raise err + except Exception as err: + logger.info( + "Error running commands: %s in (%s)!" % (cmds, cwd) + ) + logger.info("Error: %s" % (err)) + raise err + + if plot: + from pyneuroml.pynml import reload_standard_dat_file + result_file = 'output.dat' + data, indeces = reload_standard_dat_file(result_file) + logger.info('Loading %s with %s'%(data, indeces)) + ts = [] + xs = [] + labels = [] + for i in indeces: + ts.append(data['t']) + xs.append(data[i]) + labels.append(i) + + from pyneuroml.plot.Plot import generate_plot + ax = generate_plot(ts, xs, + "Data from %s after running %s"%(result_file, filename), # Title + labels=labels, + xaxis="Time (?)", # x axis legend + yaxis="??", # y axis legend + show_plot_already=True, # Show or wait for plt.show()? + legend_position = "bottom center", + ) # Save figure def cli(a: typing.Optional[typing.Any] = None, **kwargs: str): """Main cli caller method""" @@ -608,19 +658,29 @@ def cli(a: typing.Optional[typing.Any] = None, **kwargs: str): lems_model_id = file_path.replace('.ode','').split('/')[-1] lems_model_file = file_path.replace('.ode','.model.xml') + if a.run and not a.lems and not a.xpp and not a.brian2: + + logger.info("Running %s with XPP (plotting: %s)..." % (a.ode_filename, a.plot)) + + run_xpp_file(a.ode_filename, a.plot) + + if a.lems: lems_filename = to_lems(parsed_data, lems_model_id, lems_model_file) logger.info("Generated LEMS file: %s" % lems_filename) if a.run: logger.info("Running %s with jNeuroML (plotting: %s)..." % (lems_filename, a.plot)) + from pyneuroml.runners import run_lems_with_jneuroml run_lems_with_jneuroml(lems_filename, nogui=True, plot=a.plot, verbose=True, load_saved_data=True) if a.xpp: - to_xpp(parsed_data, file_path.replace('.ode','_2.ode')) - if a.run or a.plot: - raise NotImplementedError("Running XPP not yet implemented!") + new_xppfile = file_path.replace('.ode','_2.ode') + to_xpp(parsed_data, new_xppfile) + + if a.run: + run_xpp_file(new_xppfile, a.plot) if a.brian2: to_brian2(parsed_data, file_path.replace('.ode','_brian2.py')) From 95f5e14585ab118e687169c4cef3aff2c67bb8d2 Mon Sep 17 00:00:00 2001 From: pgleeson Date: Fri, 19 Apr 2024 15:49:49 +0100 Subject: [PATCH 2/5] Improved xpp handling --- .gitignore | 2 ++ pyneuroml/xppaut/__init__.py | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 9b703336..0fd85fa8 100644 --- a/.gitignore +++ b/.gitignore @@ -173,3 +173,5 @@ arm64 /pyneuroml/xppaut/report.txt /examples/test_data/xppaut/fhn_2.ode /examples/test_data/xppaut/fhn_brain.py +/examples/test_data/xppaut/nca_2.ode +/examples/test_data/xppaut/wc_2.ode diff --git a/pyneuroml/xppaut/__init__.py b/pyneuroml/xppaut/__init__.py index c03ad7c7..101123e1 100644 --- a/pyneuroml/xppaut/__init__.py +++ b/pyneuroml/xppaut/__init__.py @@ -80,6 +80,7 @@ def parse_script(file_path): elif line.startswith(('number', 'p', 'par', 'param')): params = line.replace('number ', '').replace('par ', '').replace('p ', '').replace('param ', '') # Skip the first word ('number', 'p', 'param' or 'par') for pp1 in params.split(','): + pp1 = pp1.replace(' = ','=').replace('= ','=').replace(' =','=') # better solution required... for pp2 in pp1.split(' '): if len(pp2)>0: key, value = pp2.split('=') @@ -190,7 +191,7 @@ def to_xpp(data, new_xpp_filename): xpp_ode+='\n# Parameters\n' for k,v in data["parameters"].items(): if not k in INBUILT.keys(): - xpp_ode += f'{k} = {v}\n' + xpp_ode += f'par {k} = {v}\n' xpp_ode+='\n# Functions\n' for k,v in data["functions"].items(): @@ -621,17 +622,24 @@ def run_xpp_file(filename, plot): raise err if plot: + + parsed_data = parse_script(filename) + from pyneuroml.pynml import reload_standard_dat_file result_file = 'output.dat' data, indeces = reload_standard_dat_file(result_file) - logger.info('Loading %s with %s'%(data, indeces)) + logger.info('Loading data: %s'%(data.keys())) ts = [] xs = [] labels = [] + tds = list(parsed_data['time_derivatives'].keys()) + cdvs = ['%s??'%c for c in parsed_data['conditional_derived_variables'].keys()] + outputs = tds+cdvs + logger.info('Loading data: %s, assuming these represent %s (%i values)'%(data.keys(),outputs, len(outputs))) for i in indeces: ts.append(data['t']) xs.append(data[i]) - labels.append(i) + labels.append(outputs[i] if i < len(outputs) else '???') from pyneuroml.plot.Plot import generate_plot ax = generate_plot(ts, xs, @@ -640,8 +648,7 @@ def run_xpp_file(filename, plot): xaxis="Time (?)", # x axis legend yaxis="??", # y axis legend show_plot_already=True, # Show or wait for plt.show()? - legend_position = "bottom center", - ) # Save figure + ) def cli(a: typing.Optional[typing.Any] = None, **kwargs: str): """Main cli caller method""" From 537dd0092cda0a912fdab45c64882af6a431f77d Mon Sep 17 00:00:00 2001 From: pgleeson Date: Mon, 29 Apr 2024 17:49:18 +0100 Subject: [PATCH 3/5] Indeces -> indices --- pyneuroml/pynml.py | 8 ++++---- pyneuroml/xppaut/__init__.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pyneuroml/pynml.py b/pyneuroml/pynml.py index af2fc3ee..560f52a0 100644 --- a/pyneuroml/pynml.py +++ b/pyneuroml/pynml.py @@ -897,7 +897,7 @@ def reload_standard_dat_file(file_name: str) -> typing.Tuple[dict, list]: """ with open(file_name) as dat_file: data = {} # type: dict - indeces = [] # type: list + indices = [] # type: list for line in dat_file: words = line.split() @@ -905,13 +905,13 @@ def reload_standard_dat_file(file_name: str) -> typing.Tuple[dict, list]: data["t"] = [] for i in range(len(words) - 1): data[i] = [] - indeces.append(i) + indices.append(i) data["t"].append(float(words[0])) for i in range(len(words) - 1): data[i].append(float(words[i + 1])) - logger.info("Loaded data from %s; columns: %s" % (file_name, indeces)) - return data, indeces + logger.info("Loaded data from %s; columns: %s" % (file_name, indices)) + return data, indices def evaluate_component(comp_type, req_variables={}, parameter_values={}): diff --git a/pyneuroml/xppaut/__init__.py b/pyneuroml/xppaut/__init__.py index 101123e1..db347e2a 100644 --- a/pyneuroml/xppaut/__init__.py +++ b/pyneuroml/xppaut/__init__.py @@ -594,7 +594,7 @@ def main(args=None): cli(a=args) -def run_xpp_file(filename, plot): +def run_xpp_file(filename, plot, show_plot_already=True): import subprocess as sp cmds = ['%s/xppaut'%os.environ["XPP_HOME"],filename, '-silent'] cwd = os.getcwd() @@ -627,7 +627,7 @@ def run_xpp_file(filename, plot): from pyneuroml.pynml import reload_standard_dat_file result_file = 'output.dat' - data, indeces = reload_standard_dat_file(result_file) + data, indices = reload_standard_dat_file(result_file) logger.info('Loading data: %s'%(data.keys())) ts = [] xs = [] @@ -636,7 +636,7 @@ def run_xpp_file(filename, plot): cdvs = ['%s??'%c for c in parsed_data['conditional_derived_variables'].keys()] outputs = tds+cdvs logger.info('Loading data: %s, assuming these represent %s (%i values)'%(data.keys(),outputs, len(outputs))) - for i in indeces: + for i in indices: ts.append(data['t']) xs.append(data[i]) labels.append(outputs[i] if i < len(outputs) else '???') @@ -647,7 +647,7 @@ def run_xpp_file(filename, plot): labels=labels, xaxis="Time (?)", # x axis legend yaxis="??", # y axis legend - show_plot_already=True, # Show or wait for plt.show()? + show_plot_already=show_plot_already, # Show or wait for plt.show()? ) def cli(a: typing.Optional[typing.Any] = None, **kwargs: str): From 49f9de43b96534f45f2ba4db1f3728263a3a3edd Mon Sep 17 00:00:00 2001 From: pgleeson Date: Tue, 30 Apr 2024 18:34:50 +0100 Subject: [PATCH 4/5] Updates to xpp running/plotting --- pyneuroml/utils/__init__.py | 5 ++++ pyneuroml/xppaut/__init__.py | 46 +++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/pyneuroml/utils/__init__.py b/pyneuroml/utils/__init__.py index 85dbb784..3ced389b 100644 --- a/pyneuroml/utils/__init__.py +++ b/pyneuroml/utils/__init__.py @@ -327,6 +327,11 @@ def get_state_color(s: str) -> str: if s.startswith("u"): col = "#880088" + if '/' in s: # e.g. for sub gates + from pyneuroml.utils.plot import get_next_hex_color + col = get_next_hex_color() + + return col diff --git a/pyneuroml/xppaut/__init__.py b/pyneuroml/xppaut/__init__.py index db347e2a..e0b58f0e 100644 --- a/pyneuroml/xppaut/__init__.py +++ b/pyneuroml/xppaut/__init__.py @@ -594,7 +594,7 @@ def main(args=None): cli(a=args) -def run_xpp_file(filename, plot, show_plot_already=True): +def run_xpp_file(filename, plot, show_plot_already=True, plot_separately={}): import subprocess as sp cmds = ['%s/xppaut'%os.environ["XPP_HOME"],filename, '-silent'] cwd = os.getcwd() @@ -629,26 +629,44 @@ def run_xpp_file(filename, plot, show_plot_already=True): result_file = 'output.dat' data, indices = reload_standard_dat_file(result_file) logger.info('Loading data: %s'%(data.keys())) - ts = [] - xs = [] - labels = [] + default_figure = "Data loaded from: %s after running %s"%(result_file, filename) # Title + ts = {default_figure:[]} + xs = {default_figure:[]} + labels = {default_figure:[]} + for new_fig in plot_separately: + ts[new_fig] = [] + xs[new_fig] = [] + labels[new_fig] = [] + tds = list(parsed_data['time_derivatives'].keys()) cdvs = ['%s??'%c for c in parsed_data['conditional_derived_variables'].keys()] outputs = tds+cdvs logger.info('Loading data: %s, assuming these represent %s (%i values)'%(data.keys(),outputs, len(outputs))) for i in indices: - ts.append(data['t']) - xs.append(data[i]) - labels.append(outputs[i] if i < len(outputs) else '???') + label = outputs[i] if i < len(outputs) else '???' + + fig = default_figure + for new_fig in plot_separately: + if label in plot_separately[new_fig]: + fig = new_fig + ts[fig].append(data['t']) + xs[fig].append(data[i]) + labels[fig].append(label) from pyneuroml.plot.Plot import generate_plot - ax = generate_plot(ts, xs, - "Data from %s after running %s"%(result_file, filename), # Title - labels=labels, - xaxis="Time (?)", # x axis legend - yaxis="??", # y axis legend - show_plot_already=show_plot_already, # Show or wait for plt.show()? - ) + axes = {} + for fig_title in ts: + + ax = generate_plot(ts[fig_title], xs[fig_title], + title = fig_title, + labels=labels[fig_title], + xaxis="Time (?)", # x axis legend + yaxis="??", # y axis legend + show_plot_already=show_plot_already, # Show or wait for plt.show()? + ) + axes[fig_title] = ax + return axes + def cli(a: typing.Optional[typing.Any] = None, **kwargs: str): """Main cli caller method""" From e309515a302bcb768db4e6b8a18f9332bfc065aa Mon Sep 17 00:00:00 2001 From: pgleeson Date: Tue, 30 Apr 2024 18:35:53 +0100 Subject: [PATCH 5/5] Updates to pynml-channelanalysis to allow plotting subgates --- pyneuroml/analysis/LEMS_Test_TEMPLATE.xml | 4 ++-- pyneuroml/analysis/NML2ChannelAnalysis.py | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pyneuroml/analysis/LEMS_Test_TEMPLATE.xml b/pyneuroml/analysis/LEMS_Test_TEMPLATE.xml index b131a1c7..5609ec96 100644 --- a/pyneuroml/analysis/LEMS_Test_TEMPLATE.xml +++ b/pyneuroml/analysis/LEMS_Test_TEMPLATE.xml @@ -139,10 +139,10 @@ #end## #foreach ($g in $gates)## - + - + #end## diff --git a/pyneuroml/analysis/NML2ChannelAnalysis.py b/pyneuroml/analysis/NML2ChannelAnalysis.py index 7bb3c03c..66cd6f1f 100644 --- a/pyneuroml/analysis/NML2ChannelAnalysis.py +++ b/pyneuroml/analysis/NML2ChannelAnalysis.py @@ -469,9 +469,17 @@ def get_channel_gates( "gate_hh_rates", "gate_hh_tau_infs", "gate_hh_instantaneouses", + "gate_fractionals", ]: if hasattr(channel, gates): - channel_gates += [g.id for g in getattr(channel, gates)] + if gates == "gate_fractionals": + for g in getattr(channel, gates): + for sg in g.sub_gates: + channel_gates.append(str('%s/%s'%(g.id, sg.id))) + else: + for g in getattr(channel, gates): + channel_gates.append(g.id) + #print('- Found gates: %s'%channel_gates) return channel_gates