Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Components.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ def BlockModelAdapter(cls, label="", specific_behavior=""):
args = GetArgs(cls)

### find if there is filename param on the constructor and if there is no extention
L = [os.path.isabs(str(a)) for a in list(args.values())]
L = [os.path.isabs(str(a)) or str(a)=='result' for a in list(args.values())]
filename_without_ext_flag = L.index(True) if True in L else -1
### if there is a filename and if there is no extention -> its a to disk like object
disk_model = filename_without_ext_flag >= 0 and not os.path.splitext(list(args.values())[filename_without_ext_flag])[-1] != ''
Expand Down
2 changes: 1 addition & 1 deletion Container.py
Original file line number Diff line number Diff line change
Expand Up @@ -3633,7 +3633,7 @@ def __setstate__(self, state):
finally:
clsmembers = inspect.getmembers(module, inspect.isclass)
names = [t[0] for t in clsmembers]

### if model inherite of ScopeGUI, it requires to redefine the class with the ScopeGUI class
if 'To_Disk' in names or 'MessagesCollector' in names:
new_class = DiskGUI
Expand Down
10 changes: 5 additions & 5 deletions Domain/Collector/MessagesCollector.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ class MessagesCollector(DomainBehavior):
"""

###
def __init__(self, fileName = None, ext = '.dat', comma = ""):
def __init__(self, fileName = "result", ext = '.dat', comma = ""):
""" Constructor.

@param fileName : name of output fileName
@param ext : output file extension
@param comma : comma separated
@param fileName: name of output fileName
@param ext: output file extension
@param comma: comma separated
"""
DomainBehavior.__init__(self)

### a way to overcome the random initialization of the fileNam attr directly in the param list of the constructor!
fileName = fileName if fileName is not None else os.path.join(os.getcwd(),"out","result%d"%random.randint(1,100))
fileName = fileName if fileName!= 'result' else os.path.join(os.getcwd(),"out","result%d"%random.randint(1,100))

# local copy
self.fileName = fileName
Expand Down
15 changes: 9 additions & 6 deletions Domain/Collector/To_Disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,20 @@ class To_Disk(QuickScope):
"""

###
def __init__(self, fileName = os.path.join(os.getcwd(),"result%d"%random.randint(1,100)), eventAxis = False, comma = " ", ext = '.dat', col = 0):
def __init__(self, fileName = "result", eventAxis = False, comma = " ", ext = '.dat', col = 0):
""" Constructor.

@param fileName : Name of output fileName
@param eventAxis : Flag to plot depending events axis
@param comma : Comma symbol
@param ext : Output file extension
@param col : Considered column
@param fileName: Name of output fileName
@param eventAxis: Flag to plot depending events axis
@param comma: Comma symbol
@param ext: Output file extension
@param col: Considered column
"""
QuickScope.__init__(self)

### a way to overcome the random initialization of the fileNam attr directly in the param list of the constructor!
fileName = fileName if fileName!= 'result' else os.path.join(os.getcwd(),"out","result%d"%random.randint(1,100))

# local copy
self.fileName = fileName
self.comma = comma
Expand Down
17 changes: 10 additions & 7 deletions Domain/Generator/RandomGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ class RandomGenerator(DomainBehavior):
@version: 1.0
"""

def __init__(self, minValue=0, maxValue=10, minStep=1, maxStep=1, start=0):
def __init__(self, minValue=0, maxValue=10, minStep=1, maxStep=1, start=0, choice=[]):
""" Constructor.

@param minValue : minimum value
@param maxValue : maximum value
@param minStep : minimum step
@param maxStep : maximum step
@param start : time start
@param minValue: minimum value
@param maxValue: maximum value
@param minStep: minimum step
@param maxStep: maximum step
@param start: time start
@param choice: list of items

"""
DomainBehavior.__init__(self)
Expand All @@ -32,6 +33,8 @@ def __init__(self, minValue=0, maxValue=10, minStep=1, maxStep=1, start=0):
self.maxValue = maxValue
self.minStep = minStep
self.maxStep = maxStep
self.choice = choice

self.msg = Message(None, None)

def outputFnc(self):
Expand All @@ -41,7 +44,7 @@ def outputFnc(self):
portsToSend = random.sample(self.OPorts, numberMessage) # The port with number message

for port in portsToSend:
value = random.randint(self.minValue, self.maxValue)
value = random.randint(self.minValue, self.maxValue) if self.choice else random.choice(self.choice)
self.msg.value = [value, 0.0, 0.0]
self.msg.time = self.timeNext
### adapted with PyPDEVS
Expand Down
143 changes: 92 additions & 51 deletions plugins/state_trajectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

"""
Authors: L. Capocchi (capocchi@univ-corse.fr)
Date: 08/11/2014
Date: 30/10/2020
Description:
Plot the state trajectory of model.
Based on transition function decorator.
Expand All @@ -14,30 +14,85 @@
### ----------------------------------------------------------

