Plots added

This commit is contained in:
anwinged 2012-04-29 07:18:17 +00:00
parent 6aefad8ab1
commit f5309c96e1
5 changed files with 263 additions and 42 deletions

View File

@ -13,8 +13,13 @@ ID_DUPLICATE_MODEL = wx.NewId()
ID_DUPLICATE_TREE = wx.NewId() ID_DUPLICATE_TREE = wx.NewId()
ID_DELETE_MODEL = wx.NewId() ID_DELETE_MODEL = wx.NewId()
ID_PROCESS_MODEL = wx.NewId() ID_PROCESS_MODEL = wx.NewId()
ID_SHOW_RESULT = wx.NewId() ID_SHOW_RESULT = wx.NewId()
ID_SHOW_PLOT = wx.NewId() ID_SHOW_PLOT = wx.NewId()
ID_ADD_PLOT = wx.NewId()
ID_ADD_LINE = wx.NewId()
ID_ABOUT = wx.NewId()
class TreeListCtrl(wx.gizmos.TreeListCtrl): class TreeListCtrl(wx.gizmos.TreeListCtrl):
@ -55,12 +60,13 @@ class MainFrame (wx.Frame):
self.m_user_models = TreeListCtrl(self, self.m_user_models = TreeListCtrl(self,
style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT
| wx.TR_EDIT_LABELS | wx.TR_ROW_LINES | wx.TR_MULTIPLE) | wx.TR_FULL_ROW_HIGHLIGHT | wx.TR_ROW_LINES | wx.TR_MULTIPLE)
self.m_user_models.SetMinSize(wx.Size(-1, 300)) self.m_user_models.SetMinSize(wx.Size(-1, 300))
self.m_user_models.AddColumn("Model name") self.m_user_models.AddColumn("Model name")
self.m_user_models.AddColumn("Status") self.m_user_models.AddColumn("Status")
self.m_user_models.AddColumn("Progress") self.m_user_models.AddColumn("Progress")
self.m_user_models.AddColumn("Comment") self.m_user_models.AddColumn("Comment")
self.m_user_models.SetMainColumn(0)
bSizer4.Add(self.m_user_models, 0, wx.ALL | wx.EXPAND, 1) bSizer4.Add(self.m_user_models, 0, wx.ALL | wx.EXPAND, 1)
@ -79,6 +85,7 @@ class MainFrame (wx.Frame):
bSizer5.Add(self.m_quick_result, 1, wx.EXPAND | wx.ALL, 1) bSizer5.Add(self.m_quick_result, 1, wx.EXPAND | wx.ALL, 1)
self.m_plots = wx.TreeCtrl(self, style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT) self.m_plots = wx.TreeCtrl(self, style = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
self.m_plots.AddRoot('root')
bSizer5.Add(self.m_plots, 1, wx.EXPAND | wx.ALL, 1) bSizer5.Add(self.m_plots, 1, wx.EXPAND | wx.ALL, 1)
bSizer3.Add(bSizer5, 0, wx.ALL | wx.EXPAND, 1) bSizer3.Add(bSizer5, 0, wx.ALL | wx.EXPAND, 1)
@ -90,13 +97,16 @@ class MainFrame (wx.Frame):
self.SetMenuBar(mbar) self.SetMenuBar(mbar)
self.BuildContextMenu() self.BuildContextMenu()
#tbar = self.BuildToolBar()
#self.SetToolBar(tbar)
self.SetSizer(bSizer3) self.SetSizer(bSizer3)
self.Layout() self.Layout()
self.Centre(wx.BOTH) self.Centre(wx.BOTH)
def __del__(self): il = wx.ImageList(16, 16)
pass
def BuildMenu(self): def BuildMenu(self):
menubar = wx.MenuBar() menubar = wx.MenuBar()
@ -106,9 +116,7 @@ class MainFrame (wx.Frame):
menubar.Append(menu, '&File') menubar.Append(menu, '&File')
menu = wx.Menu() menu = wx.Menu()
menu.Append(ID_PROCESS_MODEL, 'Process\tCtrl+R') menu.Append(ID_PROCESS_MODEL, 'Process\tF5')
menu.Append(ID_SHOW_RESULT, 'Show result\tCtrl+S')
menu.Append(ID_SHOW_PLOT, 'Show plot\tCtrl+G')
menu.AppendSeparator() menu.AppendSeparator()
menu.Append(ID_ADD_MODEL_ROOT, 'Add model to root') menu.Append(ID_ADD_MODEL_ROOT, 'Add model to root')
menu.Append(ID_ADD_MODEL_SELECTED, 'Append model to selected') menu.Append(ID_ADD_MODEL_SELECTED, 'Append model to selected')
@ -121,8 +129,15 @@ class MainFrame (wx.Frame):
menubar.Append(menu, '&Model') menubar.Append(menu, '&Model')
menu = wx.Menu() menu = wx.Menu()
menu.Append(3, "&Log In\tCtrl+L") menu.Append(ID_SHOW_RESULT, 'Show result\tCtrl+S')
menu.Append(2, "&Options\tCtrl+P") menu.AppendSeparator()
menu.Append(ID_SHOW_PLOT, 'Show plot\tCtrl+G')
menu.Append(ID_ADD_PLOT, 'Add plot')
menu.Append(ID_ADD_LINE, 'Add line')
menubar.Append(menu, '&Result')
menu = wx.Menu()
menu.Append(ID_ABOUT, "&About\tF1")
menubar.Append(menu, '&Help') menubar.Append(menu, '&Help')
return menubar return menubar
@ -135,6 +150,19 @@ class MainFrame (wx.Frame):
self.m_specs.Bind(wx.EVT_CONTEXT_MENU, self.m_specs.Bind(wx.EVT_CONTEXT_MENU,
lambda x: self.m_specs.PopupMenu(menu)) lambda x: self.m_specs.PopupMenu(menu))
menu1 = wx.Menu()
menu1.Append(ID_ADD_PLOT, 'Add plot')
menu1.Append(ID_ADD_LINE, 'Add line')
self.m_plots.Bind(wx.EVT_CONTEXT_MENU,
lambda x: self.m_plots.PopupMenu(menu1))
def BuildToolBar(self):
tbar = wx.ToolBar(self, -1)
tbar.AddLabelTool(ID_SHOW_PLOT, 'Show plot', wx.Bitmap('share/show-plot.png'))
tbar.Realize()
return tbar
class ResultFrame(wx.Frame): class ResultFrame(wx.Frame):
def __init__(self, parent, title): def __init__(self, parent, title):
wx.Frame.__init__ (self, parent, -1, title, size = wx.Size(500, 500), wx.Frame.__init__ (self, parent, -1, title, size = wx.Size(500, 500),
@ -155,8 +183,35 @@ class ResultFrame(wx.Frame):
self.Layout() self.Layout()
self.Centre(wx.BOTH) self.Centre(wx.BOTH)
class LineSelectDialog(wx.Dialog):
def __init__(self, parent, title):
wx.Dialog.__init__ (self, parent, -1, title, size = wx.Size(400, 300))
bSizer = wx.BoxSizer(wx.HORIZONTAL)
self.left = wx.ListBox(self)
self.right = wx.ListBox(self, style = wx.LB_EXTENDED)
bSizer.Add(self.left, 1, wx.EXPAND | wx.ALL, 2)
bSizer.Add(self.right, 1, wx.EXPAND | wx.ALL, 2)
buttonsSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(bSizer, 1, wx.EXPAND | wx.ALL, 0)
sizer.Add(buttonsSizer, 0, wx.EXPAND | wx.ALL, 5)
self.SetSizer(sizer)
self.Layout()
self.Centre(wx.BOTH)
class PlotFrame(wx.Frame): class PlotFrame(wx.Frame):
def __init__(self, parent, title): def __init__(self, parent, title):
wx.Frame.__init__ (self, parent, -1, title, size = wx.Size(600, 400)) wx.Frame.__init__ (self, parent, -1, title, size = wx.Size(600, 400))
self.plot = wxplot.PlotCanvas(self) self.plot = wxplot.PlotCanvas(self)
self.plot.SetGridColour(wx.Color(200, 200, 200))
self.plot.SetEnableGrid(True)
self.plot.SetEnableAntiAliasing(True)
self.plot.SetEnableHiRes(True)

224
opal.py
View File

@ -15,6 +15,7 @@ import server
import task import task
import wx import wx
import wx.propgrid as wxpg import wx.propgrid as wxpg
import wx.lib.plot as wxplot
import forms import forms
import time import time
import datetime import datetime
@ -69,6 +70,8 @@ class MainFrame(forms.MainFrame):
self.OnAddModelToSelected) self.OnAddModelToSelected)
self.m_user_models.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.m_user_models.Bind(wx.EVT_TREE_ITEM_ACTIVATED,
self.OnModelProcess) self.OnModelProcess)
self.m_plots.Bind(wx.EVT_TREE_ITEM_ACTIVATED,
self.OnPlotProcess)
self.Bind(wx.EVT_MENU, self.OnTest, self.Bind(wx.EVT_MENU, self.OnTest,
@ -85,12 +88,27 @@ class MainFrame(forms.MainFrame):
id = forms.ID_DELETE_MODEL) id = forms.ID_DELETE_MODEL)
self.Bind(wx.EVT_MENU, self.OnModelProcess, self.Bind(wx.EVT_MENU, self.OnModelProcess,
id = forms.ID_PROCESS_MODEL) id = forms.ID_PROCESS_MODEL)
self.Bind(wx.EVT_MENU, self.OnShowResult, self.Bind(wx.EVT_MENU, self.OnShowResult,
id = forms.ID_SHOW_RESULT) id = forms.ID_SHOW_RESULT)
self.Bind(wx.EVT_MENU, self.OnShowPlot,
id = forms.ID_SHOW_PLOT)
self.Bind(wx.EVT_MENU, self.OnAddPlot,
id = forms.ID_ADD_PLOT)
self.Bind(wx.EVT_MENU, self.OnAddLines,
id = forms.ID_ADD_LINE)
self.Bind(wx.EVT_CLOSE, self.OnClose) self.Bind(wx.EVT_CLOSE, self.OnClose)
self.Bind(wx.EVT_IDLE, self.OnIdle) self.Bind(wx.EVT_IDLE, self.OnIdle)
# если установлен в True, то обработчик состояний работ
# будет работать вхолостую, чтобы не создать deadlock
# проблема возникает в том, что при одновременной блокировке
# GUI и вызова модального диалога, последний весит все приложение напрочь
# в момент своего закрытия. а так как диалог все равно модальный,
# форме не обязательно обновляться в тот момент, когда он открыт
self.do_nothing = False
ov = threading.Thread(target = self.Overseer) ov = threading.Thread(target = self.Overseer)
ov.daemon = True ov.daemon = True
ov.start() ov.start()
@ -126,33 +144,40 @@ class MainFrame(forms.MainFrame):
um = self.m_user_models um = self.m_user_models
cycle_count = 0 cycle_count = 0
while True: while True:
wx.MutexGuiEnter()
#print 'cycle{:-8}'.format(cycle_count)
cycle_count += 1
# просматриваем всю иерархию моделей
for item in um:
data = um.GetPyData(item)
if not data:
continue
jid = data.jid
if jid != None and self.server.IsJobChanged(jid):
state, percent, comment = self.server.GetJobState(jid)
um.SetItemText(item, StateToStr(state), 1)
p = 'Unknown' if percent < 0 else '{:%}'.format(percent)
um.SetItemText(item, p, 2)
um.SetItemText(item, comment, 3)
print 'JID', jid, (state, percent, comment)
# завершающие действия по окончанию выполнения работы
if state == server.JOB_COMPLETED:
# получаем результаты выполнения
data.res = self.server.GetJobResult(jid)
# если завершившаяся задача в данный момент выделена
# то сразу же показываем этот результат
if um.IsSelected(item):
self.ShowQuickResult(data.res)
wx.MutexGuiLeave()
time.sleep(0.1) time.sleep(0.1)
# если нужно подождать, то мы подождем
if self.do_nothing:
continue
wx.MutexGuiEnter()
try:
# print 'cycle{:-8}'.format(cycle_count)
cycle_count += 1
# просматриваем всю иерархию моделей
for item in um:
data = um.GetPyData(item)
if not data:
continue
jid = data.jid
if jid != None and self.server.IsJobChanged(jid):
state, percent, comment = self.server.GetJobState(jid)
um.SetItemText(item, StateToStr(state), 1)
p = 'Unknown' if percent < 0 else '{:%}'.format(percent)
um.SetItemText(item, p, 2)
um.SetItemText(item, comment, 3)
print 'JID', jid, (state, percent, comment)
# завершающие действия по окончанию выполнения работы
if state == server.JOB_COMPLETED:
# получаем результаты выполнения
data.res = self.server.GetJobResult(jid)
# если завершившаяся задача в данный момент выделена
# то сразу же показываем этот результат
if um.IsSelected(item):
self.ShowQuickResult(data.res)
finally:
wx.MutexGuiLeave()
pass
except Exception, e: except Exception, e:
print 'Error in overseer: ', e print 'Error in overseer: ', e
@ -227,16 +252,22 @@ class MainFrame(forms.MainFrame):
um.Expand(root) um.Expand(root)
def NewProject(self, model): def NewProject(self, model):
# 1. загрузить спецификации модели """
# 2. создать одну модель по умолчанию Начать новый проект:
1. Построить дерево спецификаций
2. Создать одну пользовательскую модель (по умолчанию)
3. Сделать заготовки для графиков/отчетов/прочего
"""
# Строим спецификации
self.BuildSpecs(model) self.BuildSpecs(model)
# Очищаем окно пользовательских моделей
# и создаем там одну
um = self.m_user_models um = self.m_user_models
um.DeleteAllItems() um.DeleteAllItems()
um.AddRoot('Root') um.AddRoot('root')
self.AddModelToRoot(model) self.AddModelToRoot(model)
# Создаем корневой элемент для окна с графиками
self.m_plots.AddRoot('root')
return True # Project(model) return True # Project(model)
@ -394,6 +425,89 @@ class MainFrame(forms.MainFrame):
rframe = ResultFrame(self, title, data.res) rframe = ResultFrame(self, title, data.res)
rframe.Show() rframe.Show()
def GetLines(self):
"""
Возвращает набор линий, которые пользователь указал для
построения графика к выбранной модели.
Линии представляют из себя кортежи из 4х элементов:
[ внутренний индекс в иерархии моделей,
данные модели,
колонка-х,
колонка-у ]
"""
um = self.m_user_models
item, data = self.GetSelectedItemData(um)
title = um.GetItemText(item)
if not data.res:
self.SetStatusText("There is no results in model")
return []
f = LineSelectDialog(self, 'Select lines for "{}"'.format(title))
for index, col in enumerate(data.res.columns):
row_title = col.GetTitle()
row_data = index
f.Add(row_title, row_data)
f.SetSelections()
lines = []
self.do_nothing = True
try:
if f.ShowModal() == wx.ID_OK:
lines = [ (item, data, x, y) for x, y in f.GetData() ]
finally:
self.do_nothing = False
return lines
def ShowPlot(self, lines, title = ''):
if not lines:
return
data = []
for item, moddata, x, y in lines:
data.append(moddata.res.Zip(x, y))
p = PlotFrame(self, 'Plot for model "%s"' % title, data)
p.Show()
def OnShowPlot(self, event):
lines = self.GetLines()
self.ShowPlot(lines)
def OnAddPlot(self, event):
root = self.m_plots.GetRootItem()
child = self.m_plots.AppendItem(root, 'New plot')
self.m_plots.SetPyData(child, 'plot')
def OnAddLines(self, event):
item = self.m_plots.GetSelection()
data = self.m_plots.GetItemPyData(item)
if data != 'plot':
return
lines = self.GetLines()
if not lines:
return
for line in lines:
child = self.m_plots.AppendItem(item, 'Line')
self.m_plots.SetPyData(child, line)
def OnPlotProcess(self, event):
item = self.m_plots.GetSelection()
data = self.m_plots.GetItemPyData(item)
lines = []
if data == 'plot':
child, cookie = self.m_plots.GetFirstChild(item)
while child.IsOk():
lines.append(self.m_plots.GetItemPyData(child))
child, cookie = self.m_plots.GetNextChild(item, cookie)
else:
lines = [data]
self.ShowPlot(lines)
def OnIdle(self, event): def OnIdle(self, event):
pass pass
@ -431,6 +545,52 @@ class ResultFrame(forms.ResultFrame):
for label, param in self.result.data.iteritems(): for label, param in self.result.data.iteritems():
pg.Append(wxpg.StringProperty(label, value = str(param.GetValue()))) pg.Append(wxpg.StringProperty(label, value = str(param.GetValue())))
#-----------------------------------------------------------------------------
# Форма с выбором наборов значений для построения графика
#-----------------------------------------------------------------------------
class LineSelectDialog(forms.LineSelectDialog):
def __init__(self, parent, title):
forms.LineSelectDialog.__init__(self, parent, title)
def Add(self, title, data = None):
self.left.Append(title, data)
self.right.Append(title, data)
def SetSelections(self):
if self.left.GetCount():
self.left.Select(0)
for i in xrange(1, self.right.GetCount()):
self.right.Select(i)
def GetData(self):
item = self.left.GetSelection()
x = self.left.GetClientData(item)
items = self.right.GetSelections()
ys = [ self.right.GetClientData(i) for i in items ]
return [ (x, y) for y in ys ]
#-----------------------------------------------------------------------------
# Форма с изображением графика
#-----------------------------------------------------------------------------
class PlotFrame(forms.PlotFrame):
def __init__(self, parent, title, lines_with_data):
forms.PlotFrame.__init__(self, parent, title)
#self.data = data
data = lines_with_data
lines = []
colours = ['red', 'blue', 'green']
for i, d in enumerate(data):
lines.append( wxplot.PolyLine(d, colour = colours[i % len(colours)]) )
graph = wxplot.PlotGraphics(lines)
self.plot.Draw(graph)
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Приложение # Приложение
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------

BIN
share/show-plot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

View File

@ -181,3 +181,9 @@ class ResultData:
return self.table return self.table
rows = property(GetRows) rows = property(GetRows)
def GetColumn(self, index):
return [ row[index] for row in self.rows ]
def Zip(self, col1, col2):
return [ (row[col1], row[col2]) for row in self.rows ]

View File

@ -11,7 +11,7 @@
"author": "Anton Vakhrushev", "author": "Anton Vakhrushev",
"date": "2012-03-08", "date": "2012-03-08",
"exec": false, "exec": true,
"params": { "params": {