Quantile Probability Plot

In this post I will present a code I've written to generate Quantile Probability Plots. You can download the code from the MATLAB File Exchange Website.

What are these Quantile Probability Plots? They are some particular plots very used in the Psychology field, expecially in RT experiments when we want to analyse several distributions from several subjects in different conditions. First of all let's see an example of a quantile probability plot in the literature:

Ratcliff

(from Ratcliff and Smith, 2011)

As explained in Simen et al., 2009
"Quantile Probability Plots (QPP) provide a compact form of representation for RT and accuracy data across multiple conditions. In a QPP quantiles of a distribution of RTs of
a particular type (e.g., crrect responses) are plotted as a function of proportion of  responses of that type: thus, a vertical column of N markers would be centered above the position 0.8 if N quantiles were computed from the correct RTs in a task condition in which accuracy was 80%). The ith quantile of each distribution is then connected by a line to the ith quantiles of othe distribution."

For example, in the graph presented we have four counditions. From the graph we can extrapolate the percentage of correct responses to be around 0.7, 0.85, 0.9 and 0.95 (look at the right side). For each one of this distribution we computer 5 quantiles, plotted against the y axis (in ms). In the left side we have the distributions from the same conditions, but for the error responses!

With my code you can easily generate this kind of graph and even something more. Let's see how to use it.

First of all, you need to organize the file in this way: first column has to be the dependent variable (for example, reaction times in our case); second column the correct or incorrect label (1 for correct, 0 for incorrect); third column, the condition (any float/integer number, does not need to be in order). This could be enough, but most of the time you want to calculate the average  across more than one subject. If this is the case, you need to indicate another column with the subject number.

The classic way to use it is just call it with the data:

quantProbPlot(data) will generate:

untitled

We may want to put some labels to indicate the conditions. In this case we ca use the optional argument 'condLabel': quantProbPlot(data,'condLabel',1) will generate:simpleLabel

(for this and the following plots, the distributions will always look different just because everytime I generated a different sample distributions!)

This is only the beginning. In some papers they plot the classic QPP with a superimposed scatter plot of individual RTs in each condition. A random noise is added on the x axes to improve redeability. Example: quantProbPlot(data, 'scatterPlot',1):

Scatter

Nice isn't it? I also elaborate some strategies to better compare error responses with correct responses, through two optional parameters. One is "separate" and the other one is "reverse". Separate can take 0, 1 or 2, whereas reverse can only take 0 or 1 and works only if separate is >0.

Generally, separate=1 separaters the correct responses with the incorrect one in two subplots, whereas separate=2 plot the correct and incorrect with two different lines. This is usually quite useless, for example:

Separate2

however, you can make it much more interesting when you combine it with reverse. Infact, if you call quantProbPlot(quantData,'separate',2,'reverse',1) you will obtain this nice graph:

Separate2Reverse

which allows you to easily compare correct and incorrect responses!

With all these options, you can play around with scatter plot, separating, labels etc. in order to easily analyse your data.

I include in the file also the Drift Diffusion Model file that I proposed last time. I used this file to  generate the dataset I use to test the Quantile Probability Plot code. For some example, open the "testQuantProbPlot", also included in the zip file.

DOWNLOAD HERE!

scaleSubplot, to organize your subplot nicely

Download scaleSubplot

In psychology we often deal with data from several subjects, each subjet having several datapoints across more than one condition. Showing the results of an experiment for individual subjects in order to get a meaningful insight understandment of the data could be quite tricky. A classic way of organizing the data consists of plotting each subject's result in a subplot, in order to have all the subject's data in a single figure. MATLAB function subplot is quite good for the task, even if more and more often I find myself using the tight_subplot function. Anyway, one problem is that the subplot axes does not have the same scale by default, and this decrease the redeability of the results.

MATLAB allows you to link different axes (namely different subplots) so that you can scale all of them at the same time (linkaxes).  However, once that all the subplots have the same scale, showing the axes label for each subplot seems a little bit redundant. It would be sufficient just to show the axes of the bottom and left most panels. I coded a function that does exactly that.

scaleSubplot(fig, varargin) allows you to scale at the same time all the subplots of a figure. You can specify a custom scale or let the code decide a nice unique scale for all the subplots. You can decide to scale at the same time the horizontal and vertical axes, or only one of them.  Let's look at some example.

The easiest way of using the function is: scaleSubplot(gcf). In this case you will scale both x and y axes, and the script will find the best xlimit and ylimit for all the subplots. The code will make sure that all the data will be visualized in the subplots.

Note how the redundant x/ylabels have been suppressed:

Untitled