### at the beginning to prevent with statement for python version <=2.5

from __future__ import with_statement

import sys
import wx
import os
import inspect
import subprocess
import importlib

required_libs = ['matplotlib']

for lib_name in required_libs:
try:
importlib.import_module(lib_name)
except:
subprocess.run(f'pip install {lib_name}'.split())

#import matplotlib.pyplot as plt

import wx.lib.agw.aui as aui
#import wx.lib.mixins.inspection as wit

import matplotlib as mpl
from matplotlib.backends.backend_wxagg import (
FigureCanvasWxAgg as FigureCanvas,
NavigationToolbar2WxAgg as NavigationToolbar)

class PlotPanel(wx.Panel):
def __init__(self, parent, id=-1, dpi=None, **kwargs):
wx.Panel.__init__(self, parent, id=id, **kwargs)
self.figure = mpl.figure.Figure(dpi=dpi, figsize=(2, 2))
self.canvas = FigureCanvas(self, -1, self.figure)
self.toolbar = NavigationToolbar(self.canvas)
self.toolbar.Realize()

sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas, 1, wx.EXPAND)
sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
self.SetSizer(sizer)
self.SetAutoLayout(True)

class PlotNotebook(wx.Panel):
def __init__(self, parent, id=-1):
wx.Panel.__init__(self, parent, id=id)
self.nb = aui.AuiNotebook(self)
sizer = wx.BoxSizer()
sizer.Add(self.nb, 1, wx.EXPAND)
self.SetSizer(sizer)
self.SetAutoLayout(True)

def add(self, name="plot"):
page = PlotPanel(self.nb)
self.nb.AddPage(page, name)
return page.figure

# to send event
try:
from pubsub import pub
except Exception:
sys.stdout.write('Last version for Python2 is PyPubSub 3.3.0 \n pip install PyPubSub==3.3.0')
sys.exit()

from PluginManager import PluginManager
from Container import Block, CodeBlock, ContainerBlock
from Utilities import install_and_import

ID_SHAPE = wx.NewIdRef()

def log(func):
def wrapped(*args, **kwargs):

try:
#print "Entering: [%s] with parameters %s" % (func.__name__, args)
try:

### DEVS instance
devs = func.__self__

### condition
cond = hasattr(devs, 'state') and 'status' in list(devs.state.keys())
cond = hasattr(devs, 'state') and 'status' in devs.state.keys()


