├── .DS_Store
├── Decoding_binORG.m
├── LICENSE
├── README.md
├── SVM_ECOC_ERP_Decoding_2020.m
├── SVM_ECOC_ERP_PermutationTesting_2020.m
├── SVM_ECOC_Stat_Plot_Permutation_2020.m
├── boundedline.m
└── inpaint_nans.m
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ammsimmons/binorg_decoding/89264203ebbd8ae7577c3524b1837621eb060aae/.DS_Store
--------------------------------------------------------------------------------
/Decoding_binORG.m:
--------------------------------------------------------------------------------
1 | % binorgEEG script:
2 | % Use *right after* Extracting Bin-Based Epochs
3 | % Creates bin-organized .mat files for Decoding
4 | % Writes .mat files to current working directory
5 |
6 | % Place continuous BE datasets (.set & .fdt) in current working directory
7 | % Examples of these kind of data can be found on box:
8 | % https://ucdavis.box.com/s/jrd9zus448nkc0wjkjf1x5nxbc7oxwg8
9 |
10 | % by Aaron M. Simmons, University of California, Davis
11 |
12 | clear all;
13 | close all;
14 |
15 |
16 | parentfolder = pwd;
17 | subject_list = {505, 506, 507, 508, 509, 510, 512, 514, 516, 517, 519, 520, 521, 523, 524, 525};
18 | numsubjects = length(subject_list);
19 |
20 |
21 | for s = 1:numsubjects
22 | subject = subject_list{s};
23 | subjectfolder = [parentfolder]; %loc of file
24 | fprintf('\n\n\n*** Processing subject %d (%s) ***\n\n\n', s, num2str(subject));
25 |
26 | %Initialize EEG
27 | eeglab;
28 |
29 | %load data
30 | EEG = pop_loadset('filename', [num2str(subject) '_binned_be.set'], 'filepath', subjectfolder);
31 |
32 | %use binorg-EEG function (this function is only on ERPlab V8.1)
33 | binepEEG_to_binorgEEG(EEG, ['Decoding_BE_' num2str(subject)]);
34 | % Produces bin-organized .mat file and outputs file into current working directory
35 | % it will be called "Decoding_BE_XXX" as specified in string filename
36 |
37 | close all;
38 | clear EEG;
39 |
40 | end
41 |
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # binorg_decoding
2 | Bin-Organized Decoding (J. Neuro: Bae&Luck, 2018).
3 |
4 | Here you will find an updated version of Bae & Luck (2018) analysis scripts. We have updated the scripts to allow the use of bin-organized decoding, therefore allowing users to use EEGlab/ERPlab* to format and decode their own data more seamlessly.
5 |
6 | **ERPLAB Version V8.01 REQUIRED**
7 | Download ERPLAB here: https://github.com/lucklab/erplab/releases/download/8.01/erplab8.01.zip
8 |
9 | **Decoding Scripts**
10 | The MATLAB scripts used for the online webinar are found in this .zip file: https://github.com/ammsimmons/binorg_decoding/archive/master.zip
11 |
12 | Order of Operations:
13 | 1. Decoding_binOrg.m
14 | 2. SVM_ECOC_ERP_Decoding_2020.m \
15 | --See Below for Link to Data on Box:
16 | https://ucdavis.box.com/s/aecglu8zqox52nc94f5jywj9mxktbf57
17 | 3. SVM_ECOC_Stat_Plot_Permutation_2020.m \
18 | -- Required: "boundedline.m" & "inpaint_nans.m" (Kearney, 2020) \
19 | -- See here: https://www.mathworks.com/matlabcentral/fileexchange/27485-boundedline-m
20 | 4. SVM_ECOC_ERP_PermutationTesting_2020.m
21 |
22 | Again, data used on our Decoding Webinar (2020) can be found at:
23 | https://ucdavis.box.com/s/aecglu8zqox52nc94f5jywj9mxktbf57
24 |
25 | Background:
26 | The scripts we use are an updated version of those found in Bae & Luck (2018). If you wish to see those on OSF, see them on this link https://osf.io/bpexa/ \
27 | Our scripts above are much easier to adapt to use for your own data than the original 2018 scripts.
--------------------------------------------------------------------------------
/SVM_ECOC_ERP_Decoding_2020.m:
--------------------------------------------------------------------------------
1 | % This is an updated function of Bae & Luck (2018) Decoding
2 | % pipeline that utilizes a nested bin-epoched data structure.
3 | % Refer to OSF: https://osf.io/29wre/
4 |
5 | % NOTE: low-pass filtering to 6hz was applied to continuous EEG (prior to
6 | % binning). % Code to be used on a bin-epoched dataset for one
7 | % class only (e.g. Orientation)
8 |
9 | % NOTE: This script requires the 'fitcecoc' Matlab function. This function is a
10 | % part of the Matlab Statistics and Machine Learning toolbox.
11 |
12 | %Edited by Aaron Simmons (UC Davis)
13 | %Original Author: Gi-Yeul Bae (Arizona State University)
14 |
15 | function SVM_ECOC_ERP_Decoding(subs)
16 |
17 | % Parallelization: This script utilizes Matlab parallelization ...
18 | % if parallelization is not possible, change "parfor" to "for-loop"
19 | delete(gcp)
20 | parpool
21 |
22 | %% Check presence of Matlab Statistics and Machine Learning Toolbox
23 | % This toolbox is required for the SVM classification
24 | V = ver;
25 | Vname = {V.Name};
26 | if ~(any(strcmp(Vname, 'Statistics and Machine Learning Toolbox')))
27 | error('Error. Statistics and Machine Learning toolbox not found.');
28 | end
29 |
30 |
31 | %% Subject List:
32 | if nargin ==0
33 |
34 | subs = [505, 506, 507, 508, 509, 510, 512, 514, 516, 517, 519, 520, 521, 523, 524, 525];
35 |
36 | end
37 |
38 | nSubs = length(subs); %number of subjects
39 |
40 | %% Subject Filename(s)
41 |
42 | % Load Subject Datafiles
43 | dataLocation = pwd; % set directory of data set (default: pwd)
44 | fName = ['/Decoding_BE_']; % subject filename (subject # appended at end)
45 |
46 | % Save Decoding results
47 | saveLocation = pwd; % set save directory of data set (default: pwd)
48 | savName = ['/Orientation_Results_ERPbased_'];
49 |
50 |
51 | %% Parameters to set
52 | % Main structure is svmECOC. The output file is composed of svmECOC struct
53 |
54 | svmECOC.nBins = 16; % # of stimulus bins
55 |
56 | svmECOC.nIter = 10; % # of iterations
57 |
58 | svmECOC.nBlocks = 3; % # of blocks for cross-validation
59 |
60 | svmECOC.dataTime.pre = -500; % Set epoch start (from imported data)
61 | svmECOC.dataTime.post = 1496; % Set epoch end (from imported data)
62 |
63 | svmECOC.time = -500:20:1496; % time points of interest in the analysis
64 | % the time-points of interest is a resampling of preprocessed data
65 | % the time steps (20ms) here change the data to 1 data point per 20ms
66 |
67 | % Timepoints/sampling rate of preprocessed/loaded data
68 | svmECOC.window = 4; % 1 data point per 4 ms in the preprocessed data
69 | svmECOC.Fs = 250; % samplring rate of in the preprocessed data for filtering
70 |
71 | % Equalalize trials across bins?
72 | equalT = 1; % equal trials acr bin = 1; use as many trials within bin = 0
73 |
74 | % The electrode channel list is mapped 1:1 with respect to your
75 | % electrode channel configuration (e.g., channel 1 is FP1 in our EEG cap)
76 | % Check if the label for each electrode corresponds to the electrode
77 | % labeling of your own EEG system
78 | ReleventChan = sort([2,3,4,18,19, 5,6,20, 7,8,21,9,10,11,12,13,14, 22,23,24,25,26,27, 15,16,1,17]); %electrodes
79 | % here, we removed external EOG electrodes & mastoid ref, for 27 electrodes
80 |
81 | svmECOC.nElectrodes = length(ReleventChan); % # of electrode included in the analysis
82 |
83 |
84 | % for brevity in analysis
85 | nBins = svmECOC.nBins;
86 |
87 | ogWin = svmECOC.window;
88 |
89 | nIter = svmECOC.nIter;
90 |
91 | nBlocks = svmECOC.nBlocks;
92 |
93 | dataTime = svmECOC.dataTime;
94 |
95 | times = svmECOC.time;
96 |
97 | nElectrodes = svmECOC.nElectrodes;
98 |
99 | nSamps = length(svmECOC.time);
100 |
101 |
102 | %% Step 9: Loop through participants
103 | for s = 1:nSubs %decoding is performed within each subject independently
104 | sn = subs(s);
105 |
106 | %progress output to command window
107 | fprintf('Subject:\t%d\n',sn)
108 |
109 | %% Parameters to set per subject
110 | currentSub = num2str(sn);
111 | loadThis = strcat(dataLocation,fName,currentSub,'.mat');
112 |
113 | % where to save decoding output file name.
114 | % File (.mat) will contain decoding results.
115 | OutputfName = strcat(saveLocation,savName,currentSub,'.mat');
116 |
117 |
118 | %% Data Loading/preallocation per subject
119 | % loads bin_organized data
120 | load(loadThis)
121 |
122 | % grab EEG data from bin-list organized data
123 | eegs = binorgEEG.binwise_data;
124 | nPerBin = binorgEEG.n_trials_this_bin;
125 |
126 | % set up time points
127 | % we create index of timpoint of interests from original data
128 | tois = ismember(dataTime.pre:ogWin:dataTime.post,svmECOC.time);
129 |
130 | % # of trials
131 | svmECOC.nTrials = (sum(nPerBin));
132 |
133 | % Preallocate Matrices
134 | svm_predict = nan(nIter,nSamps,nBlocks,nBins); % a matrix to save prediction from SVM
135 | tst_target = nan(nIter,nSamps,nBlocks,nBins); % a matrix to save true target values
136 |
137 | % create svmECOC.block structure to save block assignments
138 | svmECOC.blocks=struct();
139 |
140 | if nBins ~= max(size(eegs))
141 | error('Error. nBins dne # of bins in dataset!');
142 | % Code to be used on a bin-epoched dataset for one
143 | % class only (e.g. Orientation). Users may
144 | % try to bin multiple classes in one BDF.
145 | % This is not currently allowed.
146 | end
147 |
148 |
149 | %% Step 8: Loop through each iteration with random shuffling
150 | tic % start timing iteration loop
151 |
152 | for iter = 1:nIter
153 |
154 | %% Obtaining AVG. EEG (ERP spatial dist)
155 | % within each block at each time point
156 | % stored in blockDat_filtData
157 |
158 | %preallocate & rewrite per each iteration
159 | blockDat_filtData = nan(nBins*nBlocks,nElectrodes,nSamps);
160 | labels = nan(nBins*nBlocks,1); % bin labels for averaged & filtered EEG data
161 | blockNum = nan(nBins*nBlocks,1); % block numbers for averaged & filtered EEG data
162 | bCnt = 1; %initialize binblock counter
163 |
164 | % this code operates and creates ERPs at each bin
165 | % and organizes that into approprate block
166 |
167 | %% shuffling, binning, & averaging
168 | for bin = 1:nBins
169 |
170 | if equalT == 1 %equal trials across bins
171 | % find bin with fewest trial
172 | minCnt = min(nPerBin);
173 |
174 | % max # of trials such that # of trials for each bin ...
175 | % can be equated within each block
176 | nPerBinBlock = floor(minCnt/nBlocks);
177 |
178 | %Obtain index within each shuffled bin
179 | shuffBin = randperm((nPerBinBlock*nBlocks))';
180 |
181 | %Preallocate arrays
182 | blocks = nan(size(shuffBin));
183 | shuffBlocks = nan(size(shuffBin));
184 |
185 | %arrage block order within bins
186 | x = repmat((1:nBlocks)',nPerBinBlock,1);
187 | shuffBlocks(shuffBin) = x;
188 |
189 |
190 | else
191 | % We will use as many possible trials per
192 | % bin having accounted already for artifacts
193 |
194 | %Drop excess trials
195 | nPerBinBlock = floor(nPerBin/nBlocks); %array for nPerBin
196 |
197 | %Obtain index within each shuffled bin
198 | shuffBin = randperm((nPerBinBlock(bin))*nBlocks)';
199 |
200 | %Preallocate arrays
201 |
202 | blocks = nan(size(shuffBin));
203 | shuffBlocks = nan(size(shuffBin));
204 |
205 | %arrage block order within bins
206 | x = repmat((1:nBlocks)',nPerBinBlock(bin),1);
207 | shuffBlocks(shuffBin) = x;
208 | end
209 |
210 | %unshuffled block assignment
211 | blocks(shuffBin) = shuffBlocks;
212 |
213 | % save block assignment
214 | blockID = ['iter' num2str(iter) 'bin' num2str(bin)];
215 |
216 | svmECOC.blocks.(blockID) = blocks; % block assignment
217 |
218 |
219 | %create ERP average and place into blockDat_filtData struct
220 | %grab current bin with correct # of electrodes & samps
221 | eeg_now = eegs(bin).data(ReleventChan,:,:);
222 |
223 | %here, we create blockDat_filtData.
224 | %this results in nBins*nBlocks amount of ERP spatial
225 | %distributions (across nChans) at each sample/timepoint
226 |
227 | %% Step 1: computing ERPs based on random subset of trials for each block
228 | for bl = 1:nBlocks
229 |
230 | blockDat_filtData(bCnt,:,:) = squeeze(mean(eeg_now(:,tois,blocks==bl),3));
231 |
232 | labels(bCnt) = bin; %used for arranging classification obj.
233 |
234 | blockNum(bCnt) = bl;
235 |
236 | bCnt = bCnt+1;
237 |
238 | end
239 |
240 | end
241 |
242 |
243 | %% Step 7: Loop through each timepoint
244 | % Do SVM_ECOC at each time point
245 | parfor t = 1:nSamps
246 |
247 | % grab data for timepoint t
248 | toi = ismember(times,times(t)-svmECOC.window/2:times(t)+svmECOC.window/2);
249 |
250 | % average across time window of interest
251 | % here, you can parse nBin*nBlock across all channels (ERP spatial dist)
252 | dataAtTimeT = squeeze(mean(blockDat_filtData(:,:,toi),3));
253 |
254 | %% Step 6: Cross-validation for-loop
255 | for i=1:nBlocks % loop through blocks, holding each out as the test set
256 |
257 |
258 | %% Step 2 & Step 4: Assigning training and testing data sets
259 | trnl = labels(blockNum~=i); % training labels
260 |
261 | tstl = labels(blockNum==i); % test labels
262 |
263 | trnD = dataAtTimeT(blockNum~=i,:); % training data
264 |
265 | tstD = dataAtTimeT(blockNum==i,:); % test data
266 |
267 | %% Step 3: Training
268 | mdl = fitcecoc(trnD,trnl, 'Coding','onevsall','Learners','SVM' ); %train support vector mahcine
269 | %% Step 5: Testing
270 | LabelPredicted = predict(mdl, tstD); % predict classes for new data
271 |
272 | svm_predict(iter,t,i,:) = LabelPredicted; % save predicted labels
273 |
274 | tst_target(iter,t,i,:) = tstl; % save true target labels
275 |
276 |
277 | end % end of block: Step 6: cross-validation
278 |
279 | end % end of time points: Step 7: Decoding each time point
280 |
281 | end % end of iteration: Step 8: iteration with random shuffling
282 |
283 | toc % stop timing the iteration loop
284 |
285 | %output decoding results in main svmECOC structure
286 | svmECOC.targets = tst_target;
287 | svmECOC.modelPredict = svm_predict;
288 | svmECOC.nBlocks = nBlocks;
289 |
290 | save(OutputfName,'svmECOC','-v7.3');
291 |
292 | end % end of subject loop: Step 9: Decoding for each participant
--------------------------------------------------------------------------------
/SVM_ECOC_ERP_PermutationTesting_2020.m:
--------------------------------------------------------------------------------
1 | % This is an updated script that computes average decoding accuracy
2 | % and performes cluster-based permutation analysis.
3 |
4 | % In order to perform cluster-based permutation analysis, users must use
5 | % this script to simulate null-distribution to test against.
6 |
7 | % This script needs all the original decoding results in the same
8 | % directory. These simulations utilize these subject decoding results.
9 |
10 | %Edited by Aaron Simmons (UC Davis)
11 | %Original Author: Gi-Yeul Bae (ASU)
12 |
13 | %% Parameters
14 | % Must match SVM_ECOC_Stat_Plot_Permutation_2020.m
15 |
16 | % Subject List
17 | subList = [505 506 507 508 509 510 512 514 516 517 519 520 521 523 524 525];
18 | Nsub = length(subList);
19 |
20 | % Decoding Parameters (must match svmECOC object)
21 | Nblock = 3; % cross-validation
22 | Nitr = 10; % iteration
23 | Ntp = 100; % # of time points
24 | NBins = 16; % # of stimulus bins
25 |
26 | % Permutation Simulation Parameters
27 | NPermutations = 10000; %# of permutations
28 | permutedT = nan(1,NPermutations); %preallocate memory
29 | NTrials = zeros(Nsub,1); %Preallocate trials from svmECOC object
30 | chancelvl = 1/NBins; %chance level of avg. decoding
31 |
32 | % resampled timepoints from decoding (20ms/tp)
33 | tm = -500:20:1496;
34 |
35 | %create empty matrix
36 | AverageAccuracy = zeros(Nsub,Ntp);
37 |
38 | % which time points to permute? relevantTime to conduct stats
39 | tStart = find(tm==220); % start of retention interval
40 | ntPerm = find(tm==1480); % end of retention interval (in this case, end of epoch)
41 |
42 | % Load Individual subject filenames
43 | fileLocation = pwd;
44 | fName = ['/Orientation_Results_ERPbased_'];
45 |
46 | % Save Filename (saves .mat file to current directory)
47 | saveName = ['Permuted_T_mass.mat'];
48 |
49 | tic
50 |
51 | for permt = 1: NPermutations
52 |
53 | for sub = 1:Nsub
54 | DecodingAccuracy = zeros(Ntp,Nblock,Nitr);
55 |
56 | % Load Data
57 | readThis =strcat(fileLocation,fName,num2str(subList(sub)),'.mat');
58 | load(readThis)
59 |
60 | NTrials(sub,1) = svmECOC.nTrials;
61 |
62 | svmPrediction = squeeze(svmECOC.modelPredict);
63 | tstTargets = squeeze(svmECOC.targets);
64 |
65 | for block = 1:Nblock
66 | for itr = 1:Nitr
67 | %% assign random target ID for Permutation Testing
68 | Answer = shuffle(1:NBins)';
69 |
70 | for tp = 1:Ntp % for stimulus duration of 0 ms ~ 1480 ms
71 |
72 | prediction = squeeze(svmPrediction(itr,tp,block,:)); % this is predictions from models
73 | Err = Answer - prediction;
74 | ACC = mean(Err==0);
75 | DecodingAccuracy(tp,block,itr) = ACC; % average decoding accuracy
76 |
77 | end
78 |
79 | end
80 | end
81 |
82 | grandAvg = squeeze(mean(mean(DecodingAccuracy,2),3));
83 |
84 | smoothed = nan(1,Ntp);
85 | for tAvg = 1:Ntp
86 | if tAvg ==1
87 | smoothed(tAvg) = mean(grandAvg((tAvg):(tAvg+2)));
88 | elseif tAvg ==2
89 | smoothed(tAvg) = mean(grandAvg((tAvg-1):(tAvg+2)));
90 | elseif tAvg == (Ntp-1)
91 | smoothed(tAvg) = mean(grandAvg((tAvg-2):(tAvg+1)));
92 | elseif tAvg == Ntp
93 | smoothed(tAvg) = mean(grandAvg((tAvg-2):(tAvg)));
94 | else
95 | smoothed(tAvg) = mean(grandAvg((tAvg-2):(tAvg+2)));
96 | end
97 |
98 | end
99 |
100 |
101 | AverageAccuracy(sub,:) =smoothed; % average across iteration and block
102 |
103 | clear svmECOC
104 |
105 | end %End of subject
106 |
107 | % AverageAccuracy = Nsub x Ncond (Attend vs Ignore) x Ntyp (Evoked VS Total) x Ntp;
108 |
109 | %now compute average accuracy across participants
110 | subAverage = squeeze(mean(AverageAccuracy,1));
111 | seAverage = squeeze(std(AverageAccuracy,1))/sqrt(Nsub);
112 |
113 | %% do cluster mass analyses
114 |
115 | releventTime = tStart:ntPerm; % during the retention interval
116 |
117 | Ps = nan(2,length(releventTime));
118 | for i = 1:length(releventTime) % make sure this time range is correct
119 | tp = releventTime(i);
120 |
121 | [H,P,CI,STATS] = ttest(AverageAccuracy(:,tp), chancelvl,'tail','right'); % Test Against Zero
122 |
123 | Ps(1,i) = STATS.tstat;
124 | Ps(2,i) = P;
125 | end
126 | % find significant points
127 | candid = Ps(2,:) <= .05;
128 |
129 | candid_marked = zeros(1,length(candid));
130 | candid_marked(1,1) = candid(1,1);
131 | candid_marked(1,length(candid)) = candid(1,length(candid));
132 | %remove orphan time points
133 | for i = 2:length(releventTime)-1
134 |
135 | if candid(1,i-1) == 0 && candid(1,i) ==1 && candid(1,i+1) ==0
136 | candid_marked(1,i) = 0;
137 | else
138 | candid_marked(1,i) = candid(1,i);
139 | end
140 |
141 | end
142 |
143 | % combine whole time range with relevent time & significant information
144 | clusters = zeros(length(tm),1);
145 | clusterT = zeros(length(tm),1);
146 | clusters(releventTime,1) = candid_marked; % significant or not
147 | clusterT(releventTime,1) = Ps(1,:); % t values
148 | clusterTsum = sum(Ps(1,logical(candid_marked)));
149 |
150 | %%find how many clusters are there, and compute summed T of each cluster
151 | tmp = zeros(10,25); % creates a matrix with arbitrary size (n cluster x size of each cluster)
152 | cl = 0;
153 | member = 0;
154 | for i = 2:length(clusters)-1
155 |
156 |
157 | if clusters(i-1) ==0 && clusters(i) == 1 && clusters(i+1) == 1
158 | cl = cl+1;
159 | member = member +1;
160 | tmp(cl,member) = i;
161 |
162 | elseif clusters(i-1) ==1 && clusters(i) == 1 && clusters(i+1) == 0
163 | if i == 2
164 | cl = cl +1;
165 | member = member +1;
166 | tmp(cl,member) = i;
167 | member = 0;
168 |
169 | else
170 | member = member +1;
171 | tmp(cl,member) = i;
172 | member = 0;
173 | end
174 |
175 |
176 | elseif clusters(i-1) ==1 && clusters(i) == 1 && clusters(i+1) == 1
177 | if i ==2
178 | cl = cl+1;
179 | member = member +1;
180 | tmp(cl,member) = i;
181 | else
182 | member = member +1;
183 | tmp(cl,member) = i;
184 | end
185 |
186 |
187 | else
188 |
189 |
190 | end
191 | end
192 |
193 |
194 | HowManyClusters = cl;
195 | a = tmp(1:cl,:);
196 | eachCluster = a(:,logical(sum(a,1)~=0));
197 |
198 | %now, compute summed T of each cluster
199 | dat_clusterSumT = zeros(HowManyClusters,1);
200 | for c = 1:HowManyClusters
201 | dat_clusterSumT(c,1) = sum(clusterT(eachCluster(c,eachCluster(c,:) ~=0)));
202 | end
203 |
204 | if size(dat_clusterSumT,1) > 0 % if there is at least one signifiant cluster
205 | permutedT(1,permt) = max(dat_clusterSumT);
206 | else
207 | permutedT(1,permt) = 0;
208 | end
209 | if rem(permt,(NPermutations/10)) == 0
210 | progress = 100*(permt/NPermutations);
211 | whatToPrint = strcat(num2str(progress),'% is done.');
212 | disp(whatToPrint)
213 | toc % end of one permutation
214 | tic
215 | end
216 |
217 | end % end of simulation
218 |
219 | permutedT = sort(permutedT);
220 | save(saveName,'permutedT');
221 |
--------------------------------------------------------------------------------
/SVM_ECOC_Stat_Plot_Permutation_2020.m:
--------------------------------------------------------------------------------
1 | % This is an updated script that computes average decoding accuracy
2 | % and performes cluster-based permutation analysis.
3 |
4 | % In order to perform cluster-based permutation analysis, users must have
5 | % already simulated null-distribution to test against. See
6 | % "SVM_ECOC_ERP_PermutationTesting_revised.". Plot function requires matlab
7 | % function "boundedline" & "inpaint_nans" (Kearny 2020) in working directory.
8 | % see here: https://www.mathworks.com/matlabcentral/fileexchange/27485-boundedline-m
9 |
10 | % Edited by Aaron Simmons (UC Davis)
11 | % Original Author: Gi-Yeul Bae (Arizona State University)
12 |
13 | % Note: Randomization routine included in this analysis (e.g., random integer generator)
14 | % can produce stats slightly different from those reported in the paper.
15 | % Gi-Yeul Bae 2017-10-3
16 |
17 | %% Parameters
18 |
19 | % Subject List
20 | subList = [505 506 507 508 509 510 512 514 516 517 519 520 521 523 524 525];
21 | Nsub = length(subList); % N subjects
22 |
23 | % Decoding Parameters (must match svmECOC object)
24 | Nblock = 3; % cross-validation
25 | Nitr = 10; % iteration
26 | Ntp = 100; % # of time points
27 | NBins = 16; % # of stimulus bins
28 |
29 | % Stats (see "Plot Significant Clusters" (line 204) for resulting plot formatting)
30 | ClusterMassAnalysis = 0; % 0 = do not perform / 1 = perform
31 | NPermutations = 10000; % N permutations of null distribution
32 | chancelvl = 1/NBins; %chance lvl of avg. decoding
33 | tm = -500:20:1496; % resampled timepoints from decoding (20ms/tp)
34 | %define time point for statistical analysis
35 | releventTime = 37:100; % corresponds to [220, 1480] ms
36 | % find(tm==220); % obtain index of relevant time points in sampling units
37 |
38 | % Individual subject filenames
39 | fileLocation = pwd;
40 | fName = ['Processed/Orientation_Results_ERPbased_'];
41 |
42 |
43 | %% Plotting Decoding Results (no stats)
44 |
45 | % Create/preallocate empty matrix
46 | AverageAccuracy = nan(Nsub,Ntp);
47 |
48 | % First we will obtain average decoding accuracy within subjects at each
49 | % timepoint. This results in size(AverageAccuracy).
50 |
51 | for sub = 1:Nsub
52 | DecodingAccuracy = nan(Ntp,Nblock,Nitr);
53 | % We will compute decoding accuracy per subject in DecodingAccuracy,
54 | % enter DecodingAccuracy into AverageAccuray, then overwrite next subj.
55 |
56 | %% load SVM_ECOC output files
57 | readThis =strcat(fileLocation,filesep,fName,num2str(subList(sub)),'.mat');
58 | load(readThis)
59 |
60 | % Obtain predictions from SVM-ECOC model
61 | svmPrediction = squeeze(svmECOC.modelPredict);
62 | tstTargets = squeeze(svmECOC.targets);
63 | %clear svmECOC (is now a large unnecessary objet)
64 | clear svmECOC
65 |
66 | %% Step 5: Compute decoding accuracy of each decoding trial
67 | for block = 1:Nblock
68 | for itr = 1:Nitr
69 | for tp = 1:Ntp
70 |
71 | prediction = squeeze(svmPrediction(itr,tp,block,:)); % this is predictions from models
72 | TrueAnswer = squeeze(tstTargets(itr,tp,block,:)); % this is predictions from models
73 | Err = TrueAnswer - prediction; %compute error. No error = 0
74 | ACC = mean(Err==0); %Correct hit = 0 (avg propotion of vector of 1s and 0s)
75 | DecodingAccuracy(tp,block,itr) = ACC; % average decoding accuracy at tp & block
76 |
77 | end
78 | end
79 | end
80 |
81 | % Average across block and iterations
82 | grandAvg = squeeze(mean(mean(DecodingAccuracy,2),3));
83 |
84 | % Perform temporal smoothing (5 point moving avg)
85 | smoothed = nan(1,Ntp);
86 | for tAvg = 1:Ntp
87 | if tAvg ==1
88 | smoothed(tAvg) = mean(grandAvg((tAvg):(tAvg+2)));
89 | elseif tAvg ==2
90 | smoothed(tAvg) = mean(grandAvg((tAvg-1):(tAvg+2)));
91 | elseif tAvg == (Ntp-1)
92 | smoothed(tAvg) = mean(grandAvg((tAvg-2):(tAvg+1)));
93 | elseif tAvg == Ntp
94 | smoothed(tAvg) = mean(grandAvg((tAvg-2):(tAvg)));
95 | else
96 | smoothed(tAvg) = mean(grandAvg((tAvg-2):(tAvg+2)));
97 | end
98 |
99 | end
100 |
101 | % Save smoothe data
102 | AverageAccuracy(sub,:) =smoothed; % average across iteration and block
103 |
104 | end %End of subject
105 |
106 | %compute average accuracy across participants and SE of the mean.
107 | subAverage = squeeze(mean(AverageAccuracy,1));
108 | seAverage = squeeze(std(AverageAccuracy,1))/sqrt(Nsub);
109 |
110 | %% Visualization:Plotting the decoding accuracy
111 | % across all subjects at each timepoint
112 | % Not publication quality
113 | figure(1)
114 | cl=colormap(parula(50));
115 | plot(tm, subAverage); %plot
116 | boundedline(tm,subAverage,seAverage,'cmap',cl(42,:),'alpha','transparency',0.35)
117 | line([tm(1),tm(length(tm))],[chancelvl,chancelvl]); %chance line
118 |
119 |
120 | %% Perform cluster mass analyses
121 | if ClusterMassAnalysis == 1
122 |
123 | % t-test at each relevent time point
124 | Ps = nan(2,length(releventTime));
125 | for i = 1:length(releventTime)
126 | tp = releventTime(i);
127 |
128 | [H,P,CI,STATS] = ttest(AverageAccuracy(:,tp), chancelvl, 'tail', 'right'); % one sample t-test
129 |
130 | Ps(1,i) = STATS.tstat;
131 | Ps(2,i) = P;
132 | end
133 |
134 | % find significant time points
135 | candid = Ps(2,:) <= .05;
136 |
137 | %remove orphan time points
138 | candid_woOrphan = candid;
139 | candid_woOrphan(1,1) = candid(1,1);
140 | for i = 2:(length(releventTime)-1)
141 |
142 | if candid(1,i-1) == 0 && candid(1,i) ==1 && candid(1,i+1) ==0
143 | candid_woOrphan(1,i) = 0;
144 | else
145 | candid_woOrphan(1,i) = candid(1,i);
146 | end
147 |
148 | end
149 |
150 | % combine whole time range with relevent time & significant information
151 | clusters = zeros(length(tm),1);
152 | clusterT = zeros(length(tm),1);
153 | clusters(releventTime,1) = candid_woOrphan;
154 | clusterT(releventTime,1) = Ps(1,:);
155 | clusterTsum = sum(Ps(1,logical(candid_woOrphan)));
156 |
157 | %%find how many clusters are there, and compute summed T of each cluster
158 | tmp = zeros(10,300);
159 | cl = 0;
160 | member = 0;
161 | for i = 2:length(clusters)-1
162 |
163 | if clusters(i-1) ==0 && clusters(i) == 1 && clusters(i+1) == 1
164 | cl = cl+1;
165 | member = member +1;
166 | tmp(cl,member) = i;
167 |
168 | elseif clusters(i-1) ==1 && clusters(i) == 1 && clusters(i+1) == 0
169 | member = member +1;
170 | tmp(cl,member) = i;
171 | member = 0;
172 | elseif clusters(i-1) ==1 && clusters(i) == 1 && clusters(i+1) == 1
173 | member = member +1;
174 | tmp(cl,member) = i;
175 |
176 | else
177 |
178 | end
179 | end
180 |
181 |
182 | HowManyClusters = cl;
183 | a = tmp(1:cl,:); % subset significant clusters
184 | eachCluster = a(:,logical(sum(a,1)~=0)); % cut the size at the maximum cluster
185 |
186 | %now, compute summed T of each cluster
187 | dat_clusterSumT = nan(HowManyClusters,1);
188 | for c = 1:HowManyClusters
189 | dat_clusterSumT(c,1) = sum(clusterT(eachCluster(c,eachCluster(c,:) ~=0)));
190 | end
191 |
192 |
193 |
194 | %% note: Load Simulation tests (simulation takes very long time)
195 | load('Permuted_T_mass.mat')
196 |
197 |
198 | %% find critical t-value
199 | cutOff = NPermutations - NPermutations * 0.05; %one tailed
200 | critT = permutedT(cutOff); % t-mass of top 95%
201 | sigCluster = dat_clusterSumT > critT;
202 |
203 |
204 | %% Plot significant clusters
205 | figure(2)
206 | cl=colormap(parula(50));
207 |
208 | % draw average accuracy
209 | accEst = squeeze(subAverage);
210 | % draw clusters
211 | draw = eachCluster(sigCluster,:);
212 | draw = sort(reshape(draw,1,size(draw,1)*size(draw,2)));
213 | draw = draw(draw>0);
214 |
215 | w = zeros(Ntp,1);
216 | w(draw)=1;
217 | a = area(1:length(tm), accEst.*w');
218 | a.EdgeColor = 'none';
219 | a.FaceColor = [0.8,0.8,0.8];
220 | child = get(a,'Children');
221 | set(child,'FaceAlpha',0.9)
222 | % draw mean and SE of average decoding accuracy
223 | hold on
224 | mEI = boundedline(1:length(tm),subAverage,seAverage, 'cmap',cl(42,:),'alpha','transparency',0.35);
225 |
226 | %% Plot Formatting
227 | xlabel('Time (ms)');ylabel('Decoding Accuracy')
228 | ax = gca;
229 | ax.YLim = [0.05, 0.15];
230 | ax.YTick = [0,0.02,0.04,0.06,0.08,0.10,0.12,0.14];
231 | ax.XTick = [1 26 51 76 100];
232 | ax.XTickLabel = {'-500','0','500','1000','1500'};
233 | h = line(1:length(tm),chancelvl* ones(1,Ntp));
234 | h.LineStyle = '--';
235 | h.Color = [0.1,0.1,0.1];
236 | hold off
237 |
238 | saveas(figure(2),'plot_decoding_accuracy_with_stat','pdf')
239 | end
--------------------------------------------------------------------------------
/boundedline.m:
--------------------------------------------------------------------------------
1 | function varargout = boundedline(varargin)
2 | %BOUNDEDLINE Plot a line with shaded error/confidence bounds
3 | %
4 | % [hl, hp] = boundedline(x, y, b)
5 | % [hl, hp] = boundedline(x, y, b, linespec)
6 | % [hl, hp] = boundedline(x1, y1, b1, linespec1, x2, y2, b2, linespec2)
7 | % [hl, hp] = boundedline(..., 'alpha')
8 | % [hl, hp] = boundedline(..., ax)
9 | % [hl, hp] = boundedline(..., 'transparency', trans)
10 | % [hl, hp] = boundedline(..., 'orientation', orient)
11 | % [hl, hp] = boundedline(..., 'nan', nanflag)
12 | % [hl, hp] = boundedline(..., 'cmap', cmap)
13 | %
14 | % Input variables:
15 | %
16 | % x, y: x and y values, either vectors of the same length, matrices
17 | % of the same size, or vector/matrix pair where the row or
18 | % column size of the array matches the length of the vector
19 | % (same requirements as for plot function).
20 | %
21 | % b: npoint x nside x nline array. Distance from line to
22 | % boundary, for each point along the line (dimension 1), for
23 | % each side of the line (lower/upper or left/right, depending
24 | % on orientation) (dimension 2), and for each plotted line
25 | % described by the preceding x-y values (dimension 3). If
26 | % size(b,1) == 1, the bounds will be the same for all points
27 | % along the line. If size(b,2) == 1, the bounds will be
28 | % symmetrical on both sides of the lines. If size(b,3) == 1,
29 | % the same bounds will be applied to all lines described by
30 | % the preceding x-y arrays (only applicable when either x or
31 | % y is an array). Bounds cannot include Inf, -Inf, or NaN,
32 | %
33 | % linespec: line specification that determines line type, marker
34 | % symbol, and color of the plotted lines for the preceding
35 | % x-y values.
36 | %
37 | % 'alpha': if included, the bounded area will be rendered with a
38 | % partially-transparent patch the same color as the
39 | % corresponding line(s). If not included, the bounded area
40 | % will be an opaque patch with a lighter shade of the
41 | % corresponding line color.
42 | %
43 | % ax: handle of axis where lines will be plotted. If not
44 | % included, the current axis will be used.
45 | %
46 | % transp: Scalar between 0 and 1 indicating with the transparency or
47 | % intensity of color of the bounded area patch. Default is
48 | % 0.2.
49 | %
50 | % orient: direction to add bounds
51 | % 'vert': add bounds in vertical (y) direction (default)
52 | % 'horiz': add bounds in horizontal (x) direction
53 | %
54 | % nanflag: Sets how NaNs in the boundedline patch should be handled
55 | % 'fill': fill the value based on neighboring values,
56 | % smoothing over the gap
57 | % 'gap': leave a blank space over/below the line
58 | % 'remove': drop NaNs from patches, creating a linear
59 | % interpolation over the gap. Note that this
60 | % applies only to the bounds; NaNs in the line will
61 | % remain.
62 | %
63 | % cmap: n x 3 colormap array. If included, lines will be colored
64 | % (in order of plotting) according to this colormap,
65 | % overriding any linespec or default colors.
66 | %
67 | % Output variables:
68 | %
69 | % hl: handles to line objects
70 | %
71 | % hp: handles to patch objects
72 | %
73 | % Example:
74 | %
75 | % x = linspace(0, 2*pi, 50);
76 | % y1 = sin(x);
77 | % y2 = cos(x);
78 | % e1 = rand(size(y1))*.5+.5;
79 | % e2 = [.25 .5];
80 | %
81 | % ax(1) = subplot(2,2,1);
82 | % [l,p] = boundedline(x, y1, e1, '-b*', x, y2, e2, '--ro');
83 | % outlinebounds(l,p);
84 | % title('Opaque bounds, with outline');
85 | %
86 | % ax(2) = subplot(2,2,2);
87 | % boundedline(x, [y1;y2], rand(length(y1),2,2)*.5+.5, 'alpha');
88 | % title('Transparent bounds');
89 | %
90 | % ax(3) = subplot(2,2,3);
91 | % boundedline([y1;y2], x, e1(1), 'orientation', 'horiz')
92 | % title('Horizontal bounds');
93 | %
94 | % ax(4) = subplot(2,2,4);
95 | % boundedline(x, repmat(y1, 4,1), permute(0.5:-0.1:0.2, [3 1 2]), ...
96 | % 'cmap', cool(4), 'transparency', 0.5);
97 | % title('Multiple bounds using colormap');
98 |
99 |
100 | % Copyright 2010 Kelly Kearney
101 |
102 | %--------------------
103 | % Parse input
104 | %--------------------
105 |
106 | % Alpha flag
107 |
108 | isalpha = cellfun(@(x) ischar(x) && strcmp(x, 'alpha'), varargin);
109 | if any(isalpha)
110 | usealpha = true;
111 | varargin = varargin(~isalpha);
112 | else
113 | usealpha = false;
114 | end
115 |
116 | % Axis
117 |
118 | isax = cellfun(@(x) isscalar(x) && ishandle(x) && strcmp('axes', get(x,'type')), varargin);
119 | if any(isax)
120 | hax = varargin{isax};
121 | varargin = varargin(~isax);
122 | else
123 | hax = gca;
124 | end
125 |
126 | % Transparency
127 |
128 | [found, trans, varargin] = parseparam(varargin, 'transparency');
129 |
130 | if ~found
131 | trans = 0.2;
132 | end
133 |
134 | if ~isscalar(trans) || trans < 0 || trans > 1
135 | error('Transparency must be scalar between 0 and 1');
136 | end
137 |
138 | % Orientation
139 |
140 | [found, orient, varargin] = parseparam(varargin, 'orientation');
141 |
142 | if ~found
143 | orient = 'vert';
144 | end
145 |
146 | if strcmp(orient, 'vert')
147 | isvert = true;
148 | elseif strcmp(orient, 'horiz')
149 | isvert = false;
150 | else
151 | error('Orientation must be ''vert'' or ''horiz''');
152 | end
153 |
154 |
155 | % Colormap
156 |
157 | [hascmap, cmap, varargin] = parseparam(varargin, 'cmap');
158 |
159 |
160 | % NaN flag
161 |
162 | [found, nanflag, varargin] = parseparam(varargin, 'nan');
163 | if ~found
164 | nanflag = 'fill';
165 | end
166 | if ~ismember(nanflag, {'fill', 'gap', 'remove'})
167 | error('Nan flag must be ''fill'', ''gap'', or ''remove''');
168 | end
169 |
170 | % X, Y, E triplets, and linespec
171 |
172 | [x,y,err,linespec] = deal(cell(0));
173 | while ~isempty(varargin)
174 | if length(varargin) < 3
175 | error('Unexpected input: should be x, y, bounds triplets');
176 | end
177 | if all(cellfun(@isnumeric, varargin(1:3)))
178 | x = [x varargin(1)];
179 | y = [y varargin(2)];
180 | err = [err varargin(3)];
181 | varargin(1:3) = [];
182 | else
183 | if any(cellfun(@(x) isa(x, 'datetime'), varargin(1:3)))
184 | % Special error message for most likely culprit: datetimes
185 | error('boundedline cannot support datetime input due to incompatibility between patches and datetime axes; please convert to datenumbers instead');
186 | else
187 | % Otherwise
188 | error('Unexpected input: should be numeric x, y, bounds triplets');
189 | end
190 | end
191 | if ~isempty(varargin) && ischar(varargin{1})
192 | linespec = [linespec varargin(1)];
193 | varargin(1) = [];
194 | else
195 | linespec = [linespec {[]}];
196 | end
197 | end
198 |
199 | %--------------------
200 | % Reformat x and y
201 | % for line and patch
202 | % plotting
203 | %--------------------
204 |
205 | % Calculate y values for bounding lines
206 |
207 | plotdata = cell(0,7);
208 |
209 | htemp = figure('visible', 'off');
210 | for ix = 1:length(x)
211 |
212 | % Get full x, y, and linespec data for each line (easier to let plot
213 | % check for properly-sized x and y and expand values than to try to do
214 | % it myself)
215 |
216 | try
217 | if isempty(linespec{ix})
218 | hltemp = plot(x{ix}, y{ix});
219 | else
220 | hltemp = plot(x{ix}, y{ix}, linespec{ix});
221 | end
222 | catch
223 | close(htemp);
224 | error('X and Y matrices and/or linespec not appropriate for line plot');
225 | end
226 |
227 | linedata = get(hltemp, {'xdata', 'ydata', 'marker', 'linestyle', 'color'});
228 |
229 | nline = size(linedata,1);
230 |
231 | % Expand bounds matrix if necessary
232 |
233 | if nline > 1
234 | if ndims(err{ix}) == 3
235 | err2 = squeeze(num2cell(err{ix},[1 2]));
236 | else
237 | err2 = repmat(err(ix),nline,1);
238 | end
239 | else
240 | err2 = err(ix);
241 | end
242 |
243 | % Figure out upper and lower bounds
244 |
245 | [lo, hi] = deal(cell(nline,1));
246 | for iln = 1:nline
247 |
248 | x2 = linedata{iln,1};
249 | y2 = linedata{iln,2};
250 | nx = length(x2);
251 |
252 | if isvert
253 | lineval = y2;
254 | else
255 | lineval = x2;
256 | end
257 |
258 | sz = size(err2{iln});
259 |
260 | if isequal(sz, [nx 2])
261 | lo{iln} = lineval - err2{iln}(:,1)';
262 | hi{iln} = lineval + err2{iln}(:,2)';
263 | elseif isequal(sz, [nx 1])
264 | lo{iln} = lineval - err2{iln}';
265 | hi{iln} = lineval + err2{iln}';
266 | elseif isequal(sz, [1 2])
267 | lo{iln} = lineval - err2{iln}(1);
268 | hi{iln} = lineval + err2{iln}(2);
269 | elseif isequal(sz, [1 1])
270 | lo{iln} = lineval - err2{iln};
271 | hi{iln} = lineval + err2{iln};
272 | elseif isequal(sz, [2 nx]) % not documented, but accepted anyways
273 | lo{iln} = lineval - err2{iln}(:,1);
274 | hi{iln} = lineval + err2{iln}(:,2);
275 | elseif isequal(sz, [1 nx]) % not documented, but accepted anyways
276 | lo{iln} = lineval - err2{iln};
277 | hi{iln} = lineval + err2{iln};
278 | elseif isequal(sz, [2 1]) % not documented, but accepted anyways
279 | lo{iln} = lineval - err2{iln}(1);
280 | hi{iln} = lineval + err2{iln}(2);
281 | else
282 | error('Error bounds must be npt x nside x nline array');
283 | end
284 |
285 | end
286 |
287 | % Combine all data (xline, yline, marker, linestyle, color, lower bound
288 | % (x or y), upper bound (x or y)
289 |
290 | plotdata = [plotdata; linedata lo hi];
291 |
292 | end
293 | close(htemp);
294 |
295 | % Override colormap
296 |
297 | if hascmap
298 | nd = size(plotdata,1);
299 | cmap = repmat(cmap, ceil(nd/size(cmap,1)), 1);
300 | cmap = cmap(1:nd,:);
301 | plotdata(:,5) = num2cell(cmap,2);
302 | end
303 |
304 |
305 | %--------------------
306 | % Plot
307 | %--------------------
308 |
309 | % Setup of x and y, plus line and patch properties
310 |
311 | nline = size(plotdata,1);
312 | [xl, yl, xp, yp, marker, lnsty, lncol, ptchcol, alpha] = deal(cell(nline,1));
313 |
314 | for iln = 1:nline
315 | xl{iln} = plotdata{iln,1};
316 | yl{iln} = plotdata{iln,2};
317 | % if isvert
318 | % xp{iln} = [plotdata{iln,1} fliplr(plotdata{iln,1})];
319 | % yp{iln} = [plotdata{iln,6} fliplr(plotdata{iln,7})];
320 | % else
321 | % xp{iln} = [plotdata{iln,6} fliplr(plotdata{iln,7})];
322 | % yp{iln} = [plotdata{iln,2} fliplr(plotdata{iln,2})];
323 | % end
324 |
325 | [xp{iln}, yp{iln}] = calcpatch(plotdata{iln,1}, plotdata{iln,2}, isvert, plotdata{iln,6}, plotdata{iln,7}, nanflag);
326 |
327 | marker{iln} = plotdata{iln,3};
328 | lnsty{iln} = plotdata{iln,4};
329 |
330 | if usealpha
331 | lncol{iln} = plotdata{iln,5};
332 | ptchcol{iln} = plotdata{iln,5};
333 | alpha{iln} = trans;
334 | else
335 | lncol{iln} = plotdata{iln,5};
336 | ptchcol{iln} = interp1([0 1], [1 1 1; lncol{iln}], trans);
337 | alpha{iln} = 1;
338 | end
339 | end
340 |
341 | % Plot patches and lines
342 |
343 | if verLessThan('matlab', '8.4.0')
344 | [hp,hl] = deal(zeros(nline,1));
345 | else
346 | [hp,hl] = deal(gobjects(nline,1));
347 | end
348 |
349 |
350 | for iln = 1:nline
351 | hp(iln) = patch(xp{iln}, yp{iln}, ptchcol{iln}, 'facealpha', alpha{iln}, 'edgecolor', 'none', 'parent', hax);
352 | end
353 |
354 | for iln = 1:nline
355 | hl(iln) = line(xl{iln}, yl{iln}, 'marker', marker{iln}, 'linestyle', lnsty{iln}, 'color', lncol{iln}, 'parent', hax);
356 | end
357 |
358 | %--------------------
359 | % Assign output
360 | %--------------------
361 |
362 | nargoutchk(0,2);
363 |
364 | if nargout >= 1
365 | varargout{1} = hl;
366 | end
367 |
368 | if nargout == 2
369 | varargout{2} = hp;
370 | end
371 |
372 | %--------------------
373 | % Parse optional
374 | % parameters
375 | %--------------------
376 |
377 | function [found, val, vars] = parseparam(vars, param)
378 |
379 | isvar = cellfun(@(x) ischar(x) && strcmpi(x, param), vars);
380 |
381 | if sum(isvar) > 1
382 | error('Parameters can only be passed once');
383 | end
384 |
385 | if any(isvar)
386 | found = true;
387 | idx = find(isvar);
388 | val = vars{idx+1};
389 | vars([idx idx+1]) = [];
390 | else
391 | found = false;
392 | val = [];
393 | end
394 |
395 | %----------------------------
396 | % Calculate patch coordinates
397 | %----------------------------
398 |
399 | function [xp, yp] = calcpatch(xl, yl, isvert, lo, hi, nanflag)
400 |
401 | ismissing = isnan([xl;yl;lo;hi]);
402 |
403 | % If gap method, split
404 |
405 | if any(ismissing(:)) && strcmp(nanflag, 'gap')
406 |
407 | tmp = [xl;yl;lo;hi];
408 |
409 | idx = find(any(ismissing,1));
410 | n = diff([0 idx length(xl)]);
411 |
412 | tmp = mat2cell(tmp, 4, n);
413 | isemp = cellfun('isempty', tmp);
414 | tmp = tmp(~isemp);
415 |
416 | tmp = cellfun(@(a) a(:,~any(isnan(a),1)), tmp, 'uni', 0);
417 | isemp = cellfun('isempty', tmp);
418 | tmp = tmp(~isemp);
419 |
420 | xl = cellfun(@(a) a(1,:), tmp, 'uni', 0);
421 | yl = cellfun(@(a) a(2,:), tmp, 'uni', 0);
422 | lo = cellfun(@(a) a(3,:), tmp, 'uni', 0);
423 | hi = cellfun(@(a) a(4,:), tmp, 'uni', 0);
424 | else
425 | xl = {xl};
426 | yl = {yl};
427 | lo = {lo};
428 | hi = {hi};
429 | end
430 |
431 | [xp, yp] = deal(cell(size(xl)));
432 |
433 | for ii = 1:length(xl)
434 |
435 | iseq = ~verLessThan('matlab', '8.4.0') && isequal(lo{ii}, hi{ii}); % deal with zero-width bug in R2014b/R2015a
436 |
437 | if isvert
438 | if iseq
439 | xp{ii} = [xl{ii} nan(size(xl{ii}))];
440 | yp{ii} = [lo{ii} fliplr(hi{ii})];
441 | else
442 | xp{ii} = [xl{ii} fliplr(xl{ii})];
443 | yp{ii} = [lo{ii} fliplr(hi{ii})];
444 | end
445 | else
446 | if iseq
447 | xp{ii} = [lo{ii} fliplr(hi{ii})];
448 | yp{ii} = [yl{ii} nan(size(yl{ii}))];
449 | else
450 | xp{ii} = [lo{ii} fliplr(hi{ii})];
451 | yp{ii} = [yl{ii} fliplr(yl{ii})];
452 | end
453 | end
454 |
455 | if strcmp(nanflag, 'fill')
456 | xp{ii} = inpaint_nans(xp{ii}', 4);
457 | yp{ii} = inpaint_nans(yp{ii}', 4);
458 | if iseq % need to maintain NaNs for zero-width bug
459 | nx = length(xp{ii});
460 | xp{ii}((nx/2)+1:end) = NaN;
461 | end
462 | elseif strcmp(nanflag, 'remove')
463 | if iseq
464 | nx = length(xp{ii});
465 | keepnan = false(size(xp));
466 | keepnan((nx/2)+1:end) = true;
467 | isn = (isnan(xp{ii}) | isnan(yp{ii})) & ~keepnan;
468 | else
469 | isn = isnan(xp{ii}) | isnan(yp{ii});
470 | end
471 | xp{ii} = xp{ii}(~isn);
472 | yp{ii} = yp{ii}(~isn);
473 | end
474 |
475 | end
476 |
477 | if strcmp(nanflag, 'gap')
478 | [xp, yp] = singlepatch(xp, yp);
479 | else
480 | xp = xp{1};
481 | yp = yp{1};
482 | end
483 |
484 |
--------------------------------------------------------------------------------
/inpaint_nans.m:
--------------------------------------------------------------------------------
1 | function B=inpaint_nans(A,method)
% INPAINT_NANS: in-paints over nans in an array
% usage: B=INPAINT_NANS(A) % default method
% usage: B=INPAINT_NANS(A,method) % specify method used
%
% Solves approximation to one of several pdes to
% interpolate and extrapolate holes in an array
%
% arguments (input):
% A - nxm array with some NaNs to be filled in
%
% method - (OPTIONAL) scalar numeric flag - specifies
% which approach (or physical metaphor to use
% for the interpolation.) All methods are capable
% of extrapolation, some are better than others.
% There are also speed differences, as well as
% accuracy differences for smooth surfaces.
%
% methods {0,1,2} use a simple plate metaphor.
% method 3 uses a better plate equation,
% but may be much slower and uses
% more memory.
% method 4 uses a spring metaphor.
% method 5 is an 8 neighbor average, with no
% rationale behind it compared to the
% other methods. I do not recommend
% its use.
%
% method == 0 --> (DEFAULT) see method 1, but
% this method does not build as large of a
% linear system in the case of only a few
% NaNs in a large array.
% Extrapolation behavior is linear.
%
% method == 1 --> simple approach, applies del^2
% over the entire array, then drops those parts
% of the array which do not have any contact with
% NaNs. Uses a least squares approach, but it
% does not modify known values.
% In the case of small arrays, this method is
% quite fast as it does very little extra work.
% Extrapolation behavior is linear.
%
% method == 2 --> uses del^2, but solving a direct
% linear system of equations for nan elements.
% This method will be the fastest possible for
% large systems since it uses the sparsest
% possible system of equations. Not a least
% squares approach, so it may be least robust
% to noise on the boundaries of any holes.
% This method will also be least able to
% interpolate accurately for smooth surfaces.
% Extrapolation behavior is linear.
%
% Note: method 2 has problems in 1-d, so this
% method is disabled for vector inputs.
%
% method == 3 --+ See method 0, but uses del^4 for
% the interpolating operator. This may result
% in more accurate interpolations, at some cost
% in speed.
%
% method == 4 --+ Uses a spring metaphor. Assumes
% springs (with a nominal length of zero)
% connect each node with every neighbor
% (horizontally, vertically and diagonally)
% Since each node tries to be like its neighbors,
% extrapolation is as a constant function where
% this is consistent with the neighboring nodes.
%
% method == 5 --+ See method 2, but use an average
% of the 8 nearest neighbors to any element.
% This method is NOT recommended for use.
%
%
% arguments (output):
% B - nxm array with NaNs replaced
%
%
% Example:
% [x,y] = meshgrid(0:.01:1);
% z0 = exp(x+y);
% znan = z0;
% znan(20:50,40:70) = NaN;
% znan(30:90,5:10) = NaN;
% znan(70:75,40:90) = NaN;
%
% z = inpaint_nans(znan);
%
%
% See also: griddata, interp1
%
% Author: John D'Errico
% e-mail address: woodchips@rochester.rr.com
% Release: 2
% Release date: 4/15/06
% I always need to know which elements are NaN,
% and what size the array is for any method
[n,m]=size(A);
A=A(:);
nm=n*m;
k=isnan(A(:));
% list the nodes which are known, and which will
% be interpolated
nan_list=find(k);
known_list=find(~k);
% how many nans overall
nan_count=length(nan_list);
% convert NaN indices to (r,c) form
% nan_list==find(k) are the unrolled (linear) indices
% (row,column) form
[nr,nc]=ind2sub([n,m],nan_list);
% both forms of index in one array:
% column 1 == unrolled index
% column 2 == row index
% column 3 == column index
nan_list=[nan_list,nr,nc];
% supply default method
if (nargin<2) || isempty(method)
method = 0;
elseif ~ismember(method,0:5)
error 'If supplied, method must be one of: {0,1,2,3,4,5}.'
end
% for different methods
switch method
case 0
% The same as method == 1, except only work on those
% elements which are NaN, or at least touch a NaN.
% is it 1-d or 2-d?
if (m == 1) || (n == 1)
% really a 1-d case
work_list = nan_list(:,1);
work_list = unique([work_list;work_list - 1;work_list + 1]);
work_list(work_list <= 1) = [];
work_list(work_list >= nm) = [];
nw = numel(work_list);
u = (1:nw)';
fda = sparse(repmat(u,1,3),bsxfun(@plus,work_list,-1:1), ...
repmat([1 -2 1],nw,1),nw,nm);
else
% a 2-d case
% horizontal and vertical neighbors only
talks_to = [-1 0;0 -1;1 0;0 1];
neighbors_list=identify_neighbors(n,m,nan_list,talks_to);
% list of all nodes we have identified
all_list=[nan_list;neighbors_list];
% generate sparse array with second partials on row
% variable for each element in either list, but only
% for those nodes which have a row index > 1 or < n
L = find((all_list(:,2) > 1) & (all_list(:,2) < n));
nl=length(L);
if nl>0
fda=sparse(repmat(all_list(L,1),1,3), ...
repmat(all_list(L,1),1,3)+repmat([-1 0 1],nl,1), ...
repmat([1 -2 1],nl,1),nm,nm);
else
fda=spalloc(n*m,n*m,size(all_list,1)*5);
end
% 2nd partials on column index
L = find((all_list(:,3) > 1) & (all_list(:,3) < m));
nl=length(L);
if nl>0
fda=fda+sparse(repmat(all_list(L,1),1,3), ...
repmat(all_list(L,1),1,3)+repmat([-n 0 n],nl,1), ...
repmat([1 -2 1],nl,1),nm,nm);
end
end
% eliminate knowns
rhs=-fda(:,known_list)*A(known_list);
k=find(any(fda(:,nan_list(:,1)),2));
% and solve...
B=A;
B(nan_list(:,1))=fda(k,nan_list(:,1))\rhs(k);
case 1
% least squares approach with del^2. Build system
% for every array element as an unknown, and then
% eliminate those which are knowns.
% Build sparse matrix approximating del^2 for
% every element in A.
% is it 1-d or 2-d?
if (m == 1) || (n == 1)
% a 1-d case
u = (1:(nm-2))';
fda = sparse(repmat(u,1,3),bsxfun(@plus,u,0:2), ...
repmat([1 -2 1],nm-2,1),nm-2,nm);
else
% a 2-d case
% Compute finite difference for second partials
% on row variable first
[i,j]=ndgrid(2:(n-1),1:m);
ind=i(:)+(j(:)-1)*n;
np=(n-2)*m;
fda=sparse(repmat(ind,1,3),[ind-1,ind,ind+1], ...
repmat([1 -2 1],np,1),n*m,n*m);
% now second partials on column variable
[i,j]=ndgrid(1:n,2:(m-1));
ind=i(:)+(j(:)-1)*n;
np=n*(m-2);
fda=fda+sparse(repmat(ind,1,3),[ind-n,ind,ind+n], ...
repmat([1 -2 1],np,1),nm,nm);
end
% eliminate knowns
rhs=-fda(:,known_list)*A(known_list);
k=find(any(fda(:,nan_list),2));
% and solve...
B=A;
B(nan_list(:,1))=fda(k,nan_list(:,1))\rhs(k);
case 2
% Direct solve for del^2 BVP across holes
% generate sparse array with second partials on row
% variable for each nan element, only for those nodes
% which have a row index > 1 or < n
% is it 1-d or 2-d?
if (m == 1) || (n == 1)
% really just a 1-d case
error('Method 2 has problems for vector input. Please use another method.')
else
% a 2-d case
L = find((nan_list(:,2) > 1) & (nan_list(:,2) < n));
nl=length(L);
if nl>0
fda=sparse(repmat(nan_list(L,1),1,3), ...
repmat(nan_list(L,1),1,3)+repmat([-1 0 1],nl,1), ...
repmat([1 -2 1],nl,1),n*m,n*m);
else
fda=spalloc(n*m,n*m,size(nan_list,1)*5);
end
% 2nd partials on column index
L = find((nan_list(:,3) > 1) & (nan_list(:,3) < m));
nl=length(L);
if nl>0
fda=fda+sparse(repmat(nan_list(L,1),1,3), ...
repmat(nan_list(L,1),1,3)+repmat([-n 0 n],nl,1), ...
repmat([1 -2 1],nl,1),n*m,n*m);
end
% fix boundary conditions at extreme corners
% of the array in case there were nans there
if ismember(1,nan_list(:,1))
fda(1,[1 2 n+1])=[-2 1 1];
end
if ismember(n,nan_list(:,1))
fda(n,[n, n-1,n+n])=[-2 1 1];
end
if ismember(nm-n+1,nan_list(:,1))
fda(nm-n+1,[nm-n+1,nm-n+2,nm-n])=[-2 1 1];
end
if ismember(nm,nan_list(:,1))
fda(nm,[nm,nm-1,nm-n])=[-2 1 1];
end
% eliminate knowns
rhs=-fda(:,known_list)*A(known_list);
% and solve...
B=A;
k=nan_list(:,1);
B(k)=fda(k,k)\rhs(k);
end
case 3
% The same as method == 0, except uses del^4 as the
% interpolating operator.
% del^4 template of neighbors
talks_to = [-2 0;-1 -1;-1 0;-1 1;0 -2;0 -1; ...
0 1;0 2;1 -1;1 0;1 1;2 0];
neighbors_list=identify_neighbors(n,m,nan_list,talks_to);
% list of all nodes we have identified
all_list=[nan_list;neighbors_list];
% generate sparse array with del^4, but only
% for those nodes which have a row & column index
% >= 3 or <= n-2
L = find( (all_list(:,2) >= 3) & ...
(all_list(:,2) <= (n-2)) & ...
(all_list(:,3) >= 3) & ...
(all_list(:,3) <= (m-2)));
nl=length(L);
if nl>0
% do the entire template at once
fda=sparse(repmat(all_list(L,1),1,13), ...
repmat(all_list(L,1),1,13) + ...
repmat([-2*n,-n-1,-n,-n+1,-2,-1,0,1,2,n-1,n,n+1,2*n],nl,1), ...
repmat([1 2 -8 2 1 -8 20 -8 1 2 -8 2 1],nl,1),nm,nm);
else
fda=spalloc(n*m,n*m,size(all_list,1)*5);
end
% on the boundaries, reduce the order around the edges
L = find((((all_list(:,2) == 2) | ...
(all_list(:,2) == (n-1))) & ...
(all_list(:,3) >= 2) & ...
(all_list(:,3) <= (m-1))) | ...
(((all_list(:,3) == 2) | ...
(all_list(:,3) == (m-1))) & ...
(all_list(:,2) >= 2) & ...
(all_list(:,2) <= (n-1))));
nl=length(L);
if nl>0
fda=fda+sparse(repmat(all_list(L,1),1,5), ...
repmat(all_list(L,1),1,5) + ...
repmat([-n,-1,0,+1,n],nl,1), ...
repmat([1 1 -4 1 1],nl,1),nm,nm);
end
L = find( ((all_list(:,2) == 1) | ...
(all_list(:,2) == n)) & ...
(all_list(:,3) >= 2) & ...
(all_list(:,3) <= (m-1)));
nl=length(L);
if nl>0
fda=fda+sparse(repmat(all_list(L,1),1,3), ...
repmat(all_list(L,1),1,3) + ...
repmat([-n,0,n],nl,1), ...
repmat([1 -2 1],nl,1),nm,nm);
end
L = find( ((all_list(:,3) == 1) | ...
(all_list(:,3) == m)) & ...
(all_list(:,2) >= 2) & ...
(all_list(:,2) <= (n-1)));
nl=length(L);
if nl>0
fda=fda+sparse(repmat(all_list(L,1),1,3), ...
repmat(all_list(L,1),1,3) + ...
repmat([-1,0,1],nl,1), ...
repmat([1 -2 1],nl,1),nm,nm);
end
% eliminate knowns
rhs=-fda(:,known_list)*A(known_list);
k=find(any(fda(:,nan_list(:,1)),2));
% and solve...
B=A;
B(nan_list(:,1))=fda(k,nan_list(:,1))\rhs(k);
case 4
% Spring analogy
% interpolating operator.
% list of all springs between a node and a horizontal
% or vertical neighbor
hv_list=[-1 -1 0;1 1 0;-n 0 -1;n 0 1];
hv_springs=[];
for i=1:4
hvs=nan_list+repmat(hv_list(i,:),nan_count,1);
k=(hvs(:,2)>=1) & (hvs(:,2)<=n) & (hvs(:,3)>=1) & (hvs(:,3)<=m);
hv_springs=[hv_springs;[nan_list(k,1),hvs(k,1)]];
end
% delete replicate springs
hv_springs=unique(sort(hv_springs,2),'rows');
% build sparse matrix of connections, springs
% connecting diagonal neighbors are weaker than
% the horizontal and vertical springs
nhv=size(hv_springs,1);
springs=sparse(repmat((1:nhv)',1,2),hv_springs, ...
repmat([1 -1],nhv,1),nhv,nm);
% eliminate knowns
rhs=-springs(:,known_list)*A(known_list);
% and solve...
B=A;
B(nan_list(:,1))=springs(:,nan_list(:,1))\rhs;
case 5
% Average of 8 nearest neighbors
% generate sparse array to average 8 nearest neighbors
% for each nan element, be careful around edges
fda=spalloc(n*m,n*m,size(nan_list,1)*9);
% -1,-1
L = find((nan_list(:,2) > 1) & (nan_list(:,3) > 1));
nl=length(L);
if nl>0
fda=fda+sparse(repmat(nan_list(L,1),1,2), ...
repmat(nan_list(L,1),1,2)+repmat([-n-1, 0],nl,1), ...
repmat([1 -1],nl,1),n*m,n*m);
end
% 0,-1
L = find(nan_list(:,3) > 1);
nl=length(L);
if nl>0
fda=fda+sparse(repmat(nan_list(L,1),1,2), ...
repmat(nan_list(L,1),1,2)+repmat([-n, 0],nl,1), ...
repmat([1 -1],nl,1),n*m,n*m);
end
% +1,-1
L = find((nan_list(:,2) < n) & (nan_list(:,3) > 1));
nl=length(L);
if nl>0
fda=fda+sparse(repmat(nan_list(L,1),1,2), ...
repmat(nan_list(L,1),1,2)+repmat([-n+1, 0],nl,1), ...
repmat([1 -1],nl,1),n*m,n*m);
end
% -1,0
L = find(nan_list(:,2) > 1);
nl=length(L);
if nl>0
fda=fda+sparse(repmat(nan_list(L,1),1,2), ...
repmat(nan_list(L,1),1,2)+repmat([-1, 0],nl,1), ...
repmat([1 -1],nl,1),n*m,n*m);
end
% +1,0
L = find(nan_list(:,2) < n);
nl=length(L);
if nl>0
fda=fda+sparse(repmat(nan_list(L,1),1,2), ...
repmat(nan_list(L,1),1,2)+repmat([1, 0],nl,1), ...
repmat([1 -1],nl,1),n*m,n*m);
end
% -1,+1
L = find((nan_list(:,2) > 1) & (nan_list(:,3) < m));
nl=length(L);
if nl>0
fda=fda+sparse(repmat(nan_list(L,1),1,2), ...
repmat(nan_list(L,1),1,2)+repmat([n-1, 0],nl,1), ...
repmat([1 -1],nl,1),n*m,n*m);
end
% 0,+1
L = find(nan_list(:,3) < m);
nl=length(L);
if nl>0
fda=fda+sparse(repmat(nan_list(L,1),1,2), ...
repmat(nan_list(L,1),1,2)+repmat([n, 0],nl,1), ...
repmat([1 -1],nl,1),n*m,n*m);
end
% +1,+1
L = find((nan_list(:,2) < n) & (nan_list(:,3) < m));
nl=length(L);
if nl>0
fda=fda+sparse(repmat(nan_list(L,1),1,2), ...
repmat(nan_list(L,1),1,2)+repmat([n+1, 0],nl,1), ...
repmat([1 -1],nl,1),n*m,n*m);
end
% eliminate knowns
rhs=-fda(:,known_list)*A(known_list);
% and solve...
B=A;
k=nan_list(:,1);
B(k)=fda(k,k)\rhs(k);
end
% all done, make sure that B is the same shape as
% A was when we came in.
B=reshape(B,n,m);
% ====================================================
% end of main function
% ====================================================
% ====================================================
% begin subfunctions
% ====================================================
function neighbors_list=identify_neighbors(n,m,nan_list,talks_to)
% identify_neighbors: identifies all the neighbors of
% those nodes in nan_list, not including the nans
% themselves
%
% arguments (input):
% n,m - scalar - [n,m]=size(A), where A is the
% array to be interpolated
% nan_list - array - list of every nan element in A
% nan_list(i,1) == linear index of i'th nan element
% nan_list(i,2) == row index of i'th nan element
% nan_list(i,3) == column index of i'th nan element
% talks_to - px2 array - defines which nodes communicate
% with each other, i.e., which nodes are neighbors.
%
% talks_to(i,1) - defines the offset in the row
% dimension of a neighbor
% talks_to(i,2) - defines the offset in the column
% dimension of a neighbor
%
% For example, talks_to = [-1 0;0 -1;1 0;0 1]
% means that each node talks only to its immediate
% neighbors horizontally and vertically.
%
% arguments(output):
% neighbors_list - array - list of all neighbors of
% all the nodes in nan_list
if ~isempty(nan_list)
% use the definition of a neighbor in talks_to
nan_count=size(nan_list,1);
talk_count=size(talks_to,1);
nn=zeros(nan_count*talk_count,2);
j=[1,nan_count];
for i=1:talk_count
nn(j(1):j(2),:)=nan_list(:,2:3) + ...
repmat(talks_to(i,:),nan_count,1);
j=j+nan_count;
end
% drop those nodes which fall outside the bounds of the
% original array
L = (nn(:,1)<1)|(nn(:,1)>n)|(nn(:,2)<1)|(nn(:,2)>m);
nn(L,:)=[];
% form the same format 3 column array as nan_list
neighbors_list=[sub2ind([n,m],nn(:,1),nn(:,2)),nn];
% delete replicates in the neighbors list
neighbors_list=unique(neighbors_list,'rows');
% and delete those which are also in the list of NaNs.
neighbors_list=setdiff(neighbors_list,nan_list,'rows');
else
neighbors_list=[];
end
--------------------------------------------------------------------------------