Tutorial: Adding new functionality to RepTate¶
Goals¶
In this section, we will present how to create a new RepTate application. We will show the important steps needed to build a new RepTate application. To do so, we will need to modify some already existing RepTate code, as well as writing new custom code.
As an example, let us say that we want to create a new RepTate application that:
accepts text files (
.xy
) which are supposed to be composed of:a first line (header) containing the
date
and temperatureT
two columns containing data \(x\) and \(y\)
allows to view the data:
without transformation, \(x\) vs \(y\)
\(x\) vs \(\sqrt{y}\)
has a theory: a simple line fitting with two parameters \(a\) and \(b\) such that \(y = ax+b\).
Tip
Each time we need to modify or add some line of Python code, the line number is indicated
on the left hand side for information.
This should correspond to the same line numbering for the “template” files, but might
be different for the files in the core/
or gui/
folders.
New application¶
Create a new application file¶
To create a new RepTate application, we will use the template
application file ApplicationTemplate.py
that can be found in the
applications/
folder.
Make a copy of this file and rename it with a sensible name that relates to the application purpose. According to the Goals section, we name it
ApplicationXY.py
.Open
ApplicationXY.py
with your favourite text editor and replace all the occurrences of “Template” by “XY”. For example,44 class ApplicationTemplate(QApplicationWindow):
becomes
44 class ApplicationXY(QApplicationWindow):
Give a brief description of the purpose of the application, e.g. “Application reading XY files”. The first lines of
ApplicationXY.py
should now look like33"""Module ApplicationXY 34 35Application reading XY files 36 37"""
The file ApplicationXY.py
is ready for the next round of modifications
that are (i) file types accepted by the application, (ii) the views,
and (iii) the theories, as defined in the Goals section.
But first, we have to let RepTate know about our new application.
Edit RepTate’s QApplicationManager
¶
We need to add a reference to this new application into
RepTate’s QApplicationManager
, so it knows it exists. To do so:
Insert this line in the top part of the file
gui/QsApplicationManager.py
, e.g.77from RepTate.applications.ApplicationXY import ApplicationXY
Insert the following line to add an entry to the
QApplicationManager
dictionary155self.available_applications[ApplicationXY.appname] = ApplicationXY
In order to have our new application available in the Graphical User Interface (GUI), we need to create a new “button” that will launch our new application when clicked.
Add a button in the main RepTate tool-bar by inserting the following lines in the
__init__
method ofgui/QApplicationManager.py
. The icon name (filename) should correspond to theappname
, hereXY.png
. See the section New Icons to create and use your onwn icon in RepTate.258 # ApplicationXY button 259 #choose the button icon 260 icon = QIcon(':/Icon8/Images/new_icons/XY.png') 261 tool_tip = 'XY' # text that appear on hover 262 self.actionXY = QAction(icon, tool_tip, self) 263 #insert the new button before the "MWD" button 264 self.toolBarApps.insertAction(self.actionMWD, self.actionXY)
The new button has been successfully inserted into the application tool bar. However, if we click on it, nothing happens because it is not linked to any action. We need to “wire” (connect) this new button to a “function”. In the same file
gui/QApplicationManager.py
, below the previous lines, add266 #connect button 267 self.actionXY.triggered.connect(lambda: self.handle_new_app('XY'))
Warning
The application name (
appname
), defined at line 46 ofApplicationXY.py
, should then be “XY”. Additionally, the icon name defining the logo of the new application should be named “XY.png”, see the definition of thehandle_new_app
method.
Note
Our new application is ready to be used in RepTate!
Note on default theories¶
By default, some “basic theories” are included with the application
(e.g. polynomial, power-law, exponential). To remove all these
“basic theories” from your new application, comment the following line
in the __init__
method of class ApplicationXY
135self.add_common_theories() # Add basic theories to the application
New file type¶
RepTate applications are designed to accept a only a
predefined file extension. As defined in the Goals section,
we want our new application ApplicationXY.py
to accept .xy
files.
To do so, we modify ApplicationXY.py
as follows.
In class ApplicationXY
, before def __new__
, add
48extension = "xy" # drag and drop this extension automatically opens this application
In the __init__
method of class ApplicationXY
add
86# set the type of files that ApplicationTemplate can open
87ftype = TXTColumnFile(
88 name='XY data', # name the type of data
89 extension='xy', # file extension
90 description='XY data from XY-experiment',
91 col_names=['X', 'Y'], # name the variables for legend
92 basic_file_parameters=['date', 'T'], # parameter in file header
93 col_units=['-', '-']) # units of X and Y (here none)
New view¶
About the “old” view¶
At the moment, only one view is allowed in our new ApplicationXY
.
That view is located in the __init__
method of
class ApplicationXY
:
62# VIEWS
63# set the views that can be selected in the view combobox
64self.views['y(x)'] = View(
65 name='y(x)',
66 description='y as a function of x',
67 x_label='x',
68 y_label='y(x)',
69 x_units='-',
70 y_units='-',
71 log_x=False,
72 log_y=False,
73 view_proc=self.viewyx,
74 n=1,
75 snames=['y(x)'])
The important attributes of the view called “y(x)” are:
the x- and y-label to be used in the plot,
the units that are appended to the x- and y-labels,
the
log_x
andlog_y
define whether the axes should be in in log-scale (base 10)self.viewyx
is the method that defines what operations are done on the data before plotting them (see below),n
defines the number of series the view is plotting.
In the line below, you can define the default number of view, i.e., the number of views that appear when you open the appliction. In case the new application would benefit from having multiple views shown at the same time (similar to the React or Stress Relaxation applications), this number can be increased (up to 4)
75# set multiviews
76# default view order in multiplot views, set nplots=1 for single view
77self.nplots = 1
The definition of the method viewyx
is
given by
108def viewyx(self, dt, file_parameters):
109 """Documentation"""
110 x = np.zeros((dt.num_rows, 1))
111 y = np.zeros((dt.num_rows, 1))
112 x[:, 0] = dt.data[:, 0]
113 y[:, 0] = dt.data[:, 1]
114 return x, y, True
The two lines x[:, 0] = dt.data[:, 0]
and y[:, 0] = dt.data[:, 1]
tell us that viewyx
does not perform any operations on the data.
It simply copies the input data into x
and y
arrays. It means that
we already have one of the views required from the Goals section.
Definition of a new view¶
To define a new view that shows \(x\) vs \(\sqrt{y}\), as
requested in the Goals section, we add a view to
self.views
dictionary. The new view is called “sqrt(y)”.
In the __init__
method of class ApplicationXY
, add
74self.views['sqrt(y)'] = View(
75 name='sqrt(y)',
76 description='sqrt(y) as a function of x',
77 x_label='x',
78 y_label='$y^{1/2}$',
79 x_units='-',
80 y_units='-',
81 log_x=False,
82 log_y=False,
83 view_proc=self.view_sqrt_y,
84 n=1,
85 snames=['sqrt(y)'])
Tip
The x_label
and y_label
support LaTeX-like syntax.
We also need to define the new method view_sqrt_y
.
In class ApplicationXY
, add the definition
118def view_sqrt_y(self, dt, file_parameters):
119 """Documentation"""
120 x = np.zeros((dt.num_rows, 1))
121 y = np.zeros((dt.num_rows, 1))
122 x[:, 0] = dt.data[:, 0]
123 y[:, 0] = (dt.data[:, 1])**0.5
124 return x, y, True
Note
The new view is ready!
New theory¶
Create a new theory file¶
To create a new RepTate application, we will use the template
theory file TheoryTemplate.py
that can be found in RepTate
theories/
folder.
Make a copy of this file and rename it with a sensible name that relates to the theory purpose. According to the Goals section, we name it
TheoryLine.py
.Open
TheoryLine.py
with your favourite text editor and replace all the occurrences of “Template” by “Line”. For example,42 class TheoryTemplate(QTheory):
becomes
42 class TheoryLine(QTheory):
Give a brief description of the purpose of the application, e.g. “ Theory fitting a line to the data”. The first lines of
TheoryLine.py
should now look like33"""Module TheoryLine 34 35Theory fitting a line to the data 36 37""" 38import numpy as np
The file TheoryLine.py
is ready for the next round of modifications
that are (i) define the parameters, (ii) define the theory “function”.
But first, we have to let ApplicationXY (developed just above) know about
our new theory.
Edit ApplicationXY.py
¶
We need to add a reference to this new theory into
ApplicationXY.py
, so it knows it exists. To do so:
Insert the following line in the
__init__
method ofclass ApplicationXY
, after the “# IMPORT THEORIES
” comment54 # IMPORT THEORIES 55 # Import theories specific to the Application e.g.: 56 from RepTate.theories.TheoryLine import TheoryLine
Hint
We choose to place the theories
import
inside the__init__
method ofclass ApplicationXY
rather than in the very top of the fileApplicationXY.py
as this prevents RepTate from loading all theories at start. Instead, theories are loaded only when an application using them is opened.Insert the following line, also in the
__init__
method ofclass ApplicationXY
, after the# THEORIES
, and beforeself.add_common_theories()
, the line102 self.theories[TheoryLine.thname] = TheoryLine
Edit the theory¶
According to the Goals section, the theory should define a straight line \(y=ax+b\), hence there are two parameters. We will (i) write a short documentation of our new theory, (ii) define the parameters, and (iii) write the main function that calculates the theory values.
Add a Python docstring to (auto)-document the theory. Place some description of the goal of the theory as well as a description of the parameters. This will help future reader of the file understand the purpose of the theory and it will be automatically integrated to the online RepTate documentation (reptate.readthedocs).
42 class TheoryLine(QTheory): 43 """Fit a straight line. 44 45 * **Function** 46 .. math:: 47 y = a x + b 48 49 * **Parameters** 50 - :math:`a`: slope of the line 51 - :math:`b`: the :math:`y`:-intercept 52 53 """
To define the theory parameters, \(a\) and \(b\), we modify the
__init__
method ofclass TheoryLine
to have only these two parameter definitions60 self.parameters['a'] = Parameter( 61 name='a', 62 value=1, 63 description='parameter a', 64 type=ParameterType.real, 65 opt_type=OptType.opt) 66 self.parameters['b'] = Parameter( 67 name='b', 68 value=0, 69 description='parameter b', 70 type=ParameterType.real, 71 opt_type=OptType.opt)
The important attributes of the parameters are:
value
: the initial value of the parametertype
: defines if he parameter is real, integer or discreteopt_type
: optimisation type is eitherconst
for constant parameter (cannot be optimised),opt
if the parameter is optimised by default,nopt
if the parameter can be optimised but is not by default.
Modify the method
calculate
ofclass TheoryLine
89 ft = f.data_table 90 tt = self.tables[f.file_name_short] 91 tt.num_columns = ft.num_columns 92 tt.num_rows = ft.num_rows 93 tt.data = np.zeros((tt.num_rows, tt.num_columns)) 94 a = self.parameters['a'].value 95 b = self.parameters['b'].value 96 tt.data[:, 0] = ft.data[:, 0] # x values 97 tt.data[:, 1] = a * ft.data[:, 0] + b # y values
Hint
The file type of
ApplicationXY
defined in section New file type tells us that there are two columns in the data files. Hence, the theory data also have two columns to populate. For example of application/theory using more than two data columns, seeclass ApplicationLVE
ofApplicationLVE.py
andclass TheoryMaxwellModesFrequency
ofTheoryMaxwellModes.py
.The information from the data file header, in our example
date
andT
, can be called via, e.g.T = float(f.file_parameters["T"])
. Parameters are stored as strings, hence thefloat
conversion.
Note
The new “Line” theory is ready to be used in our new ApplicationXY!
New Icons¶
Application icons are stored in a compiled resource file
gui/MainWindow_rc.py
.
In order to add a new icon to this resource file, that can later be used as
a button icon for instance, we need to
Modify the file
gui/MainWindow.qrc
by opening it in a text editor and add the relative path of the new image or icon we want to have in the resource file. For instance:copy and paste you favourite icon
my_favourite_icon.png
in thegui/Images/new_icons/
folder.add the line
<file>Images/new_icons/my_favourite_icon.png</file>
to the filegui/MainWindow.qrc
Re-compile the file
MainWindow_rc.py
into a resource fileMainWindow_rc.py
by running the following command in a terminal (assuming the current working directory isgui/
)$ rcc MainWindow.qrc -o MainWindow_rc.py
Note
Your new icon my_favourite_icon.png
is now ready to be used
by Qt:
icon = QIcon(':/Icons/Images/new_icons/my_favourite_icon.png')