Sunday, August 17, 2014

MATLAB SFTP with WinSCP

One of the ways to transfer files using SFTP in MATLAB (sort of) is simply to do it in an external tool (e.g., WinSCP). Assuming the tool supports scripting (WinSCP's scripting), you can prepare the scripts first and simply call the tool using the ! command with the path to the script file. A few thoughts: 1. put it in a timer function to automate the transfer 2. dynamically generate the script so that actions can vary in each session 3. wonder if the session can be maintained in which case we could provide some sort of interactivity in MATLAB's command window.

Saturday, May 3, 2014

MATLAB MySQL query datetime column type

When you do a SELECT * in MySQL query from MATLAB, you would expect all the entries in the table to be returned.

Apparently, there are cases where it will not return everything. (Matlab R2013a, MySQL 5.5.32)

It seems that if you have '0000-00-00 00:00:00' in the datetime field of a row, which is the zero value of the datetime type, the row will not be returned even if you do the select all query.

However, if you are querying other columns (besides the datatime column), the row that has the zero value datetime will be returned.



Tuesday, April 15, 2014

moving things to github

I am in the process of moving some of the source code from the past postings into github. It is easier to share, easier to maintain, and easier to get feedback (if any).

https://github.com/weishang

As a side-note/rant, if you look at the source control options for Matlab, I don't know, it feels lacking. With all the options available nowadays (2014), Matlab supports MS visual sourcesafe, whose final version is 2005.


Saturday, February 1, 2014

Multi-'screen' MATLAB GUI

Once again, I had little time cleaning up the post so read at your own risk. :-) 

Why bother?


First and foremost, the multi-screen GUI I am talking about is much like a Single Page Application (SPA) in the context of web application. Everything you see in the GUI can change entirely as you 'navigate' from "screen" to "screen". An example would be an application that has various stages to it, as the user goes from stage to stage, only the relevant information/controls will show on the GUI. Of course, you can always just slap everything on the GUI without considering splitting them into "screens", but you only have so much space on the GUI and every bit of information that shouldn't be there is wasting the UI space.

<begin digression>
Also, one can also implement the application using multiple GUIs instead of multiple screens. Such approach is more appropriate in the case where the different GUIs have to be shown at the same time, but there are distinct features about each GUI so it doesn’t really make sense to put them all in the same GUI, also, reusability is another issue. But that’s a different topic altogether.
<end digression>

Enough background. Below is how.

First of all, there is no such feature (multiple-screen GUI) in Matlab, but there is a little trick we can use to make it appear so, and that is with the use of 'uipanel'.