### is DEVS model has no state_trajectory attribute, we create it only for init!
Expand Down Expand Up @@ -74,7 +129,7 @@ def state_trajectory_decorator(inst):
'''

for name, m in inspect.getmembers(inst, inspect.isfunction)+inspect.getmembers(inst, inspect.ismethod):
if name in list(inst.getBlockModel().state_trajectory.values()):
if name in inst.getBlockModel().state_trajectory.values():
setattr(inst, name, log(m))

return inst
Expand Down Expand Up @@ -105,7 +160,7 @@ def GetFlatShapesList(diagram,L):
return L

def PlotStateTrajectory(m):
""" Plot the state trajectory of m model
""" Plot the state trajectory of m model.
"""

if m:
Expand All @@ -121,45 +176,31 @@ def PlotStateTrajectory(m):
y = []

### adapted to PyPDEVS
times_lst = [a[0] if isinstance(a, tuple) else a for a in list(st.keys())]
times_lst = list(map(lambda a: a[0] if isinstance(a, tuple) else a, st.keys()))

states_lst = [states.index(st[k]) for k in st]

items = list(zip(times_lst, states_lst))

items = zip(times_lst, states_lst)
sorted_items = sorted(items, key=lambda x: (x[0], x[1]))

x, y = list(zip(*sorted_items))
x, y = zip(*sorted_items)

assert len(x)==len(y)

#for plotting
if install_and_import('matplotlib'):
import matplotlib.pyplot as plt

fig = plt.figure()

### change the title of the plot
#fig.suptitle('%s State Trajectory'%label, fontsize=17)

### change the title of the plot window
fig.canvas.set_window_title('%s State Trajectory'%label)

### changes the color of the space around the plot
fig.patch.set_facecolor('white')

### change the axis label
plt.xlabel('time', fontsize=16)
plt.ylabel('state', fontsize=16)

ax = fig.add_subplot(111)
### changes the color of the space inside the plot
ax.patch.set_facecolor('white')

ax.step(x, y)
plt.yticks(list(range(len(states))), states, size='small')

plt.show()
frame = wx.Frame(None, -1, 'Plotter')
plotter = PlotNotebook(frame)
axes1 = plotter.add('%s State Trajectory'%label).gca()
axes1.set_yticks(range(len(states)))
axes1.set_yticklabels(states)
axes1.set_xlabel('time',fontsize=16)
axes1.set_ylabel('state',fontsize=16)
axes1.plot(x, y)

#axes2 = plotter.add('figure 2').gca()
#axes2.plot([1, 2, 3, 4, 5], [2, 1, 4, 2, 3])

frame.Show()

else:
dial = wx.MessageDialog(None,
Expand Down Expand Up @@ -205,7 +246,7 @@ def start_state_trajectory(*args, **kwargs):
master = kwargs['master']
parent = kwargs['parent']

if not pluginmanager.is_enable('start_activity_tracking'):
if not PluginManager.is_enable('start_activity_tracking'):
for devs in GetFlatDEVSList(master, []):
block = devs.getBlockModel()
if hasattr(block, 'state_trajectory'):
Expand Down Expand Up @@ -249,10 +290,10 @@ def Config(parent):
master = None

frame = wx.Frame(parent,
wx.ID_ANY,
title = _('State Trajectory Plotting'),
style = wx.DEFAULT_FRAME_STYLE | wx.CLIP_CHILDREN)

panel = wx.Panel(frame)
style = wx.DEFAULT_FRAME_STYLE | wx.CLIP_CHILDREN | wx.STAY_ON_TOP)
panel = wx.Panel(frame, wx.ID_ANY)

lst_1 = GetFlatShapesList(diagram,[])
lst_2 = ('confTransition', 'extTransition', 'intTransition')
Expand All @@ -261,15 +302,15 @@ def Config(parent):
hbox = wx.BoxSizer(wx.HORIZONTAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)

st = wx.StaticText(panel, wx.NewIdRef(), _("Select models and functions:"), (10,10))
st = wx.StaticText(panel, wx.ID_ANY, _("Select models and functions:"), (10,10))

cb1 = wx.CheckListBox(panel, wx.NewIdRef(), (10, 30), wx.DefaultSize, lst_1, style=wx.LB_SORT)
cb2 = wx.CheckListBox(panel, wx.NewIdRef(), (10, 30), wx.DefaultSize, lst_2)
cb1 = wx.CheckListBox(panel, wx.ID_ANY, (10, 30), wx.DefaultSize, lst_1, style=wx.LB_SORT)
cb2 = wx.CheckListBox(panel, wx.ID_ANY, (10, 30), wx.DefaultSize, lst_2)

selBtn = wx.Button(panel, wx.ID_SELECTALL)
desBtn = wx.Button(panel, wx.NewIdRef(), _('Deselect All'))
desBtn = wx.Button(panel, wx.ID_ANY, _('Deselect All'))
okBtn = wx.Button(panel, wx.ID_OK)
#reportBtn = wx.Button(panel, wx.NewIdRef(), _('Report'))
#reportBtn = wx.Button(panel, wx.ID_ANY, _('Report'))

hbox2.Add(cb1, 1, wx.EXPAND, 5)
hbox2.Add(cb2, 1, wx.EXPAND, 5)
Expand All @@ -292,14 +333,14 @@ def Config(parent):
block=diagram.GetShapeByLabel(cb1.GetString(index))
if hasattr(block,'state_trajectory'):
L1.append(index)
L2[block.label] = list(block.state_trajectory.keys())
L2[block.label] = block.state_trajectory.keys()

if L1:
cb1.SetCheckedItems(L1)
### tout les block on la meme liste de function active pour le trace, donc on prend la première
### tout les blocks on la meme liste de function active pour le trace, donc on prend la premi�re
cb2.SetCheckedItems(list(L2.values())[0])

### ckeck delta_ext and delta_int
### ckeck par defaut delta_ext et delta_int
if L2 == {}:
cb2.SetCheckedItems([1,2])

Expand All @@ -316,7 +357,7 @@ def OnPlot(event):
def OnSelectAll(evt):
""" Select All button has been pressed and all plug-ins are enabled.
"""
cb1.SetCheckedItems(list(range(cb1.GetCount())))
cb1.SetCheckedItems(range(cb1.GetCount()))

def OnDeselectAll(evt):
""" Deselect All button has been pressed and all plugins are disabled.
Expand Down