We can have more control on the image by specifying some optional arguments. For example, if we want to have the same scale only the x axis, we specify 'sameScale',{'x'}. Notice how the x labels on the intermediate subplots are suppressed, but all the y labels are still there, since they do not have the same scale. In the figure below we also specify a custom xlimit. If you decide to specify a custom limit, make sure that all the datapoints in all the subplot fall within you limits.

Untitled2

We can also specify only one of the boundaries for the axes limit, and leave the code decide for the other one. For example we can write scaleSubplot(gcf,'xlimit',[-Inf 40]) or scaleSubplot(gcf,'ylimit',[0 Inf]).

My function is expecially useful when we want to have a tight subplot. In this case, eliminating the intermediate axis can make the subplot much more readable. For example, I generate the image on the left side with tight_subplot(2,4,0.05), where 0.05 is the gap between subplots. However, with all the axes labels, the image is a mess. After a simple scaleSubplot(gcf) the figure looks much better.

Untitled3

Hope you enjoy it.

Download scaleSubplot

Drift Diffusion Model

You can find some information about the Drift Diffusion Model here. There are probably several versions of the Drift Diffusion Model coded in MATLAB. I coded my own for two purposes:

1) If I code something, I better understand it

2) I wanted to have a flexible version that I can easily modify.

I attach to this post my MATLAB code for the DDM. It is optimized to the best of my skill. It can be used to simulate a model with two choices (as usual) or one choice, with or without variability across trial (so it can actually be used to simulate a Pure DDM or a Extended DDM). The code is highly commented.

The file can be downloaded here or, if you are have a MATLAB account, here.

If you take a look at the code, you could get confused about the presence at the same time of the for loop and the cumsum function. The cumsum is a really fast way in MATLAB to operate a cumulative sum of a vector. However, in this case I have to sum an undefined number of points (since the process stops when it hits the threshold, and it is not possible to know it beforehand). I could just use an incredibly high number of points and hope the process hits the threshold at some point. Or I could use a for loop to keep summing points until it hits a threshold. Both these methods are computationally expensive. So I used a compromise: the software runs cumsum for the first maxWalk points,and, if the threshold has not been hit, runs cumsum again (starting from the end of the previous run) within a loop (it repeats the loop for 100 times, every time for maxWalk points). After some testing, this version is generally much faster than a version with only cumsum or only a for loop.

This is an example of the resulting RT distribution with a high drift rate (e.g., the correct stimulus is easily identifiable):

untitled

I will soon post an alternative version of this file. They are less efficient, but allow to plot the process as it accumulates, which is quite cool.

Swap line with line above/below with AutoHotkey

One of the thing that I enjoy more in coding is... coding fast. This probably release in my brain a great amount of adrenaline, and makes me thing that I am fantastically good, even when my coding is actually poor 😀

One way to increase speed coding is to use keyboard shortcuts. Instead of moving your hand from the keyboard to the mouse to do trivial task such as selecting a whole line or copy and paste something, one can just use shortcuts. However, different software environments may have different shortcut, or may miss some particular shortcut combination that you use in other environment.

For example, a really nice trick in Eclipse, Notepad++ and other editor is the possibility to swap the current line to the line immediately above or below it. Unfortunately, this option is not available in some environments, for example in MATLAB. Should we just give up? Well, NO.

This is when AutoHotkey comes into play. This is a fantastic software that allows us to create script and macro to remap keystroke and action on the computer. The potential of AutoHotkey is huge, and in this post I will just show one example, coding a little script to swap the current line with the line above or below, exactly like in Eclipse or Notepad++. But, this time, the shortcut will work in every environment! 🙂

Once AutoHotkey is installed on your computer (and will not take much, since the software is also extremely light), right click on the little icon on the startbar and select edit script. Then, just copy and paste the following script:

#ifwinactive, AutoHotkey.ahk - Notepad

~^s::
reload
return

#ifwinactive

LWin & Q::
if GetKeyState("LControl","P")=1
{
Send {Home}
Send {LShift Down}
X=%A_CaretX%
Y=%A_CaretY%
Send {End}
if (A_CaretX=X and A_CaretY=Y)
{
Send {Up}
return
}
Send {LShift Up}
Send ^x
Send {Up}
Send {Home}
Sleep 10
Send ^v
Sleep 10
X=%A_CaretX%
Y=%A_CaretY%
Sleep 10
Send +{End}
if (A_CaretX=X and A_CaretY=Y)
return
else {
Send ^x
Send {Down}
Send ^v
Send {Up}
Send {Home}
return

}

}

LWin & A::
if GetKeyState("LControl","P")=1