The concept is fairly simple, assuming you have already got a design in mind, i.e., you are clear about what uicontrols go into to what uipanel, all you need to do is have them populated in the right panels, subsequently, we show and hide the panels as we see fit. Note that the panels should have been resized at this point so they overlap completely, and at any given time, only one panel should be shown (Visible = 'on'), while others are hidden (isVisible = 'off'). (I don't understand why 'on'/'off' are used instead of true/false or 1/0.)

Now, I would strongly recommended creating everything programmatically instead of relying on Matlab’s GUIDE, as the panel will need to be resized, moved around, which is impossible to do in GUIDE. You also need to pay special attention to the unit setting for all the uicontrols when you are doing this, if there is any mis-matches or invalid values, then the uicontrols may not show up, or when you resize the GUI, the uicontrols in a panel may all go crazy.
Below is the link to a fairly simple demo that shows the multi-screen in action of the application. Three buttons to show one of the three panels (much like the tab effect if you just position them in a better way).
https://github.com/weishang/matlab-multiScreen

What else?


The trick described in this post is using overlapping panels as screens and show/hide the panels as you desired. Here’s what else you can do with this trick.
  • A demo application which goes from one screen to the next, much like a slide show. With the help of the timer object (may find this post useful). 
  • A GUI with the ‘tab’ effect 
  • A fully blown single page application 
  • ...

Saturday, August 31, 2013

MATLAB GUI and Timer Object

I shouldn't really started this post at all since I have little time to 'beautify' the post, but what's described in this post can be very useful for someone that needs to have the GUI update itself at a fixed time interval, say, plotting the latest forecast data. Note that it doesn't have to be a fixed timer interval, in fact if you put enough thought into this, the schedule for the updates can be very flexible (by using database, etc).

Be warned though, the quality of the post is lacking, but I will make sure the sample application is running as expected so all you need to do is to expand on it and plug in all the pieces you need/have.

If you are not familiar with MATLAB GUI, you should read up on it (and unfortunately this post is probably not for you). If you are fairly familiar with MATLAB GUI, but haven't used  the timer object much. Here is the documentation, it is best if you try out a few examples that uses timer object without the GUI, just to get a feel for it.

Now, without further ado, below is a walk through of creating a MATLAB GUI-based digital clock (from scratch).

1. Type GUIDE in matlab, and choose to create a blank gui.

2. Create a static text on the GUI, make it and its fontsize big, and tag it as lbl_timeNow

3. Save the GUI (with the name, say, myClock), and open up its m-file.

4. In the OpeningFcn (prefixed with whatever name), insert the following code

timer_obj = timer(...
    'StartFcn',         @user_timer_start, ...              % start function
    'TimerFcn',         {@user_timer_update, hObject}, ...  % timer function, has to specific the handle to the GUI,
    'StopFcn',          @user_timer_stop, ...               % stop function
    'ErrorFcn',         @user_timer_err, ...                % error function
    'ExecutionMode',    'fixedRate', ...                    %
    'Period',           0.1, ...                           % updates every xx seconds
    'TasksToExecute',   inf, ...
    'BusyMode',         'drop');


start(timer_obj);        % start the timer object

setappdata(hObject, 'timer_obj', timer_obj');  % save the timer object as app data

Effectively, we just created and started a timer whose TimerFcn gets executed every 0.1 second. And the timer is saved as the app data so when we try to close the GUI, we can easily get our hands on the timer and get rid of it at the same time. 

5. Implement the user_timer_update function (which is set as the TimerFcn of the timer). Insert the following function to the m file. Notice how it has three input parameters, the last of which was past in in step 5 with '{@user_timer_update, hObject},'.

function user_timer_update(src,evt, fig_handle)

handles = guihandles(
fig_handle);

set(handles.lbl_timeNow, 'string', datestr(now, 'yyyy-mm-dd HH:MM:SS'));


6. Put in the other timer functions, StartFcn, StopFcn, ErrorFcn into the m file. They are just dump text printer for now. 

function user_timer_start(src, evt)
disp('Timer started!');

function user_timer_stop(src, evt)
disp('Timer stop');

function user_timer_err(src, evt)
disp('Timer error');


7.  We are almost done, just need to make sure the timer is removed when we close the GUI. So go to the GUIDE editor, and select 'CloseRequestFcn' property of the figure, it should populate the function in the m file for you. Now, before delete(hObject), put in

stop(getappdata(hObject, 'timer_obj')); % stops the timer 
delete(getappdata(hObject, 'timer_obj'));  % delete the timer object 

8. Now, here is a list of things that you may want to do: 

  • make the gui look pretty 
  • properly implement the other timer functions, StartFcn, StopFcn, etc. 


Here is what it looks like and here are .fig and .m files. 



Well. That's all for now. Good luck. 

Saturday, July 27, 2013

Connecting to (local) MySQL database in MATLAB

If you try to connect to a local MySQL database based on the Matlab documentation on the database function (see connection example here), you are likely to get the 'Unable to find JDBC driver' error. 

To fix the error, first download the JDBC driver from MySQL website. 


Once download, unzip and find the mysql-connector-java-5.0.8-bin.jar (or more current version) file and move it to Matlab's java path ($matlabroot\java\jar\). 

Next, type prefdir in MATLAB and find your preferences folder, once in that folder, create a text file called javaclasspath.txt, and place the $matlabroot\java\jar\name_of_the_jar_file in and save the file, restart Matlab.

Now if you type javalclasspath, you should see the jar file appear at the bottom of the static path.

Finally, to test out if everything works as expected, run 

conn = database('mysql', 'root', 'DB_password', 'com.mysql.jdbc.Driver',  'jdbc:mysql://localhost/');

conn

tables(conn)


close(conn);

* May need to adjust database name, user account, password, driver name, and url of the database. 


Saturday, June 22, 2013

MATLAB Database Toolbox + MS Access + Date Comparison Problem

I was trying to get a date comparison into a simple select statement.

query = 'select * from telemetry where measured_at < `06/06/2012 11:25:00 AM`;';

I kept getting this "super" informative error message.

Error using database/fetch (line 37)
[Microsoft][ODBC Microsoft Access Driver] Too few parameters. Expected 1.

Error in get_DB_conn (line 17)
x = fetch(conn, query);

"Too few parameters". Hmm, I thought I called the function the wrong way. Then again, where statement with other fields worked just fine. Took me sometime to figure out this is a formatting issue. Apparently, I need to place 'special markers' around the date so that it knows it is a date. doh!

Changed to

query = 'select * from telemetry where measured_at < #06/06/2012 11:25:00 AM#;';

and it works fine now.

Maybe it is nice to have this piece of information emphasized somewhere in the documentation?

Monday, July 2, 2012

A simple example of multiple GUIs working together

In this post, I will go over the implementation of a sample MATLAB application based on the comment left by a reader. A summary of the application's description is provided below, and the complete details can be found here. 

In this particular MATLAB application, there are three GUIs, namely, GUI-1, GUI-2 and GUI-3. A screenshot of the three GUIs are provided below, and the "starter code", which will be worked throughout this post, can be download here.

GUI-1 is the 'main' program and it serves as the gateway to the application. It provides a description of the application and has a push button, which when clicked on, will open up GUI-2 and close itself.

On GUI-2, there are multiple edit textboxes for accepting user inputs, there is also a push button, which when clicked on, will open up GUI-3 (if it hasn't been opened yet) and have the user inputs (or some results  computed based on the user inputs) pushed over to GUI-3 for display/presentation.

Note that once the GUI-3 is opened, any change in the user inputs on GUI-2 should trigger an update of the results displayed on GUI-3. There is also a push button on GUI-3, which when clicked on, will close GUI-2 and itself . 

Figure 1. Screenshot of the application 
Based on description above, the challenges faced in having these three GUIs working with each other can be posed as the follow three questions: 
1. How to open another GUI in an existing GUI?
2. How to close another GUI in an existing GUI?
3. How to pass data from one GUI to another GUI?

Opening GUI-2 from GUI-1


To be able to open GUI-2 by clicking a push button on GUI-1, simply call the m-file associated with GUI-2 in the callback of the push button on GUI-1. Using the sample code provided, find the callback function pb_open_Callback in GUI_1.m and add the following code. 

GUI_2_handle = GUI_2; % open GUI_2 and save the handle

To have GUI_1 close itself immediately after opening GUI_2, add the following code after the line above.

delete(get(hObject, 'parent')); % close GUI_1

Note that get(hObject, 'parent') returns the handle of GUI_1, since it is the parent of the push button, which is referred to as the  hObject in its callback. 


Now, save and run GUI_1. When you click on the push button, you should be able to see GUI_2 pops up and GUI_1 closes itself immediately after GUI_2. The updated code can be found here.



Opening GUI-3 from GUI-2, and closing GUI-2 from GUI-3

Opening GUI-3 with the push button on GUI-2 is very similar to what has been done above. However, the one key difference here is that there will be on-going interactions between GUI-2 and GUI-3, and thus, there are issues to be taken care of. For example, if the push button is clicked again after GUI-3 opens, it shouldn't be opening another instance of GUI-3, also, since GUI-3's push button is responsible for closing the whole application, the close functions  (executed when you clicked on the 'x' button at the upper right corner)  in GUI-2 and GUI-3 should not close themselves. 

1. In the opening function of GUI-2, initialize an empty field in the handles structure, which is to be used to hold the handle to GUI-3. The reason why we need to put it into the handles structure is that we will need to access the variable in other sub functions of GUI_2 (see step 2).


handles.GUI_3_handle = [];

2. In the callback of the push button on GUI-2, check to see if GUI-3 is already open, and if it is not, opens it the same way we did for GUI-2.

if isempty(handles. GUI_3_handle )
   % create GUI-3 
   handles. GUI_3_handle  = GUI_3; 
end

3. To be able to close GUI-2 within GUI-3, GUI-3 must have the handle to GUI-2 so that when the push button on GUI-3 is clicked, it will be able to use the delete function to first close GUI-2 and then GUI-3. There are many ways in which you can pass the handle (or any kind of data) from one GUI to another. Since this is a relatively simple example, it is acceptable to not to think too much about re-usability. Below shows the extra code that is responsible for passing the handle of GUI-2 to GUI-3.

if isempty(handles.GUI_3_handle)
   % create GUI-3 
   handles.GUI_3_handle = GUI_3;
   % obtain data in GUI-3
   GUI_3_data = guidata(handles.GUI_3_handle); 
   % store handle to GUI-2 as data in GUI-3
   GUI_3_data.GUI_2_handle = get(hObject,'parent');
   % save the GUI-3 data 
   guidata(handles.GUI_3_handle, GUI_3_data);

   % save the handles structure as data of GUI-2
   guidata(get(hObject,'parent'), handles);

end

4. To make sure the close function does not close the corresponding GUIs, replace the delete function with a dialog box that informs the user about the proper way to close the application. Note that to populate the close function in the m file, open the GUI using GUIDE. Under the figure property, click on the CloseRequestFcn (as shown in Figure 2 below).  

Figure. Creating the CloseRequestFcn in the figure property
In the CloseRequestFcn in the m-file (for both GUI-2 and GUI-3), replace the delete function, with the follow code. (You may want to pick a more appropriate dialog box.)

warndlg('Please click Close Application button on GUI-3','!! Warning !!')

If you try clicking the 'x' on the window to close the GUI, the warning dialog box will pop up and the GUI should stay opened.

5. To have the GUIs closed after the 'Close application' button on GUI-3 is clicked, simply put the following line in the call back of the push button.

delete(handles.GUI_2_handle);  % close GUI-2 
delete(get(hObject,'parent')); % close GUI-3 

Now, the opening and closing of all the GUIs in the application should function properly. The latest code can be downloaded here.

Updating results on GUI-3 from GUI-2


Based on the description of the application, when GUI-3 is opened from GUI-2, the results should be computed and then shown on GUI-3. In the callback of the push button on GUI-2, after the if-end block in which we open GUI-3 if it hasn't been created yet, we will add more code to take care of the computation of the results and the update of the results on GUI-3. The added code is highlighted in red below. 


if isempty(handles.GUI_3_handle)
   % create GUI-3 
   handles.GUI_3_handle = GUI_3; 
   % obtain data in GUI-3
   GUI_3_data = guidata(handles.GUI_3_handle); 
   % store handle to GUI-2 as data in GUI-3
   GUI_3_data.GUI_2_handle = get(hObject,'parent');
   % save the GUI-3 data 
   guidata(handles.GUI_3_handle, GUI_3_data);

   %save the handles structure as data of GUI-2
   guidata( get(hObject,'parent'), handles);

end
% GUI-3 must exist at this point. 

% obtain data stored in GUI_3 
GUI_3_data = guidata(handles.GUI_3_handle); 
% compute result based on input 1 on GUI_2 and update result 1 on GUI_3
input1 = str2double( get(handles.txt_input1, 'string'));
set(GUI_3_data.lbl_res1, 'string', num2str( input1 * rand));
% compute result based on input 2 on GUI_2 and update result 2 on GUI_3
input2 = str2double( get(handles.txt_input2, 'string'));
set(GUI_3_data.lbl_res2, 'string', num2str( input2 * rand));


For simplicity's sake, I compute the results as random numbers generated based on the inputs. Regardless of how complicated the computation can get, it is irrelevant to how the update is done. You can simply apply the set function on the static text fields on GUI-3, which are lbl_res1 and lbl_res2, to change the strings based on the "computed" results. Of course, it doesn't have to be static text fields, it can be an axes, it can be a list, as long as you can use the set function to modify the property of the uicontrol as a way to present the result, this approach would work. 


At this point, any time you click on the "Show results" button on GUI-2 , you should be able to see the results being updated on GUI-3. Next, we can work on the edit text on GUI-2, so that whenever a new input is entered (triggered by the focus leaving the text box or hitting the enter key in the text box), the corresponding result will be updated in GUI-3. First, go to the callback of input1's edit box, and add the following code.

% obtain data stored in GUI_3 
GUI_3_data = guidata(handles.GUI_3_handle); 
% compute result based on input 1 on GUI_2 and update result 1 on GUI_3
input1 = str2double( get(handles.txt_input1, 'string'));
set(GUI_3_data.lbl_res1, 'string', num2str( input1 * rand));

Then, for the callback of input2's edit box, add the following code

% obtain data stored in GUI_3 
GUI_3_data = guidata(handles.GUI_3_handle); 
% compute result based on input 2 on GUI_2 and update result 2 on GUI_3
input2 = str2double( get(handles.txt_input2, 'string'));
set(GUI_3_data.lbl_res2, 'string', num2str( input2 * rand));


At this point, if you update the inputs individually, you will see the corresponding results being updated on GUI-3 as well. The updated code can be downloaded here.


Things to consider

Note that what has been present here is a quick and easy way of getting things done. I would recommend this approach only if you have full knowledge of all the GUIs in the application and you don't plan to re-use any of the GUIs in the same or different application.

to be continued

Related links:
"Making Multiple GUIs Work Together" on mathworks.com

Wednesday, June 27, 2012

Sharing data among MATLAB GUIs: Part 3

In this post, I am going to share some of my principles in designing the data sharing among GUIs and use an example in the comment left by Anonymous to demonstrate how they work. 

The design procedure is fairly straightforward, simply following the four steps below should give you a clear picture as to how the data is communicated among all the GUIs in the application. 

1. Draw out all the GUIs. 
2. Connect the GUIs that will share data.
3. Determine the flow of the data for each connection.
4. Determine the possible action (push and/or pull) associated with the flow of data. 


Let's try it with the sample problem below:

I am working on 3 GUIs (using GUIDE). GUI-1 will call GUI-2 (used to collect user inputs, process the input data) and then output the results to GUI-3. 

Based on the description of the problem, the diagram in Figure 1 depicts the process of the design. Step 1 involves drawing there blocks for GUI-1, GUI-2, and GUI-3. Since it is stated that GUI-1 will call GUI-2 and then outputs the results to GUI-3, so connections are drawn between GUI-1 and GUI-2, GUI-1 and GUI-3. For the same reason, the flow of the data can be easily determined as from GUI-2 to GUI-1, and from GUI-1 to GUI-3. In Step 4, since it was stated that GUI-1 will call GUI-2, so I assign the pull action to the flow of data from GUI-2 to GUI-1, and since the data is processed by GUI-1 and output to GUI-3, I assign a push action to the flow of data from GUI-1 to GUI-3. 

Figure 1. A sample design process
In the next post, we will look at how to implement the data sharing based on the design. 

Monday, May 14, 2012

Drawing path taken in MATLAB

In this entry, I am showing a way of plotting path in MATLAB, which is often seen in pattern recognition and statistical modelling technique, for example, the Needleman-Wunsch algorithm and the Hidden Markov Models. Provided that the length of the output sequence is relatively short, and there are limit number of states, it may be beneficial to be able to visualize the path.

Below is an example based on the Needleman-Wunsch algorithm for sequence alignment. Note that all the cells are shown in the plot as text objects, and the available path is shown as thin lines while the optimal path obtained from the back tracking process is shown as thicker lines.
Note that even though the lines appear as broken segments in the plot, they are not drawn as such. It is rather difficult to figure out the starting and ending points of the line to produce a consistent and nice-looking plot. Instead, the lines are drawn between the centers of the text boxes. It looks like segments because there are solid white circles drawn on top of the lines, effectively, we are covering parts of the lines using white circles. Note that you can use rectangle(), which is a MATLAB function, to draw the circles, and you can set their facecolor and edgecolor to white, which will give the circles with solid white background.

The trick is to know that all the graphic objects are being placed on differently layers (or stacks). Usually, the objects that are added to the figure last will always appear on the top of everything else. So, depending on the order of how you draw things, the plot may appear different if there is any overlap between the objects.

To generate the above plot, plot the lines first, and then the white circle, and finally the text boxes. Note that in the case where the lines have to be drawn last, you can always use to uistack function to send the lines back to the bottom layer of the figure.

This rather messy m-file contains the code that produces the above plot.

Saturday, April 21, 2012

Detecting the type of mouse click

There are many ways for a user to interact with application using a mouse, there are normal click (single left click) that often selects the object, single right click that often opens up a context menu, and double-left click that often opens up the object. The ability to detect the type of the mouse click will come in handy when you are developing a truly interactive GUI. Fortunately, such information can be easily obtained by extracting the information stored in the SelectionType property of the GUI, which is a figure object.

1. Create a blank GUI and save the files.

2. Create a function to be attached to the WindowButtonDownFcn property of the GUI.


function winButtonDownFcn(hObject, eventData) 
m_type = get(hObject, 'selectionType');
if strcmp(m_type, 'normal')
    fprintf('left mouse click\n');
elseif strcmp(m_type, 'alt')
    fprintf('right mouse click\n'); 
elseif strcmp(m_type, 'open')
    fprintf('double-click\n');
end

3. In the opening function of the GUI, attach the function to the WindowButtonDownFcn property of the GUI.

set(hObject, 'windowButtonDownFcn', @winButtonDownFcn);

4. Running the GUI and try out different type of mouse clicks, the corresponding detection should be printed in the command window.

Note that there are other mouse clicks and/or key pressed may result in the same values in the selectionType property, for example, Control+left click will show up as a right click. If you would like to implement the more complicated mouse clicks (with key pressed), be sure to check the table in the documentation.

Example can be download here.

Monday, April 16, 2012

Making multiple objects drag-and-droppable

To continue on with the drag and drop topic, we now look at a way to make multiple objects in the gui drag-and-droppable. The idea is simple, rather than focusing on one object, we will be creating a cell array that stores all the handles to the objects that we would like to move, so that depending on where the mouse is, different objects will be the target of the drag-and-drop action. If we don't consider the case where multiple objects overlap, making multiple objects movable is a fairly straightforward procedure. However, to account for the fact that the different objects may overlap, the decision as to which object should be considered first, as well as the implementation of such decision make this problem interesting.

Note that I am making things a little complicated here because my starting point is windowMouseMotionFcn instead of the buttonDownFcn of the specific object. The former detects mouse motion while the latter detects mouse click on the specific object. I could easily start at buttonDownFcn and have the gui behave almost the same way, except that you won't be able to tell if an object is movable unless you click on it, in other words, there won't be any indicator (a hand-shape figure pointer) to indicate that the object is movable. Starting from the windowMouseMotionFcn is, in a way, a walk-around to the missing mouseOver fucntion, which allows you to implement the 'movable indicator'. That said, if you don't care about this functionality, check out selectmoveresize function, which is a MATLAB function that allows you to select/move/resize axes and uicontrol graphic objects.

Key procedures:

1. Create three static text fields and name their tags as lbl_target_1, lbl_target_2, and lbl_target_3. Change their unit to pixel. You can also change their background color to green and fontsize to 16.

2. In the opening function of the gui, create a cell array that consists of all the handles to the static text fields. The order of the handles in the cell array should reflect the order of corresponding uicontrols in the gui, specifically, if you wish to have a particular uicontrol appearing on top of another when they overlap, make sure its handle comes before the handle of the other uicontrol in the array.

movables = {handles.lbl_target_1, handles.lbl_target_2, handles.lbl_target_3};



3. Using uistack function to re-arrange the order of the uicontrols. First move the uicontrol to the top level, then move them down by an order that is equal to their position in the array minus 1. For example, for the third uicontrol, move it to the top first, then move it down by 2.

for i = 1:length(movables)
    cur_target = movables{i};
    uistack(cur_target, 'top'); 
    uistack(cur_target, 'down', i-1);
end


4. Attach drag_and_drop function to the windowMouseMotionFcn, with the argument movables as the cell array that contains the handles to desired uicontrols.

set(hObject, 'WindowButtonMotionFcn', {@drag_and_drop, movables});
5. In the drag_and_drop function, which is called whenever the mouse is moved on top of the gui, use a for-loop to go through all the targets and find out whether the mouse is on top of any of the uicontrol in the supplied handles array. Any time the mouse is found on top of a uicontorl, record the index of the uicontrol in the array and break the loop. Note that since the uicontrols have been sorted based on their "stack order", if there are multiple uicontrols overlap, the one at the top will always be detected.

target_id = [];
% find out which one the mouse is on top of right now 
for i = 1:length(target_handles)
    % get position information of the uicontrol
    lbl_target = target_handles{i};
    bounds = get(lbl_target,'position');
    lx = bounds(1); ly = bounds(2);
    lw = bounds(3); lh = bounds(4);
    if (x >= lx && x <= (lx + lw) && y >= ly && y <= (ly + lh))
        target_id = i;
        break;
    end
end

6. Once the index of the uicontrol is known, use another for-loop to attach grab function to the corresponding buttonDownFcn of the target uicontrol. A for-loop is needed because some uicontrols may require 'resets' if they are shadowed by another higher order uicontrol. .

for i = 1:length(target_handles)
    lbl_target = target_handles{i};
    if target_id == i 
        % set enable to off so that the whole static text field is hotspot
        set(lbl_target, 'enable', 'off');
        set(lbl_target, 'string', 'IN');
        set(lbl_target, 'backgroundcolor', 'red');
        set(lbl_target, 'ButtonDownFcn', @grab);
        setfigptr('hand', handles.fig_mouse);
    else
        % re-enable the uicontrol
        set(lbl_target, 'enable', 'on');
        set(lbl_target,'string', 'OUT');
        set(lbl_target, 'backgroundcolor', 'green');
    end
end
if isempty(target_id)
    setfigptr('arrow', handles.fig_mouse);
end

Video demo:



Files for download

Note: 
1. in the functions attached to the different callbacks of mouse actions in the gui, make sure you are not referring to other uicontrols in the gui by their tags, doing so will limit the use of the functions to the specific gui only. My drag_and_drop function will be a good example of this bad practices, since I  refer to the labels that reflect mouse action/position using their tags. 
2. Static text field isn't really a good choice as the uicontrol to be move around. In future posts in the series, I will switch to axes object instead. 

Monday, April 9, 2012

Sharing data among MATLAB GUIs: Part 2

In Part 1 of the series, I have shown that how data can be shared between the guis by writing sub-functions in the gui to take over the responsibility. Even though the idea is simple, the actual implementation takes some skills and understanding of how MATLAB guis work.

Often time, you will see the use of global variables proposed as a quick and easy fix to the problem. If the design of the application is simple, I can see why it may be the preferred approach. However, the main issue I have with the use of global variables is its awkward use.

When you use global variables, you are forced to assign/read data to/from global variables instead of push/pull data. Why does it matter, you may wonder. Well, it is awkward. When you have two guis running at the same time, the user expects that the action performed in one gui should be sufficient to complete the data sharing, rather than interacting with two guis. For example, in the example I gave in Part 1, depending on which button the user clicks, the data will either be pulled or pushed to the target gui and displayed in the text box. If you were to use global variable, you will need to first save the string in a global variable and then load the string from the global variable in the target gui, which requires two actions from the user. Isn't that awkward for data sharing? That's just for two guis, if you have five guis, you will have to cycle through all five of them to have the most up-to-date version of the data in all five of the guis.

Not only more actions is required from the user, the order of the actions is also important. If the order is not followed properly, the results in the gui may not be what's expected. For example, if you read from the global variable in the target gui before assigning updated value to the global variable in the source gui, then the target gui has the outdated values.

Finally, if you wish to expand the existing application or combine it with other guis, there may be conflicts as to how the global variables are used. I can't imagine how much of a pain that is going to be (Really, I haven't done it that way, so I have no idea).

The above are just my opinions on why using global variable is not the appropriate mean to address the data sharing among MATLAB guis. That said, I am not an expert, so if anyone thinks I am talking non-sense here, please do let me know.



Sunday, April 8, 2012

Sharing data among MATLAB GUIs: Part 1

When there are multiple GUIs in your MATLAB application, the need to let the GUIs communicate with each other is inevitable. While sharing data between the different callbacks within the same GUI may already turn some people off, the sharing of data among different GUIs is not as difficult as one may think.

In short, you need to write functions in the different GUIs to deal with establishing communication links and data exchange, and when the time comes to pull/push data to/from a GUI, simply call the appropriate functions via the GUI's functions to have the data updated.

When two GUIs are sharing data, one of them must be providing the data while the other must be receiving the data. For simplicity'sake, I am going to call the one that sends the data as the source gui and the one that receives the data as the target gui.

In the source gui, you need to have a function that returns the desired data when it is called, say, get_data(). Similarly, in the target gui, you need to have a function that read in (or use) the data, say, set_data().

Depending on where you initiate the data exchange between the two guis, the sequence of actions is different. If the communication is initiated at the source gui, you are pushing data to the target gui; on the other hand, if it is initiated at the target gui, you are pulling data from the source gui. The former case will call the set_data function in the target gui to have the data pushed over, while the latter case will call the get_data function in the source gui to have the data pulled from the source gui.

Getting down to the actual implementation, there are basically two steps. In the first step, you need to make the guis aware of each other's existence and know what their responsibility is; in the second step, you need to specify the detail/protocol of the communication. You can think of the first step as the laying down the necessary hardware and the second step as implementing software that utilize the hardware in place.

Step 1: Setting up the communication links between the guis

To share data between guis, they have to be aware of each other. In the simplest cases where you have a source gui and a target gui, you will need to have the handle of the target gui in the source gui, and the handle of the source gui in the target gui. To accomplish that, you can have a set_target function in the source gui and a set_source function in the target gui. When the functions are called, they will take the handle of the other gui and store it as an item in the handles structure for later use. Below is a sample set_target function in the source gui.


function set_target(source_handle, target_handle)
% retrieve handles structure in the source gui
handles = guidata(source_handle);  
% assign target handle as an item in the handles structure 
handles.target = target_handle;
% save the handles s
guidata(source_handle, handles);


With the set_target and set_source functions properly written in the source gui and target gui, running the following code will have the communication link established.

% This will be your main script 
% start up the two guis 
source_handle = source_gui;
target_handle = target_gui; 
% establish the link between the two 
source_gui('set_target', source_handle, target_handle); 
target_gui('set_source', target_handle, source_handle);

Step 2: Setting up the communication protocol (well, in a way)

Once the links are established, you will need to implement rules as to what and how the data is shared. During the design, you need to make sure the guis make no assumption about what is going on in the other gui or what variables are being used. Knowing exactly what your intention is with each gui should be able to help you set up your rules properly.

As an example, I have two guis with text boxes and push buttons in them. The push button in the source gui is labelled 'Send', while the one in the target gui is labelled 'Retrieve'. The interaction is fairly straightforward, write whatever you can think of in the text boxes, once a push button is clicked, you will see the text in the source gui copied over to the text box in the target gui. That said, clicking the Send button will push the data, while clicking the Retrieve button will pull the data. Same results, different approach though. The set_data and get_data functions are posted below. Nothing fancy, they either set the string property or get the string from the text box.

function set_data(handles, s) %  in the target gui 
set(handles.txt_tgt,'string', s);


function s = get_data(handles) % in the source gui 
s = get(handles.txt_src,'string');

Note that to be able to call these functions from a different guis, you need to first `publish' the functions by adding the handle to the function as an item in the handles structure. To do that, in the opening function of the gui (before the handles structure is saved), add

handles.set_data = @set_data;

to the target gui, and add

handles.get_data = @get_data; 

to the source gui. Doing so will allow you to access these functions from a different gui.

As the final step, we just need to set up the callbacks of the push buttons, so that the data exchange will occur when the button is clicked. And it is in these functions, we will call the set_data and get_data function we prepared earlier.

% in the target gui 
% --- Executes on button press in pb_retrieve.
function pb_retrieve_Callback(hObject, eventdata, handles)
% get the handle to the source gui 
source_handle = handles.source; 
% get the handles structure of the target gui 
s_handles = guidata(source_handle); 
% update string to the one returned by the get_data function 
set(handles.txt_tgt, 'string', s_handles.get_data(s_handles));

% in the source gui 
% --- Executes on button press in pb_send.
function pb_send_Callback(hObject, eventdata, handles)
% get the handle to the target gui 
target_handle = handles.target; 
% get the handles structure of the target gui 
t_handles = guidata(target_handle); 
% call the set_data function 
t_handles.set_data(t_handles, get(handles.txt_src, 'string'));


Now, if you run the 'main' script to have the two guis running at the same time and have their link established, you will be able to observe the string passing from the source to the target. The example can be downloaded here. Run the test_script.m file.

While the example used is a very simple two-gui with one-way data flow, the same concept can be expanded and applied to cases where you want one-to-many or many-to-many guis with two-way communications. As long as you can have a clear design before diving into the coding, things should be relatively straightforward.

Saturday, April 7, 2012

The reason why uicontextmenu is not working with imshow()

When you ask why the uicontextmenu is not working in an axes plotted with an image, most people will say that it is the hittest property of the image object. If the hittest property of the image object is set to 'on', any time you click the mouse within the axes, the image object, which covers the entire axes, will take over the click action and deal with it. Since you probably don't have anything associate with the image object, it will appear doing nothing at all. But at the same time you are expecting the uicontextmenu from the axes to do something. I know, drives you crazy.

If you create the image with the image() or imagesc() function, setting the hittest property of the image object to 'off' should fix the problem. Effectively, it allows you to click through the image and get to the axes.

However, if you create the image with the imshow() function, you are faced with the same problem, the uicontextmenu on the axes doesn't do anything. You can spend hours searching for a logical explanation on the Internet, and yet nothing turns up.

Well, hopefully the few hours I wasted can save you some time.

The reason is actually quite simple. One obvious differences between the images created from image() and imshow() is the ticks on the axes, while image() shows it, imshow() hides it. Now, think of the ways you can use to get rid of the ticks, you can set xtick and ytick to '[]' using set function, or you can just set the entire axes to invisible. Guess what MATHWORKS did? THEY SET THE ENTIRE AXES TO INVISIBLE, so even if you click through the image object, you won't be able to click on the axes BECAUSE IT IS INVISIBLE.

So here is the fix.
Besides setting the hittest property of the image object to 'off', you need to set 'visible' property of the axes to 'on'. Once you do that, the xticks and yticks will appear, but you can easily make them disappear by setting them to [].

Friday, April 6, 2012

Interactive drawing in MATLAB: Part 2

In the previous post, we look at how we can draw different shapes on an axes using context menu and the MATLAB build-in function such as imline, imrect, etc.

The nice thing about the build-in functions is that they are fully implemented, meaning that they can be resized, dragged, and they even have context menu on their own which allows one to change the color and some other properties.

However, one thing I hate about the functions is the little rectangle boxes appear as the end points. I understand they are there to show you where you can click to move the points, but they should at least provide an option to turn the rectangle boxes visible or invisible. I fail to see any benefits of having the rectangle boxes on the final print out. I tried and failed to find any ways to remove the rectangle boxes, so in this post, we are going to code our own function for drawing the different shapes, without the annoying rectangles. (TAKE THAT!!! MATHWORKS).

The context menu created in the previous post can be re-used here. Instead of calling the imline or imrect functions when the corresponding menu items are selected, we are just going to create our own function to draw the desired shapes. Note that at this point, we will not be worry about all the fancy stuff, such as the figure pointer, line color, ability to resize, etc.

Design of the action sequence:
1. User selects "Line" from the context menu of the axes, which activates the line drawing mode.
2. Whenever the button is pressed in the line drawing mode, a line object is created on the axes.
3. As the user moves the mouse on the axes while holding the button down, the line object is continuously updated with the current location as the end point.
4. Whenever the users release the button, the line object is finalized and the line drawing mode ends.

The draw_line function shown at the bottom can fulfill the action sequence described above. Note that we are using WindowButtonDownFcn, WindowButtonMotionFcn and WindowButtonUpFcn to track the various mouse actions, and the corresponding GUI response is realized using nested/sub functions. You can try out this function easily using the code "plot(rand(1,10)); draw_line(fh,ah);". To implement functions that draw other shapes, the same structure can be followed, and changes only have to be made for the drawing of the shapes, which can be complicated at times depending on what you want to draw. 

Video demo



The sample GUI can be downloaded here.


function draw_line(fh, ah)
% DRAW_LINE(FH, AH) draws a line on an existing axes interactively. 

% Input: 
%   fh - handle of the figure that contains the axes 
%   ah - handle of the axes to be drawn on 
%
% Wei Shang 
% wei.shang@unb.ca 
% University of New Brunswick 


% get the boundaries on the axes 
x_bounds = get(ah, 'xlim');  y_bounds = get(ah, 'ylim');
% enter line drawing mode by attaching buttonDown function
set(fh, 'WindowButtonDownFcn', @buttonDown);


    function buttonDown(fh, dummy)
        % This function is called when the mouse button is pressed. 
        % It will create a line object based on the location of where the
        % button pressed action occured. 
        
        % get the location of the action 
        p = get(ah,'currentpoint');
        x1 = p(1,1); y1 = p(1,2);
        % create a line object that starts and ends at the same point. 
        lh = line([x1,x1], [y1,y1], 'linestyle', ':');
        % atttach buttonMove function 
        set(fh,'WindowButtonMotionFcn',@buttonMove);
        % attach buttonUp function
        set(fh,'WindowButtonUpFcn', @buttonUp);
        
        function buttonMove(fh, dummy)
            % This function is called when the mouse button moved while
            % being pressed. 
            
            % obtain end points of the line 
            X = get(lh,'XData'); Y = get(lh,'YData');
            
            % obtain new points as the new mouse pointer location 
            p = get(ah,'currentpoint');
            x2 = p(1,1); y2 = p(1,2);
            
            % check and make sure they are within the bounds, if not force
            % the end point to be within the bound 
            if x2 < x_bounds(1)
                x2 = x_bounds(1);
            elseif x2 > x_bounds(2);
                x2 = x_bounds(2);
            end
            
            if y2 < y_bounds(1)
                y2 = y_bounds(1);
            elseif y2 > y_bounds(2)
                y2 = y_bounds(2);
            end
            
            % update the line object with the 
            X(2) = x2;   Y(2) = y2;
            set(lh, 'XData', X, 'YData', Y);
            
        end % ends buttonMove function 
        
        function buttonUp(fh, dummy)
            % This function finalize the line object and ends line drawing
            % mode. 
            
            % set line object's line style to solid line 
            set(lh,'linestyle','-');
            
            % set various mouse actions to null
            set(fh, 'WindowButtonMotionFcn', '');
            set(fh, 'WindowButtonUpFcn', '');
            set(fh, 'WindowButtonDownFcn', '');
            
        end % ends buttonUp function 
        
    end % ends buttonDown function 


end % ends draw_line function


Interactive drawing in MATLAB: Part 1

Being able to draw in the plots/images in MATLAB GUI can be very useful at times. 

MATLAB has a collection of Utilities for Interactive Tools which allows you to place points, lines, rectangles, ellipses, etc on to an axes, so be sure to check them out first to see if they meet your need. 


There are many ways to incorporate/initiate/activate the various drawing tools in MATLAB GUI. You can simply call the functions in the callback of the various uicontrols such as push buttons, drop-down menu, etc. 


In the example that I am about to show, I attach a context menu to the axes, which allows the user to select the desired shape and begin drawing.

1. Create a new MATLAB GUI using the GUI with Axes and Menu template.

2. In the GUIDE window, bring up the Menu editor by Clicking Tools -> Menu Editor.

3. By default, the menu window is in Menu Bar mode, select Context Menus tab at the button of the menu editor.

4. Create the menu items as follows
    a. create a top level menu and name* it cm_axes, this menu item is to be attached to the axes
    b. under the cm_axes menu, create a new menu item and name it cm_draw, this menu item acts as a container of all the possible shapes that you can draw.
    c. under the cm_draw menu, create a new menu item and name it cm_draw_line, once selected, this menu item should allow the user to draw a line
    d. again, under the cm_draw menu, create a new menu item and name it cm_draw_rect, once selected, this menu item should allow the user to draw a rectangle.
    e. repeat d to implement another other shapes that you would like to use.

* By naming a item, I meant changing the item's tag, not labels. The labels of the items can be anything as long as it makes sense.

5. Once the context menu is created, the next step is to attach the context menu to the axes. To do that, simply open up the property editor of the axes, find UIContextMenu, and select cm_axes from the drop down menu.

6. After saving the file, the various callbacks for the menu item should appear at the bottom of your m-file editor. For the menu items cm_draw_line and cm_draw_rectangle, simply insert the two functions imline and imrect, respectively.

7. Save all file, and run the GUI, right click anywhere on the axes to bring up the context menu.

Video walkthrough



Source File

Download the files here.


Tuesday, February 28, 2012

MATLAB: Making a zoom-in plot on top of a plot

Sometimes, it is helpful to provide a zoom-in of a portion of the original plot. While it can be easily done by making them two separate plots using the subplot function, there are times when you wish you can just make the zoom-in plot appear on top of the original plot. The good news is that it is possible, the bad news, well, it requires a work around, since there isn't a nice matlab function which you can simply call to have the job done for you.

The walk around itself is a very simple idea, you can create another axes on top of the original plot and have the zoom-in data copied over to the new axes. If you are doing it for one time only or the plots are very similar, then it may make sense just to hard code everything in and move on. However, in the case where the plots vary quite a bit, a function is probably needed to make it less of a pain.

FUNCTION DESIGN
Input(s):
  ah:  handle of the existing axes
  source_pos: the position of the portion to be zoomed in
  target_pos:  the position where the zoom-in plot will be placed

* To make the function easy to use, the positions as the input variables are based on the axes in the original plot.

Download the zoomPlot.m file from here here and run the following code to see the function in action.


figure; 
t = 0:0.001:0.1;
plot(t, cos(2*pi*50*t)); 
ah = gca; 
% location of the plot to be zoomed in. 
s_pos =[0.05 0 0.06 0.1];
% location of the zoom-in plot 
t_pos = [0.035 0.4 0.065 0.7];    

% generate a zoom-in plot. 
zoomPlot(ah, s_pos, t_pos);     


The resulting plot will look like



So what has been cover in this post is the basic idea of how to get a zoom-in plot to be on top of the original plot. There are many ways to make this basic function more robust and useful.
  • to allow user specify the positions interactively using mouse 
  • to allow user more flexibility in controlling the appearance of the zoom-in axes. 
  • etc. 




Friday, February 24, 2012

MATLAB: How to plot a circle

Ever wonder why there is no circle function when there is a rectangle function?

If you can draw a circle using rectangle function, why would you need a circle function?

The code below plots a circle centered at (x,y), with a radius r, using the rectangle function,

x = 0.5; y = 0.5; r = 0.5;
rectangle('position', [x-r,y-r, 2*r, 2*r], 'Curvature', [1 1]);

The neat thing about using the rectangle function is that you don't need to decide on a 'sampling rate'. The sampling rate is needed if you actually write a function that computes the samples on the circle and plot them as line objects. 



Tuesday, February 21, 2012

MATLAB GUI Inserting background image

Update [2014-04-13]: a function was created for inserting background image to MATLAB gui (or any figure for that matter). It can be found on github.

In many cases, you may wish to insert a background image to the existing GUI. Some of the uicontrols, such as pushbutton and toggle button, have the CData property, which you can set as background using data read from an image (see here). The gui itself, however, does not have such property, and a walk around is needed.

This tutorial shows how you can create an axes in the opening function of the gui and have the background image shown on the axes. To proceed, simply open up an existing gui (or create a new one), and insert the following code in the opening function of the gui.

% create an axes that spans the whole gui
ah = axes('unit', 'normalized', 'position', [0 0 1 1]); 
% import the background image and show it on the axes
bg = imread('example.jpg'); imagesc(bg);
% prevent plotting over the background and turn the axis off
set(ah,'handlevisibility','off','visible','off')
% making sure the background is behind all the other uicontrols
uistack(ah, 'bottom');

Note that the aspect ratio of the gui and the background image should match so that the appearance of the background image is optimized. 

Video walk-through