==========
peak-o-mat
==========
:Author: Christian Kristukat
:Contact: ckkart@users.sf.net
:Revision: $Revision: 1.1.2 $
:Date: $Date: 2010-9-1 $
:Copyright: This software has been placed under the GNU public license.

.. meta::
  :description: peak-o-mat is a cross-platfrom curve fitting program
  :keywords: peak fitting, curve fitting, data fitting, fitting, least squares

peak-o-mat is a  data analysis and curve fitting program  written in Python.  It
is especially  designed to fit spectroscopic  data but should be  suited for any
other fitting task.  It allows for clearing, transforming, fitting, calibrating,
etc. of  spectra with few  mouse clicks.  peak-o-mat  can easily be  extended by
writing own modules.  It is being  developed on linux and windows but should run
on any  other platform for which  python and the extension  modules listed below
are available.

If you find peak-o-mat useful consider to make a `donation
<http://sourceforge.net/donate/index.php?group_id=67624>`_.

Getting the software
====================

peak-o-mat is available on the sourceforge download page at:

  https://sourceforge.net/project/showfiles.php?group_id=67624

See the `change log <CHANGELOG>`_ for the list of changes.

Requirements
------------

- Python >= 2.5 (http://www.python.org) 

- wxPython >= 2.8-unicode (http://www.wxpython.org)

- numpy >= 1.0 and scipy >= 0.5.2 (http://www.scipy.org)

Installation from source
------------------------

Download the  source tarball and  unpack it somewhere.   It is not  necessary to
install peak-o-mat. Just enter::

  python peak-o-mat.py

Installation from binary package
--------------------------------

Windows binary  packages of peak-o-mat  are available. Everything needed  to run
peak-o-mat is included in there. You do not need to install any other software.

Basic Concepts
==============

Data
----

The data  is stored in a  tree-like structure.  There is  one top-level element,
the *project*.  The next  lower level is that of the *plots*,  each of which can
hold an arbitrary  number of *sets*.  A  *set* is a 2d array  containing the x-y
data, where  the x-data is ordered  (typical for spectroscopic  data). This data
structure is represented by  the tree view on the right side  of the main frame.
In addition to the plain x-y data, a set can have various objects attached, such
as transformations (*trafo*), a fit *model* and *weights*.

Unlike  some   other  data  analysis   programs,  peak-o-mat  allows   for  data
manipulation/transformation on  a higher  level than operating  on the  raw data
through a spreadsheet  like interface.  As peak-o-mat is  especially designed to
work  with spectroscopic  data, arithmetics  on *sets*  will do  what  you would
expect  intuitively, e.g.  adding  two *sets*  will only  add the  y-data, while
interpolating the x-axes in case they differ. Those kind of manipulations can be
done  using the  'Set operations'  module.  If you  need to  do more  complicate
operations, you can still copy the data to a *data grid* and manipulate the data
there through a python shell.

Models
------

A *model* is an  analytical function to which the set data  is fitted. It can be
described by

- a valid  python expression, where *x*  stands for the set's  x-values. You can
  use   arbitrary    variable   names   containing    alphanumeric   characters,
  e.g.  "a*exp(-b0*x**2)", and all  functions/symbols defined  in the  top level
  namespace of the *numpy* package.
  
- a space  separated list  of pre-defined symbols,  here called  *tokens*, which
  represent common backgrounds and peak shapes.  The function values represented
  by the tokens are finally added, e.g.  "CB LO GA LO" represents a model with a
  constant background, one gaussian peak  and two lorenzian peak shapes. You can
  append a number  to any token to  be able to distinguish them  later, e.g. "CB
  LO1 GA LO2".   Instead of the whitespace between the  tokens, the '+' operator
  can  be used.  In  some rare  cases you  might want  to multiply  the function
  represented by  the tokens.  This can  be achieved by using  the '*' operator.
  The model  is evaluated from  left to  right and the  usual sign rules  do not
  apply!

Transformations and masks
-------------------------

A *trafo* denotes  any transformation of the  x- or y-data of a  set. Instead of
changing the  original data, all trafos are  attached to a set  and evaluated on
demand whenever the  set data is accessed.  Like this, the  original data can be
restored by  simply removing  all trafos.  Furthermore,  if you remove  bad data
points from  a set, a *mask*  is applied to the  data so that all  points can be
restored at any time.

Weights
-------

to be written ...

GUI elements
============

The tree
--------

The tree control on the right side  of the main window reflects the structure of
the project. All  sets in one plot are  shown together in the plot  area left of
the  tree.  The  currently  selected set  is  displayed in  red,  the others  in
black. You  can select all  sets of a  plot by selecting the  corresponding plot
item  or  (only  on  wxGTK)  a  subset  of sets  within  one  plot  by  pressing
SHIFT/CTRL-keys while  selecting.  Sets can be  hidden and will thus  show up in
the plot area only if they are  part of the current selection. The tree supports
drag&drop of  plot and set items.   Press twice on  any tree item to  rename its
label.


The toolbar
-----------

.. |log| image:: images/log.png 
.. |auto| image:: images/auto.png 
.. |eraser| image:: images/eraser.png 
.. |hand| image:: images/hand.png 
.. |zoom| image:: images/zoomxy.png 
.. |autox| image:: images/scalex.png 
.. |autoy| image:: images/scaley.png 
.. |auto2fit| image:: images/auto2fit.png 
.. |peak| image:: images/peaks.png 
.. |linestyle| image:: images/linestyle.png 

|zoom| Zoom  mode: draw a rectangle around  the desired to zoom  in, click right
 button to zoom out.

|auto| Autoscale

|autox| Autoscale in x-direction only.

|autoy| Autoscale in y-direction only.

|auto2fit| Zoom to the extension of the fit model.

|hand| Drag mode: drag the visible plot area.

|eraser| Erase mode:  draw a rectangle around points to  be erased. This applies
to the current selection and can be undone.

|log| Toggles the y-scale between linear and log10.

|peak| Shows each peak of the current model in addition to the sum.

|linestyle| Toggles the style of the set data between *line* and *points*.

The data grid
-------------

To open  a data grid, which allows  for direct data manipulation  using a python
shell, choose 'Data->New data  grid' in the menu. To copy a  set's x/y-data to a
new data  grid, select 'copy to  data grid' from  the popup menu in  the project
tree.  The data grid named *exported fit paramters* is of particular interest as
it  is the  target when  exporting the  fitted parameters.   In contrast  to the
normal data  grid pages  one row  label is always  painted in  red. This  is the
target row for  the new parameters.  It will  move downwards automatically after
having recieved a new set  of parameters, extending the datagrid when necessary.
The target row can be placed manually by double-clicking on a row label.

Each data  grid page contains a  python shell window  which can be used  like an
ordinary  python  shell.   In  addition,  the following  global  attributes  are
available which allow for accessing and manipulating the data of the data grid::

  _data        : the 2d array data
  _selection   : the selected area of the data grid, applicable as index for
                 data, i.e. data[selection]
  _colN/rowN   : the N-th column/row vector
  _x/_y         : row/column vectors containing the column/row indices

Arrays and  vectors refer  to instances  of the ndarray  object provided  by the
python *numpy* extension (http://numpy.scipy.org). In order to manipulate them a
basic understanding of numpy is necessary.

The data/colN/rowN  attributes can be read  and written. When  assigning to colN
and rowN, the new value has to  have the correct shape. This is best illustrated
in a small example::

  >>> import numpy as N
  >>> _data=N.zeros((50,3))
  >>> _col0=y
  >>> _col1=_y**2+2*_x-2
  >>> _col2=1/_col1
  >>>

*Inserting/deleting/appending rows or columns*

To insert/delete/append  rows/columns, select  some rows/columns by  clicking on
the row/column labels and then choose insert/delete/append from the popup menu.

*copy&paste*

You can copy and paste data  from other applications to the spreadsheet and vice
versa using  the context menu.   When choosing *paste&replace*  the spreadsheets
content will be replaced with the  content of the clipboard, *paste* will try to
insert  the clipboard's  content to  the selected  region. Therefor  the current
selection area has to have the same shape as the data to be inserted.

*insert/delete&shift*

In a usual  peak-o-mat session you will  fit a series of spectra  and export the
fitted  parameters to  the spreadsheet.   In case  the number  of  peaks changes
within the series,  the parameter table might get misaligned in  case the new or
the missing feature  is not the last feature in the  model description.  In that
case,  some  parameters   will  be  placed  in  the   wrong  column.   Here  the
*insert/delete&shift* menu  item comes in  handy. You can choose  an arbitrarily
sized area and delete it followed by  shifting either the data right to the area
to the left or  shifting the data below the area upwards.   The same applies for
inserting data, in that case zeros  will be inserted.  The other rows or columns
remain unaffected by those operations, if necessary zeros will be padded.

The modules
===========

A module  is a  small functional unit  which adds  a feature to  peak-o-mat. The
available modules appear as notebook tabs  in the lower part of the main window.
The only  built-in module is the *Fit*  module.  All other modules  consist of a
python source (.py) and a XRC (.xrc)  file, the latter describing the GUI of the
module.

Fit
---

This is the core module of peak-o-mat.

Data operations
---------------

As mentioned  before, manipulations of  the set data  can be done on  a higher
level than editing the x- and  y-data directly.  

Operations  on the  sets can  be  either an  operation between  the y-values  of
different sets (inter-set)  or a transformation of either the  x- or y-values of
one set (intra-set).   In the former case,  a new set is created,  in the latter
case the transformation is attached to  the current set and can be removed later
thus restoring the original data.  The  sets can be referenced by the identifier
'sX', where X is the set number of the active plot shown in the tree view on the
right side.   Inter-set operations  are only possible  between sets of  the same
plot.   The  intra-set  operations  are  applied  to  all  selected  sets.   The
identifiers appearing  in the expression  determine wether the expression  is an
inter-set or an intra-set operation.

examples of valid expressions are::

  x+10              intra-set, x-axis
  1/y               intra-set, y-axis
  log10(y)          intra-set, y-axis
  (s0+s1)/2         inter-set
  sum([s1,s2,s3])   inter-set

Evaluate
--------

This module  allows you to create sets  by evaluating a custom  function or by
drawing a spline on the plot canvas. 

Set info
--------

The set  info module gives  information about the  number of total  and masked
points  of  a  set and  the  list  of  transformations  attached to  it.   The
transformations can be deactivated temporarily by unchecking the corresponding
checkbox,  removed   completely  and  their   comments  can  be   edited  when
double-clicking on the comment field.

Calibration
-----------

calibrate data using spectral lines of Ne,Ar,He,Me, etc.

Shell
-----

shell access to the internals of peak-o-mat (dangerous)

Ruby calibration
----------------

pressure calibration using the R1 luminescence

Customizing peak-o-mat
======================

Config file
-----------

Upon start peak-o-mat looks for a configuration file config.py in
$HOME/./peak-o-mat.  An example config.py file looks like the following::

  # if fast_display is True, only fast_max_pts points of all sets but the
  # active one are shown
  fast_display = False
  fast_max_pts = 500

  # truncate the data upon import
  truncate = False
  truncate_max_pts = 2000
  truncate_interpolate = False

  # set to True if the floating point is ',' (e.g. german windows)
  floating_point_is_comma = False


Adding custom peak shapes
-------------------------

On startup peak-o-mat is importing $HOME/.peak-o-mat/userfunc.py. Put your own
function definitions there according to the following scheme::

  from peak_o_mat import peaks
 
  peaks.add('PAR',
            func='a*x**2+b*x+c',
	    ptype=peaks.ptype.BACKGROUND)
  peaks.add('PEAK',
            func='amp*exp(-(pow(x-pos,2)/(fwhm*fwhm/2.0)))',
            info='a gaussian',
	    ptype=peaks.ptype.PEAK,
            picker=peaks.LOPicker)

peaks.add() is defined as follows::

  def add(self, name, func=None, info='', ptype=None, picker=None):
      name:   uppercase model name, e.g. GA
      info:   an information text describing the model
      func:   the function string
      ptype:  one of ptype.{BACKGROUND,PEAK,EXP,MISC}
      picker: a picker object, e.g. LOPicker, which handles the collection
	      of the function's parameters from mouse actions

You may use any  numpy symbols as if you had imported  numpy like *from numpy
import \**.

If you  do not specify  a *picker*,  the initial guess  for that peak  must be
entered by  hand. Common *pickers* are  defined in the file  *peaks.py* in the
peak-o-mat source distribution.

Installing/Writing Modules
--------------------------

In  order  to use  third-party  or  own modules  move  the  module's files  to
$HOME/.peak-o-mat/modules. peak-o-mat will load  them upon program start.  The
modules    which     are    distributed    with     peak-o-mat    reside    in
<site-packages>/peak_o_mat/modules.  Those global modules have to be listed in
__init__.py at the same location to be activated.

Writing  own   modules  is  easy.    Use  *xrced*  (part  of   every  wxPython
installation) to create a GUI and  save it as *mod_XXX.xrc*. The top-level GUI
element of each module must be  a wx.Panel having the module's filename as XML
ID (in this  case *mod_XXX*). Then add anything you like  but remember to keep
the overall height  of the panel small since the taller  the module's GUI, the
fewer space will  be availabe for the  graphs. If you provide XML  IDs for the
controls,  let the  IDs begin  with  *xrc_*. This  enables you  to access  the
controls by referencing  them as *self.xrc_xxx* in the  program. Then create a
python  source  file, named  *mod_XXX.py*,  which  has  the following  minimal
content::

  from peak_o_mat import module

  Module(module.Module):
      title = 'this modules title'
      def __init__(self, *args):
	  module.Module.__init__(self, __file__, *args)

It  is  absolutely necessary  to  call  the  constructor of  module.Module  as
described above, if not, peak-o-mat will  not be able to find the module's XRC
file.  However do  not add  code to  the constructor  which accesses  the GUI,
instead define the method::
  
  def init(self):
      ....

and use  it like  a constructor.  When  *OnInit* will  be called, the  GUI has
already  been  loaded and  can  be  accessed savely,  e.g.   to  set up  event
bindings.  The Module  class does  not derive  from a  wx control,  however it
provides the following instance variables/methods::

  self.panel       - reference to the panel
  self.controller  - reference to the main controller
  self.project	   - reference to the project data
  self.Bind()      - self.panel.Bind()
  self.Unbind()    - self.panel.Unbind()
  self.xrc_xxx	   - reference to the wx control with
                     the XML ID *xrc_xxx*

See the files template.py/template.xrc in the *modules* subdir for a working
example.

