'''\r
HOOKE - A force spectroscopy review & analysis tool\r
\r
-Copyright 2008 by Massimo Sandal (University of Bologna, Italy).\r
-Copyright 2010 by Rolf Schmidt (Concordia University, Canada).\r
+Copyright 2008 by Massimo Sandal (University of Bologna, Italy)\r
+Copyright 2010 by Rolf Schmidt (Concordia University, Canada)\r
\r
This program is released under the GNU General Public License version 2.\r
'''\r
\r
-import wxversion\r
import lib.libhooke as lh\r
+import wxversion\r
wxversion.select(lh.WX_GOOD)\r
\r
from configobj import ConfigObj\r
import copy\r
import os.path\r
import platform\r
+import shutil\r
import time\r
-#import wx\r
+\r
import wx.html\r
import wx.lib.agw.aui as aui\r
import wx.lib.evtmgr as evtmgr\r
import wx.propgrid as wxpg\r
\r
+from matplotlib.ticker import FuncFormatter\r
+\r
+from configobj import __version__ as configobj_version\r
from matplotlib import __version__ as mpl_version\r
from numpy import __version__ as numpy_version\r
from scipy import __version__ as scipy_version\r
from sys import version as python_version\r
from wx import __version__ as wx_version\r
+from wx.propgrid import PROPGRID_MAJOR\r
+from wx.propgrid import PROPGRID_MINOR\r
+from wx.propgrid import PROPGRID_RELEASE\r
\r
try:\r
from agw import cubecolourdialog as CCD\r
lh.hookeDir = os.path.abspath(os.path.dirname(__file__))\r
from config.config import config\r
import drivers\r
+import lib.clickedpoint\r
+import lib.curve\r
+import lib.delta\r
import lib.playlist\r
import lib.plotmanipulator\r
+import lib.prettyformat\r
import panels.commands\r
+import panels.note\r
import panels.perspectives\r
import panels.playlist\r
import panels.plot\r
__releasedate__ = lh.HOOKE_VERSION[2]\r
__release_name__ = lh.HOOKE_VERSION[1]\r
\r
-#TODO: add general preferences to Hooke\r
-#this might be useful\r
-#ID_Config = wx.NewId()\r
ID_About = wx.NewId()\r
ID_Next = wx.NewId()\r
ID_Previous = wx.NewId()\r
ID_ViewAssistant = wx.NewId()\r
ID_ViewCommands = wx.NewId()\r
ID_ViewFolders = wx.NewId()\r
+ID_ViewNote = wx.NewId()\r
ID_ViewOutput = wx.NewId()\r
ID_ViewPlaylists = wx.NewId()\r
ID_ViewProperties = wx.NewId()\r
self.SetAppName('Hooke')\r
self.SetVendorName('')\r
\r
- windowPosition = (config['main']['left'], config['main']['top'])\r
- windowSize = (config['main']['width'], config['main']['height'])\r
+ window_height = config['main']['height']\r
+ window_left= config['main']['left']\r
+ window_top = config['main']['top']\r
+ window_width = config['main']['width']\r
+\r
+ #sometimes, the ini file gets confused and sets 'left'\r
+ #and 'top' to large negative numbers\r
+ #let's catch and fix this\r
+ #keep small negative numbers, the user might want those\r
+ if window_left < -window_width:\r
+ window_left = 0\r
+ if window_top < -window_height:\r
+ window_top = 0\r
+ window_position = (window_left, window_top)\r
+ window_size = (window_width, window_height)\r
\r
#setup the splashscreen\r
if config['splashscreen']['show']:\r
def make_command_class(*bases):\r
#create metaclass with plugins and plotmanipulators\r
return type(HookeFrame)("HookeFramePlugged", bases + (HookeFrame,), {})\r
- frame = make_command_class(*plugin_objects)(parent=None, id=wx.ID_ANY, title='Hooke', pos=windowPosition, size=windowSize)\r
+ frame = make_command_class(*plugin_objects)(parent=None, id=wx.ID_ANY, title='Hooke', pos=window_position, size=window_size)\r
frame.Show(True)\r
self.SetTopWindow(frame)\r
\r
self.plotmanipulators = []\r
#self.plugins contains: {the name of the plugin: [caption, function]}\r
self.plugins = {}\r
+ #self.results_str contains the type of results we want to display\r
+ self.results_str = 'wlc'\r
\r
#tell FrameManager to manage this frame\r
self._mgr = aui.AuiManager()\r
# see the end up FrameManager::Update() for the test\r
# code. For now, just hard code a frame minimum size\r
self.SetMinSize(wx.Size(500, 500))\r
- #create panels here\r
- self.panelAssistant = self.CreatePanelAssistant()\r
- self.panelCommands = self.CreatePanelCommands()\r
- self.panelFolders = self.CreatePanelFolders()\r
- self.panelPlaylists = self.CreatePanelPlaylists()\r
- self.panelProperties = self.CreatePanelProperties()\r
- self.panelOutput = self.CreatePanelOutput()\r
- self.panelResults = self.CreatePanelResults()\r
- self.plotNotebook = self.CreateNotebook()\r
- #self.textCtrlCommandLine=self.CreateCommandLine()\r
-\r
- # add panes\r
- self._mgr.AddPane(self.panelFolders, aui.AuiPaneInfo().Name('Folders').Caption('Folders').Left().CloseButton(True).MaximizeButton(False))\r
- self._mgr.AddPane(self.panelPlaylists, aui.AuiPaneInfo().Name('Playlists').Caption('Playlists').Left().CloseButton(True).MaximizeButton(False))\r
- self._mgr.AddPane(self.plotNotebook, aui.AuiPaneInfo().Name('Plots').CenterPane().PaneBorder(False))\r
- self._mgr.AddPane(self.panelCommands, aui.AuiPaneInfo().Name('Commands').Caption('Settings and commands').Right().CloseButton(True).MaximizeButton(False))\r
- self._mgr.AddPane(self.panelProperties, aui.AuiPaneInfo().Name('Properties').Caption('Properties').Right().CloseButton(True).MaximizeButton(False))\r
- self._mgr.AddPane(self.panelAssistant, aui.AuiPaneInfo().Name('Assistant').Caption('Assistant').Right().CloseButton(True).MaximizeButton(False))\r
- self._mgr.AddPane(self.panelOutput, aui.AuiPaneInfo().Name('Output').Caption('Output').Bottom().CloseButton(True).MaximizeButton(False))\r
- self._mgr.AddPane(self.panelResults, aui.AuiPaneInfo().Name('Results').Caption('Results').Bottom().CloseButton(True).MaximizeButton(False))\r
- #self._mgr.AddPane(self.textCtrlCommandLine, aui.AuiPaneInfo().Name('CommandLine').CaptionVisible(False).Fixed().Bottom().Layer(2).CloseButton(False).MaximizeButton(False))\r
- #self._mgr.AddPane(panelBottom, aui.AuiPaneInfo().Name("panelCommandLine").Bottom().Position(1).CloseButton(False).MaximizeButton(False))\r
-\r
- # add the toolbars to the manager\r
- #self.toolbar=self.CreateToolBar()\r
- self.toolbarNavigation=self.CreateToolBarNavigation()\r
- #self._mgr.AddPane(self.toolbar, aui.AuiPaneInfo().Name('toolbar').Caption('Toolbar').ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False).RightDockable(False))\r
- self._mgr.AddPane(self.toolbarNavigation, aui.AuiPaneInfo().Name('toolbarNavigation').Caption('Navigation').ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False).RightDockable(False))\r
- # "commit" all changes made to FrameManager\r
- self._mgr.Update()\r
- #create the menubar after the panes so that the default perspective\r
- #is created with all panes open\r
- self.CreateMenuBar()\r
- self.statusbar = self.CreateStatusbar()\r
- self._BindEvents()\r
-\r
- name = self.config['perspectives']['active']\r
- menu_item = self.GetPerspectiveMenuItem(name)\r
- if menu_item is not None:\r
- self.OnRestorePerspective(menu_item)\r
- #TODO: config setting to remember playlists from last session\r
- self.playlists = self.panelPlaylists.Playlists\r
#define the list of active drivers\r
self.drivers = []\r
for driver in self.config['drivers']:\r
plugin_config = ConfigObj(ini_path)\r
#self.config.merge(plugin_config)\r
self.configs['core'] = plugin_config\r
+ #existing_commands contains: {command: plugin}\r
+ existing_commands = {}\r
#make sure we execute _plug_init() for every command line plugin we import\r
for plugin in self.config['plugins']:\r
if self.config['plugins'][plugin]:\r
#add to plugins\r
commands = eval('dir(module.' + plugin+ '.' + plugin + 'Commands)')\r
#keep only commands (ie names that start with 'do_')\r
- #TODO: check for existing commands and warn the user!\r
commands = [command for command in commands if command.startswith('do_')]\r
if commands:\r
+ for command in commands:\r
+ if existing_commands.has_key(command):\r
+ message_str = 'Adding "' + command + '" in plugin "' + plugin + '".\n\n'\r
+ message_str += '"' + command + '" already exists in "' + str(existing_commands[command]) + '".\n\n'\r
+ message_str += 'Only "' + command + '" in "' + str(existing_commands[command]) + '" will work.\n\n'\r
+ message_str += 'Please rename one of the commands in the source code and restart Hooke or disable one of the plugins.'\r
+ dialog = wx.MessageDialog(self, message_str, 'Warning', wx.OK|wx.ICON_WARNING|wx.CENTER)\r
+ dialog.ShowModal()\r
+ dialog.Destroy()\r
+ existing_commands[command] = plugin\r
self.plugins[plugin] = commands\r
try:\r
#initialize the plugin\r
pass\r
except ImportError:\r
pass\r
- #initialize the commands tree\r
+ #add commands from hooke.py i.e. 'core' commands\r
commands = dir(HookeFrame)\r
commands = [command for command in commands if command.startswith('do_')]\r
if commands:\r
self.plugins['core'] = commands\r
+ #create panels here\r
+ self.panelAssistant = self.CreatePanelAssistant()\r
+ self.panelCommands = self.CreatePanelCommands()\r
+ self.panelFolders = self.CreatePanelFolders()\r
+ self.panelPlaylists = self.CreatePanelPlaylists()\r
+ self.panelProperties = self.CreatePanelProperties()\r
+ self.panelNote = self.CreatePanelNote()\r
+ self.panelOutput = self.CreatePanelOutput()\r
+ self.panelResults = self.CreatePanelResults()\r
+ self.plotNotebook = self.CreateNotebook()\r
+\r
+ # add panes\r
+ self._mgr.AddPane(self.panelFolders, aui.AuiPaneInfo().Name('Folders').Caption('Folders').Left().CloseButton(True).MaximizeButton(False))\r
+ self._mgr.AddPane(self.panelPlaylists, aui.AuiPaneInfo().Name('Playlists').Caption('Playlists').Left().CloseButton(True).MaximizeButton(False))\r
+ self._mgr.AddPane(self.panelNote, aui.AuiPaneInfo().Name('Note').Caption('Note').Left().CloseButton(True).MaximizeButton(False))\r
+ self._mgr.AddPane(self.plotNotebook, aui.AuiPaneInfo().Name('Plots').CenterPane().PaneBorder(False))\r
+ self._mgr.AddPane(self.panelCommands, aui.AuiPaneInfo().Name('Commands').Caption('Settings and commands').Right().CloseButton(True).MaximizeButton(False))\r
+ self._mgr.AddPane(self.panelProperties, aui.AuiPaneInfo().Name('Properties').Caption('Properties').Right().CloseButton(True).MaximizeButton(False))\r
+ self._mgr.AddPane(self.panelAssistant, aui.AuiPaneInfo().Name('Assistant').Caption('Assistant').Right().CloseButton(True).MaximizeButton(False))\r
+ self._mgr.AddPane(self.panelOutput, aui.AuiPaneInfo().Name('Output').Caption('Output').Bottom().CloseButton(True).MaximizeButton(False))\r
+ self._mgr.AddPane(self.panelResults, aui.AuiPaneInfo().Name('Results').Caption('Results').Bottom().CloseButton(True).MaximizeButton(False))\r
+ #self._mgr.AddPane(self.textCtrlCommandLine, aui.AuiPaneInfo().Name('CommandLine').CaptionVisible(False).Fixed().Bottom().Layer(2).CloseButton(False).MaximizeButton(False))\r
+ #self._mgr.AddPane(panelBottom, aui.AuiPaneInfo().Name("panelCommandLine").Bottom().Position(1).CloseButton(False).MaximizeButton(False))\r
+\r
+ # add the toolbars to the manager\r
+ #self.toolbar=self.CreateToolBar()\r
+ self.toolbarNavigation=self.CreateToolBarNavigation()\r
+ #self._mgr.AddPane(self.toolbar, aui.AuiPaneInfo().Name('toolbar').Caption('Toolbar').ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False).RightDockable(False))\r
+ self._mgr.AddPane(self.toolbarNavigation, aui.AuiPaneInfo().Name('toolbarNavigation').Caption('Navigation').ToolbarPane().Top().Layer(1).Row(1).LeftDockable(False).RightDockable(False))\r
+ # "commit" all changes made to FrameManager\r
+ self._mgr.Update()\r
+ #create the menubar after the panes so that the default perspective\r
+ #is created with all panes open\r
+ self.CreateMenuBar()\r
+ self.statusbar = self.CreateStatusbar()\r
+ self._BindEvents()\r
+\r
+ name = self.config['perspectives']['active']\r
+ menu_item = self.GetPerspectiveMenuItem(name)\r
+ if menu_item is not None:\r
+ self.OnRestorePerspective(menu_item)\r
+ #TODO: config setting to remember playlists from last session\r
+ self.playlists = self.panelPlaylists.Playlists\r
+ #initialize the commands tree\r
self.panelCommands.Initialize(self.plugins)\r
for command in dir(self):\r
if command.startswith('plotmanip_'):\r
self.plotmanipulators.append(lib.plotmanipulator.Plotmanipulator(method=getattr(self, command), command=command))\r
\r
#load default list, if possible\r
- self.do_loadlist(self.config['core']['list'])\r
- #self.do_loadlist()\r
+ self.do_loadlist(self.GetStringFromConfig('core', 'preferences', 'playlist'))\r
\r
def _BindEvents(self):\r
#TODO: figure out if we can use the eventManager for menu ranges\r
evtmgr.eventManager.Register(self.OnExecute, wx.EVT_BUTTON, self.panelCommands.ExecuteButton)\r
evtmgr.eventManager.Register(self.OnTreeCtrlCommandsSelectionChanged, wx.EVT_TREE_SEL_CHANGED, self.panelCommands.CommandsTree)\r
evtmgr.eventManager.Register(self.OnTreeCtrlItemActivated, wx.EVT_TREE_ITEM_ACTIVATED, self.panelCommands.CommandsTree)\r
+ evtmgr.eventManager.Register(self.OnUpdateNote, wx.EVT_BUTTON, self.panelNote.UpdateButton)\r
#property editor\r
self.panelProperties.pg.Bind(wxpg.EVT_PG_CHANGED, self.OnPropGridChanged)\r
#results panel\r
self.MenuBar.FindItemById(ID_ViewPlaylists).Check(pane.window.IsShown())\r
if pane.name == 'Commands':\r
self.MenuBar.FindItemById(ID_ViewCommands).Check(pane.window.IsShown())\r
+ if pane.name == 'Note':\r
+ self.MenuBar.FindItemById(ID_ViewNote).Check(pane.window.IsShown())\r
if pane.name == 'Properties':\r
self.MenuBar.FindItemById(ID_ViewProperties).Check(pane.window.IsShown())\r
if pane.name == 'Output':\r
#commands tree\r
evtmgr.eventManager.DeregisterListener(self.OnExecute)\r
evtmgr.eventManager.DeregisterListener(self.OnTreeCtrlCommandsSelectionChanged)\r
+ evtmgr.eventManager.DeregisterListener(self.OnTreeCtrlItemActivated)\r
+ evtmgr.eventManager.DeregisterListener(self.OnUpdateNote)\r
\r
def AddPlaylist(self, playlist=None, name='Untitled'):\r
if playlist and playlist.count > 0:\r
playlist_root = self.panelPlaylists.PlaylistsTree.AppendItem(tree_root, playlist.name, 0)\r
#add all files to the Playlist tree\r
# files = {}\r
+ hide_curve_extension = self.GetBoolFromConfig('core', 'preferences', 'hide_curve_extension')\r
for index, file_to_add in enumerate(playlist.files):\r
- #TODO: optionally remove the extension from the name of the curve\r
- #item_text, extension = os.path.splitext(curve.name)\r
- #curve_ID = self.panelPlaylists.PlaylistsTree.AppendItem(playlist_root, item_text, 1)\r
+ #optionally remove the extension from the name of the curve\r
+ if hide_curve_extension:\r
+ file_to_add.name = lh.remove_extension(file_to_add.name)\r
file_ID = self.panelPlaylists.PlaylistsTree.AppendItem(playlist_root, file_to_add.name, 1)\r
if index == playlist.index:\r
self.panelPlaylists.PlaylistsTree.SelectItem(file_ID)\r
#self.playlists[playlist.name] = [playlist, figure]\r
self.panelPlaylists.PlaylistsTree.Expand(playlist_root)\r
self.statusbar.SetStatusText(playlist.get_status_string(), 0)\r
+ self.UpdateNote()\r
self.UpdatePlot()\r
\r
def AppendToOutput(self, text):\r
\r
def AppliesPlotmanipulator(self, name):\r
'''\r
- returns True if the plotmanipulator 'name' is applied, False otherwise\r
+ Returns True if the plotmanipulator 'name' is applied, False otherwise\r
name does not contain 'plotmanip_', just the name of the plotmanipulator (e.g. 'flatten')\r
'''\r
return self.GetBoolFromConfig('core', 'plotmanipulators', name)\r
\r
+ def ApplyPlotmanipulators(self, plot, plot_file):\r
+ '''\r
+ Apply all active plotmanipulators.\r
+ '''\r
+ if plot is not None and plot_file is not None:\r
+ manipulated_plot = copy.deepcopy(plot)\r
+ for plotmanipulator in self.plotmanipulators:\r
+ if self.GetBoolFromConfig('core', 'plotmanipulators', plotmanipulator.name):\r
+ manipulated_plot = plotmanipulator.method(manipulated_plot, plot_file)\r
+ return manipulated_plot\r
+\r
def CreateApplicationIcon(self):\r
iconFile = 'resources' + os.sep + 'microscope.ico'\r
icon = wx.Icon(iconFile, wx.BITMAP_TYPE_ICO)\r
filters = self.config['folders']['filters']\r
index = self.config['folders'].as_int('filterindex')\r
#set initial directory\r
- folder = self.config['core']['workdir']\r
+ folder = self.GetStringFromConfig('core', 'preferences', 'workdir')\r
return wx.GenericDirCtrl(self, -1, dir=folder, size=(200, 250), style=wx.DIRCTRL_SHOW_FILTERS, filter=filters, defaultFilter=index)\r
\r
+ def CreatePanelNote(self):\r
+ return panels.note.Note(self)\r
+\r
def CreatePanelOutput(self):\r
return wx.TextCtrl(self, -1, '', wx.Point(0, 0), wx.Size(150, 90), wx.NO_BORDER|wx.TE_MULTILINE)\r
\r
view_menu.AppendCheckItem(ID_ViewAssistant, 'Assistant\tF9')\r
view_menu.AppendCheckItem(ID_ViewResults, 'Results\tF10')\r
view_menu.AppendCheckItem(ID_ViewOutput, 'Output\tF11')\r
+ view_menu.AppendCheckItem(ID_ViewNote, 'Note\tF12')\r
#perspectives\r
-# perspectives_menu = self.CreatePerspectivesMenu()\r
perspectives_menu = wx.Menu()\r
\r
#help\r
help_menu.Append(wx.ID_ABOUT, 'About Hooke')\r
#put it all together\r
menu_bar.Append(file_menu, 'File')\r
-# menu_bar.Append(edit_menu, 'Edit')\r
menu_bar.Append(view_menu, 'View')\r
menu_bar.Append(perspectives_menu, "Perspectives")\r
self.UpdatePerspectivesMenu()\r
\r
def GetDisplayedPlot(self):\r
plot = copy.deepcopy(self.displayed_plot)\r
- plot.curves = []\r
- plot.curves = copy.deepcopy(plot.curves)\r
+ #plot.curves = []\r
+ #plot.curves = copy.deepcopy(plot.curves)\r
return plot\r
\r
def GetDisplayedPlotCorrected(self):\r
return config[section][key]['value']\r
return None\r
\r
+ def GetPlotmanipulator(self, name):\r
+ '''\r
+ Returns a plot manipulator function from its name\r
+ '''\r
+ for plotmanipulator in self.plotmanipulators:\r
+ if plotmanipulator.name == name:\r
+ return plotmanipulator\r
+ return None\r
+\r
def GetPerspectiveMenuItem(self, name):\r
if self._perspectives.has_key(name):\r
perspectives_list = [key for key, value in self._perspectives.iteritems()]\r
if playlist.count > 1:\r
playlist.next()\r
self.statusbar.SetStatusText(playlist.get_status_string(), 0)\r
+ self.UpdateNote()\r
self.UpdatePlot()\r
\r
def OnNotebookPageClose(self, event):\r
playlist = self.GetActivePlaylist()\r
playlist.index = index\r
self.statusbar.SetStatusText(playlist.get_status_string(), 0)\r
+ self.UpdateNote()\r
self.UpdatePlot()\r
#if you uncomment the following line, the tree will collapse/expand as well\r
#event.Skip()\r
if playlist.count > 1:\r
playlist.previous()\r
self.statusbar.SetStatusText(playlist.get_status_string(), 0)\r
+ self.UpdateNote()\r
self.UpdatePlot()\r
\r
def OnPropGridChanged (self, event):\r
def OnRestorePerspective(self, event):\r
name = self.MenuBar.FindItemById(event.GetId()).GetLabel()\r
self._RestorePerspective(name)\r
-# self._mgr.LoadPerspective(self._perspectives[name])\r
-# self.config['perspectives']['active'] = name\r
-# self._mgr.Update()\r
-# all_panes = self._mgr.GetAllPanes()\r
-# for pane in all_panes:\r
-# if not pane.name.startswith('toolbar'):\r
-# if pane.name == 'Assistant':\r
-# self.MenuBar.FindItemById(ID_ViewAssistant).Check(pane.window.IsShown())\r
-# if pane.name == 'Folders':\r
-# self.MenuBar.FindItemById(ID_ViewFolders).Check(pane.window.IsShown())\r
-# if pane.name == 'Playlists':\r
-# self.MenuBar.FindItemById(ID_ViewPlaylists).Check(pane.window.IsShown())\r
-# if pane.name == 'Commands':\r
-# self.MenuBar.FindItemById(ID_ViewCommands).Check(pane.window.IsShown())\r
-# if pane.name == 'Properties':\r
-# self.MenuBar.FindItemById(ID_ViewProperties).Check(pane.window.IsShown())\r
-# if pane.name == 'Output':\r
-# self.MenuBar.FindItemById(ID_ViewOutput).Check(pane.window.IsShown())\r
-# if pane.name == 'Results':\r
-# self.MenuBar.FindItemById(ID_ViewResults).Check(pane.window.IsShown())\r
\r
def OnResultsCheck(self, index, flag):\r
- #TODO: fix for multiple results\r
results = self.GetActivePlot().results\r
- fit_function_str = self.GetStringFromConfig('results', 'show_results', 'fit_function')\r
- results[fit_function_str].results[index].visible = flag\r
- self.UpdatePlot()\r
+ if results.has_key(self.results_str):\r
+ results[self.results_str].results[index].visible = flag\r
+ results[self.results_str].update()\r
+ self.UpdatePlot()\r
\r
def OnSavePerspective(self, event):\r
\r
def nameExists(name):\r
- menu_position = self.MenuBar.FindMenu('Perspectives') \r
+ menu_position = self.MenuBar.FindMenu('Perspectives')\r
menu = self.MenuBar.GetMenu(menu_position)\r
for item in menu.GetMenuItems():\r
if item.GetText() == name:\r
def OnTreeCtrlItemActivated(self, event):\r
self.OnExecute(event)\r
\r
+ def OnUpdateNote(self, event):\r
+ '''\r
+ Saves the note to the active file.\r
+ '''\r
+ active_file = self.GetActiveFile()\r
+ active_file.note = self.panelNote.Editor.GetValue()\r
+\r
def OnView(self, event):\r
menu_id = event.GetId()\r
menu_item = self.MenuBar.FindItemById(menu_id)\r
self.panelFolders.Fit()\r
self._mgr.Update()\r
\r
+ def _clickize(self, xvector, yvector, index):\r
+ '''\r
+ Returns a ClickedPoint() object from an index and vectors of x, y coordinates\r
+ '''\r
+ point = lib.clickedpoint.ClickedPoint()\r
+ point.index = index\r
+ point.absolute_coords = xvector[index], yvector[index]\r
+ point.find_graph_coords(xvector, yvector)\r
+ return point\r
+\r
+ def _delta(self, message='Click 2 points', whatset=lh.RETRACTION):\r
+ '''\r
+ Calculates the difference between two clicked points\r
+ '''\r
+ clicked_points = self._measure_N_points(N=2, message=message, whatset=whatset)\r
+\r
+ plot = self.GetDisplayedPlotCorrected()\r
+ curve = plot.curves[whatset]\r
+\r
+ delta = lib.delta.Delta()\r
+ delta.point1.x = clicked_points[0].graph_coords[0]\r
+ delta.point1.y = clicked_points[0].graph_coords[1]\r
+ delta.point2.x = clicked_points[1].graph_coords[0]\r
+ delta.point2.y = clicked_points[1].graph_coords[1]\r
+ delta.units.x = curve.units.x\r
+ delta.units.y = curve.units.y\r
+\r
+ return delta\r
+\r
def _measure_N_points(self, N, message='', whatset=lh.RETRACTION):\r
'''\r
General helper function for N-points measurements\r
By default, measurements are done on the retraction\r
'''\r
- if message != '':\r
+ if message:\r
dialog = wx.MessageDialog(None, message, 'Info', wx.OK)\r
dialog.ShowModal()\r
\r
\r
points = []\r
for clicked_point in clicked_points:\r
- point = lh.ClickedPoint()\r
+ point = lib.clickedpoint.ClickedPoint()\r
point.absolute_coords = clicked_point[0], clicked_point[1]\r
point.dest = 0\r
#TODO: make this optional?\r
points.append(point)\r
return points\r
\r
- def _clickize(self, xvector, yvector, index):\r
- '''\r
- returns a ClickedPoint() object from an index and vectors of x, y coordinates\r
- '''\r
- point = lh.ClickedPoint()\r
- point.index = index\r
- point.absolute_coords = xvector[index], yvector[index]\r
- point.find_graph_coords(xvector, yvector)\r
- return point\r
-\r
- def _delta(self, color='black', message='Click 2 points', show=True, whatset=1):\r
+ def do_copylog(self):\r
'''\r
- calculates the difference between two clicked points\r
+ Copies all files in the current playlist that have a note to the destination folder.\r
+ destination: select folder where you want the files to be copied\r
+ use_LVDT_folder: when checked, the files will be copied to a folder called 'LVDT' in the destination folder (for MFP-1D files only)\r
'''\r
- clicked_points = self._measure_N_points(N=2, message=message, whatset=whatset)\r
- dx = abs(clicked_points[0].graph_coords[0] - clicked_points[1].graph_coords[0])\r
- dy = abs(clicked_points[0].graph_coords[1] - clicked_points[1].graph_coords[1])\r
-\r
- plot = self.GetDisplayedPlotCorrected()\r
-\r
- curve = plot.curves[whatset]\r
- unitx = curve.units.x\r
- unity = curve.units.y\r
-\r
- #TODO: move this to clicked_points?\r
- if show:\r
- for point in clicked_points:\r
- points = copy.deepcopy(curve)\r
- points.x = point.graph_coords[0]\r
- points.y = point.graph_coords[1]\r
-\r
- points.color = color\r
- points.size = 20\r
- points.style = 'scatter'\r
- plot.curves.append(points)\r
-\r
- self.UpdatePlot(plot)\r
-\r
- return dx, unitx, dy, unity\r
+ playlist = self.GetActivePlaylist()\r
+ if playlist is not None:\r
+ destination = self.GetStringFromConfig('core', 'copylog', 'destination')\r
+ if not os.path.isdir(destination):\r
+ os.makedirs(destination)\r
+ for current_file in playlist.files:\r
+ if current_file.note:\r
+ shutil.copy(current_file.filename, destination)\r
+ if current_file.driver.filetype == 'mfp1d':\r
+ filename = current_file.filename.replace('deflection', 'LVDT', 1)\r
+ path, name = os.path.split(filename)\r
+ filename = os.path.join(path, 'lvdt', name)\r
+ use_LVDT_folder = self.GetBoolFromConfig('core', 'copylog', 'use_LVDT_folder')\r
+ if use_LVDT_folder:\r
+ destination = os.path.join(destination, 'LVDT')\r
+ shutil.copy(filename, destination)\r
\r
def do_plotmanipulators(self):\r
'''\r
'''\r
self.UpdatePlot()\r
\r
+ def do_preferences(self):\r
+ '''\r
+ Please set general preferences for Hooke here.\r
+ hide_curve_extension: hides the extension of the force curve files.\r
+ not recommended for 'picoforce' files\r
+ '''\r
+ pass\r
+\r
def do_test(self):\r
- self.AppendToOutput(self.config['perspectives']['active'])\r
+ '''\r
+ Use this command for testing purposes. You find do_test in hooke.py.\r
+ '''\r
pass\r
\r
def do_version(self):\r
self.AppendToOutput('Matplotlib version: ' + mpl_version)\r
self.AppendToOutput('SciPy version: ' + scipy_version)\r
self.AppendToOutput('NumPy version: ' + numpy_version)\r
+ self.AppendToOutput('ConfigObj version: ' + configobj_version)\r
+ self.AppendToOutput('wxPropertyGrid version: ' + '.'.join([str(PROPGRID_MAJOR), str(PROPGRID_MINOR), str(PROPGRID_RELEASE)]))\r
self.AppendToOutput('---')\r
self.AppendToOutput('Platform: ' + str(platform.uname()))\r
- #TODO: adapt to 'new' config\r
- #self.AppendToOutput('---')\r
- #self.AppendToOutput('Loaded plugins:', self.config['loaded_plugins'])\r
+ self.AppendToOutput('******************************')\r
+ self.AppendToOutput('Loaded plugins')\r
+ self.AppendToOutput('---')\r
+\r
+ #sort the plugins into alphabetical order\r
+ plugins_list = [key for key, value in self.plugins.iteritems()]\r
+ plugins_list.sort()\r
+ for plugin in plugins_list:\r
+ self.AppendToOutput(plugin)\r
+\r
+ def UpdateNote(self):\r
+ #update the note for the active file\r
+ active_file = self.GetActiveFile()\r
+ if active_file is not None:\r
+ self.panelNote.Editor.SetValue(active_file.note)\r
\r
def UpdatePerspectivesMenu(self):\r
#add perspectives to menubar and _perspectives\r
perspectiveFile = open(filename, 'rU')\r
perspective = perspectiveFile.readline()\r
perspectiveFile.close()\r
- if perspective != '':\r
+ if perspective:\r
name, extension = os.path.splitext(perspectiveFilename)\r
if extension == '.txt':\r
self._perspectives[name] = perspective\r
perspectives_list.sort()\r
\r
#get the Perspectives menu\r
- menu_position = self.MenuBar.FindMenu('Perspectives') \r
+ menu_position = self.MenuBar.FindMenu('Perspectives')\r
menu = self.MenuBar.GetMenu(menu_position)\r
#delete all menu items\r
for item in menu.GetMenuItems():\r
if playlist is not None:\r
if playlist.index >= 0:\r
self.statusbar.SetStatusText(playlist.get_status_string(), 0)\r
+ self.UpdateNote()\r
self.UpdatePlot()\r
\r
def UpdatePlot(self, plot=None):\r
\r
- def add_to_plot(curve):\r
+ def add_to_plot(curve, set_scale=True):\r
if curve.visible and curve.x and curve.y:\r
+ #get the index of the subplot to use as destination\r
destination = (curve.destination.column - 1) * number_of_rows + curve.destination.row - 1\r
+ #set all parameters for the plot\r
axes_list[destination].set_title(curve.title)\r
- axes_list[destination].set_xlabel(curve.units.x)\r
- axes_list[destination].set_ylabel(curve.units.y)\r
+ if set_scale:\r
+ axes_list[destination].set_xlabel(curve.prefix.x + curve.units.x)\r
+ axes_list[destination].set_ylabel(curve.prefix.y + curve.units.y)\r
+ #set the formatting details for the scale\r
+ formatter_x = lib.curve.PrefixFormatter(curve.decimals.x, curve.prefix.x, use_zero)\r
+ formatter_y = lib.curve.PrefixFormatter(curve.decimals.y, curve.prefix.y, use_zero)\r
+ axes_list[destination].xaxis.set_major_formatter(formatter_x)\r
+ axes_list[destination].yaxis.set_major_formatter(formatter_y)\r
if curve.style == 'plot':\r
- axes_list[destination].plot(curve.x, curve.y, color=curve.color, label=curve.label, zorder=1)\r
+ axes_list[destination].plot(curve.x, curve.y, color=curve.color, label=curve.label, lw=curve.linewidth, zorder=1)\r
if curve.style == 'scatter':\r
axes_list[destination].scatter(curve.x, curve.y, color=curve.color, label=curve.label, s=curve.size, zorder=2)\r
+ #add the legend if necessary\r
+ if curve.legend:\r
+ axes_list[destination].legend()\r
\r
if plot is None:\r
active_file = self.GetActiveFile()\r
if not active_file.driver:\r
+ #the first time we identify a file, the following need to be set\r
active_file.identify(self.drivers)\r
+ for curve in active_file.plot.curves:\r
+ curve.decimals.x = self.GetIntFromConfig('core', 'preferences', 'x_decimals')\r
+ curve.decimals.y = self.GetIntFromConfig('core', 'preferences', 'y_decimals')\r
+ curve.legend = self.GetBoolFromConfig('core', 'preferences', 'legend')\r
+ curve.prefix.x = self.GetStringFromConfig('core', 'preferences', 'x_prefix')\r
+ curve.prefix.y = self.GetStringFromConfig('core', 'preferences', 'y_prefix')\r
+ if active_file.driver is None:\r
+ self.AppendToOutput('Invalid file: ' + active_file.filename)\r
+ return\r
self.displayed_plot = copy.deepcopy(active_file.plot)\r
#add raw curves to plot\r
self.displayed_plot.raw_curves = copy.deepcopy(self.displayed_plot.curves)\r
- #apply all active plotmanipulators and add the 'manipulated' data\r
- for plotmanipulator in self.plotmanipulators:\r
- if self.GetBoolFromConfig('core', 'plotmanipulators', plotmanipulator.name):\r
- self.displayed_plot = plotmanipulator.method(self.displayed_plot, active_file)\r
+ #apply all active plotmanipulators\r
+ self.displayed_plot = self.ApplyPlotmanipulators(self.displayed_plot, active_file)\r
#add corrected curves to plot\r
self.displayed_plot.corrected_curves = copy.deepcopy(self.displayed_plot.curves)\r
else:\r
self.displayed_plot = copy.deepcopy(plot)\r
\r
figure = self.GetActiveFigure()\r
-\r
figure.clear()\r
- figure.suptitle(self.displayed_plot.title, fontsize=14)\r
\r
+ #use '0' instead of e.g. '0.00' for scales\r
+ use_zero = self.GetBoolFromConfig('core', 'preferences', 'use_zero')\r
+ #optionally remove the extension from the title of the plot\r
+ hide_curve_extension = self.GetBoolFromConfig('core', 'preferences', 'hide_curve_extension')\r
+ if hide_curve_extension:\r
+ title = lh.remove_extension(self.displayed_plot.title)\r
+ else:\r
+ title = self.displayed_plot.title\r
+ figure.suptitle(title, fontsize=14)\r
+ #create the list of all axes necessary (rows and columns)\r
axes_list =[]\r
-\r
number_of_columns = max([curve.destination.column for curve in self.displayed_plot.curves])\r
number_of_rows = max([curve.destination.row for curve in self.displayed_plot.curves])\r
-\r
for index in range(number_of_rows * number_of_columns):\r
axes_list.append(figure.add_subplot(number_of_rows, number_of_columns, index + 1))\r
\r
+ #add all curves to the corresponding plots\r
for curve in self.displayed_plot.curves:\r
add_to_plot(curve)\r
\r
#make sure the titles of 'subplots' do not overlap with the axis labels of the 'main plot'\r
figure.subplots_adjust(hspace=0.3)\r
\r
- #TODO: add multiple results support to fit in curve.results:\r
- #get the fit_function results to display\r
- fit_function_str = self.GetStringFromConfig('results', 'show_results', 'fit_function')\r
+ #display results\r
self.panelResults.ClearResults()\r
- plot = self.GetActivePlot()\r
- if plot is not None:\r
- if plot.results.has_key(fit_function_str):\r
- for curve in plot.results[fit_function_str].results:\r
- add_to_plot(curve)\r
- self.panelResults.DisplayResults(plot.results[fit_function_str])\r
- else:\r
- self.panelResults.ClearResults()\r
-\r
+ if self.displayed_plot.results.has_key(self.results_str):\r
+ for curve in self.displayed_plot.results[self.results_str].results:\r
+ add_to_plot(curve, set_scale=False)\r
+ self.panelResults.DisplayResults(self.displayed_plot.results[self.results_str])\r
+ else:\r
+ self.panelResults.ClearResults()\r
+ #refresh the plot\r
figure.canvas.draw()\r
\r
- for axes in axes_list:\r
- #TODO: add legend as global option or per graph option\r
- #axes.legend()\r
- axes.figure.canvas.draw()\r
-\r
-\r
if __name__ == '__main__':\r
\r
## now, silence a deprecation warning for py2.3\r
app = Hooke(redirect=redirect)\r
\r
app.MainLoop()\r
-\r
-\r