{
Send {Home}
Send {LShift Down}
X=%A_CaretX%
Y=%A_CaretY%
Send {End}
Send {LShift Up}
Send ^x
Send {Down}
Send {Home}
Sleep 10
Send ^v
Sleep 10
X=%A_CaretX%
Y=%A_CaretY%
Send +{End}
Sleep 10
if (A_CaretX=X and A_CaretY=Y)
return
else {
Send ^x
Send {Up}
Send ^v
Send {Down}
Send {Home}
return
}
}

Press ctrl+s, which will save and reload te script. That's it! You just bound the two combinations CTRL+WIN+Q and CTRL+WIN+A to the up/down swap action.

Try it on any editor and enjoy your new shortcut!

If you want you can change the combination used if you don't like it or, for example, because they collide with another combination you use in some environment, just change line 9/10 and 51/52 with whatever combination you prefer (here a list)

Please consider that this is my very first script with AutoHotkey, so if the style is not so elegant take this into account 😛

I also use some other cool shortcuts that you might found interesting, but I will explore them in one of the next posts.  Bye!

Copy highlighted text into comments from a PDF file

One of the nice features of Acrobat is that you can highlight text and then export only the highlighted part into a different document.  However, in order to do that, the user has to remember to tick the option "Copy selected text into Highlight, Cross-Out, and Underline comment pop ups" in Edit - Preferences - Commenting. Unfortunately, this setting is not on by default and only available  in Acrobat (8,9 and X) but not in Acrobat Reader, as said here.

It can happens that we highlight a really big document in order to export the highlighted parts, and then we remember that the "Copy selected text..." was actually off! Our highlighted parts won't be commented, meaning that we cannot export them (actually, we *can* export them, but they will be just empty boxes). There is no way to retroactively  copy all the highlighted part into comment from the graphic interface.

screensh2

However, it is possible to solve this problems by using some code. This solution will also work if you have Acrobat Reader!

There is already a software online that does that, on this website, but the price is really high (from $40 to $75!), so I developed my own script and I am going to put it out for free:

HOW TO RETROACTIVELY COPY HIGHLIGHTED TEXT INTO COMMENTS IN ACROBAT PDF

1. OPEN JAVASCRIPT EDITOR. First of all open the document with the highlighted text, and press ctrl+j. In Acrobat Pro, this should open the JavaScript editor window. If it works, just go to point 2, otherwise keep reading.

It ctrl+j doesn't do anything, than you don't have Acrobat Pro, but don't worry, you can still open the JavaScript editor. Go on this website and download the Reader JavaScript Console Window. Download the file anywhere, and follow the instruction in the ReadMe file. Once done that, you should see a new voice in the PDF menu, "Extension", and clicking on "Debugger" should open the JavaScript editor window. Done!

2. COPY THE SCRIPT. Delete any text on the bottom window, and copy and paste this code:

var annots = this.getAnnots({nSortBy: ANSB_Page});
console.println("nAnnot Report for document: " + this.documentFileName);
if ( annots != null ) {
console.println("Number of Annotations: " + annots.length);
var annotList=[];
for (var i = 0; i < annots.length;i++) {
        
        var annotTxt="";
        while (annots[i].type!="Highlight") {
            annotTxt="****";
            i=i+1;
        }
        if (i>=annots.length) {
             break;
        }
      
        pageNum=annots[i].page;
        var quadAN=annots[i].quads.toString();
        var qaAN=quadAN.split(",");
        for (var ii=0; ii<qaan.length; ii++)="" {=""   =""    =""  qaan[ii]="parseFloat(qaAN[ii]);"  }=""  for="" (var="" w="0;" w<getpagenumwords(pagenum);="" w++)=""  var="" quadwd="getPageNthWordQuads(pageNum,w).toString();"                        ="" console.println("qwd="" type:="" "="" +="" typeof="" ":="" quadwd)="" qawd="quadWD.split(",");" ii="0;" ii<qawd.length;=""  qawd[ii]="parseFloat(qaWD[ii]);"  ="" nlines="qaAN.length/8;" counter="0;" nn="0;" nn<nlines;="" nn++)=""  if="" (qawd[0]="">=qaAN[counter+0]-4.5 &&
                    qaWD[1]<=qaAN[counter+1]+0.5 &&
                    qaWD[2]<=qaAN[counter+2]+4.5 &&
                    qaWD[3]<=qaAN[counter+3]+0.5 &&
                    qaWD[4]>=qaAN[counter+4]-4.5 &&
                    qaWD[5]>=qaAN[counter+5]-0.5 &&
                    qaWD[6]<=qaAN[counter+6]+4.5 &&
                    qaWD[7]>=qaAN[counter+7]-0.5) {
                    annotTxt=annotTxt+" "+getPageNthWord(pageNum,w);
                }
            counter=counter+8;
            }
        counter=0;
            
        }
        //UNcomment one line below if you want to show information about the annotations
        //annotTxt="ANNOT N." + i + " PAGE NUM: " + (pageNum+1) + " : " + annotTxt;
        annots[i].contents=annotTxt;
        annotList[annotList.length]=annotTxt;
        //UNcomment the line below if you want to print on the screen the annotations
                //console.println(annotTxt)

}

} else
console.println(" No annotations in this document.");

console.println("DONE!")

</qaan.length;>

Select all the code (ctrl+a) and execute it (ctrl+enter). You have done! If everything has been done right, the highlighted part will now contain comments, as shown in figure:

screensh3

DONE.

Now you can be easily export the highlighted annotations on a PDF or word document. You can use the Acrobat option of exporting contents, as explained in this video. However, with the code we have now, you don't really need to do that: you can just uncomment (delete the double slash, //)  line 53 and execute the script again. This line will print on the screen the found highlighted words. If you want to also show some information about the highlighted part (just the annotation number and page) uncomment line 49. Execute the code and copy-paste the output anywhere. However, if you want, you can still use a more classic way, explained for example

The process of generating the comments could take some time, so be patient, even if the edito and the PDF will look freezed! If you really believe that the editor got stuck, try to press ctrl+shift+esc to interrupt the execution. If you have a lot of highlighted annotations (let's say, more than a hundres), it is a lot better to execute only chunk of text. To do that, change line 6 . For example, change it first to

for (var i = 0; i < 100;i++)

then to

for (var i = 100; i < 200;i++)

But always make sure that the second index will be not higher that the tot number of annotations.

PERSONAL NOTES:

I actually needed to export highlighted text because I was building a software to create the keywords index of a book, and the keywords were actually the highlighted part of the text itself. Since I never never used JavaScript before, this turned out to be quite a challenge. The way to get the text is extremely convoluted, and it' s really incredible that the Acrobat API doesn't have an easy way to do that. Briefly, I take the coordinate of the boxes describing the position of the annotations (the highlighted text). If the annotation goes through multiple lines, I'll get multiple coordinates and split them in chunk of 8. Fortunately, the annotation object also give me the page it is present. For each annotation, I will go through all the words within that page, take the coordinate of the words, and check if they are within the coordinates of the annotations. Strangely, the y coordinate starts from the bottom of the screen, instead the from above, as common in programming languages. This method will work also with words that are separated across two line.

I also noticed that, for some reason, if the word is close to some punctuation, the coordinates will mistakenly report an higher value (for example, for the word -hi- (within the dashes) the word coordinates will start and end when the dashes start and end (even if the actual word read if only hi). Therefore, if the only highlighted part is hi, the word will not be recognized, because the coordinates of the word will lie outside the coordinates of the highlighted box. To solve this problem, I just slightly increased the coordinates for the boxes (the +-4.5 or +-0.5 in the code), and this solved the problem completely.

Anyway, my first experience with JavaScript is totally positive. The language is intuitive and extremely similar to Java and C++, which I am more confident with. The real problem was the Acrobat API, which seems to behave in an unpredictable way.

-----------------------------

A big thanks to Francisco Morales which, with this post, pointed me to the right direction to develop this script.

If you appreciate my effort, please leave a comment!
If you have any problem with the script, don't be afraid to ask! 🙂

Reference Creator

In my first post I will talk about the project that led me think about opening a blog. This hasn’t been the most difficult thing I have worked on, but the one I put more effort to make it accessible to everyone.  I am talking about my Reference Creator, which can be downloaded here.

Screenshot
This software is design to be helpful for people writing articles. In my experience, people tend to write scientific article putting the in-text citation, without worrying for long time about the extremely boring task of organizing the reference. If you are not using Latex or some particular text editor, creating the reference can be an incredibly tedious task. And that’s when my software comes in handy! It will just take your in-text citations and create a reference list for you!

Let’s say that you paste this text: “[...] emphasis within a dualroute framework (e.g., Ratcliff, 1978; 2013). The idea that readers have the [...]“. The software will recognize 2 citations: Ratcliff, 1978, and Ratcliff, 2013. It will then look on the Mendeley database for the most likely papers, make some check on year, numbers/name of authors (taking into account “et al.” if present) and give back the reference list:

Ratcliff, R. (1978). A theory of memory retrieval. Psychological Review, 85(2) 59-108. doi:10.1037/0033-295X.85.2.59

Ratcliff, R. (2013). Parameter variability and distributional assumptions in the diffusion model. Psychological review, 120(1). doi:10.1037/a0030775

Warning and suggestions are given in case of double matching (two or more papers with same author list and year).

More information can be found in the website.

The file is completely free (even if you don’t have a MATLAB license) and everyone can change the source code (only if you have a MATLAB license, unfortunately).