The shaperead
function provides you with a
powerful method, called a selector, to select only the data fields
and items you want to import from shapefiles.
A selector is a cell array with two or more elements. The first element is a handle to
a predicate function (a function with a single output argument of type
logical
). Each remaining element is a character vector indicating
the name of an attribute.
For a given feature, shaperead
supplies the values of the
attributes listed to the predicate function to help determine whether to include the
feature in its output. The feature is excluded if the predicate returns
false
. The converse is not necessarily true: a feature for which
the predicate returns true
may be excluded for other reasons when the
selector is used in combination with the bounding box or record number options.
The following examples are arranged in order of increasing sophistication. Although
they use MATLAB® function handles, anonymous functions, and nested functions, you need not
be familiar with these features in order to master the use of selectors for
shaperead
.
Define the predicate function in a separate file.
(Prior to Release 14, this was the only option available.) Create a file
named roadfilter.m
, with the following contents:
function result = roadfilter(roadclass,roadlength) mininumClass = 4; minimumLength = 200; result = (roadclass >= mininumClass) && ... (roadlength >= minimumLength); end
You can then call shaperead
like
this:
roadselector = {@roadfilter, 'CLASS', 'LENGTH'} roadselector = @roadfilter 'CLASS' 'LENGTH' s = shaperead('concord_roads', 'Selector', roadselector) s = 115x1 struct array with fields: Geometry BoundingBox X Y STREETNAME RT_NUMBER CLASS ADMIN_TYPE LENGTH
or, in a slightly more compact fashion, like this:
s = shaperead('concord_roads',... 'Selector', {@roadfilter, 'CLASS', 'LENGTH'}) s = 115x1 struct array with fields: Geometry BoundingBox X Y STREETNAME RT_NUMBER CLASS ADMIN_TYPE LENGTH
Prior to Version 7 of the Mapping Toolbox™ software, putting the selector in a file or local function of its own was the only way to work with a selector.
Note that if the call to shaperead
took place within a
function, then roadfilter
could be defined in a local
function thereof rather than in a file of its own.
As a simple variation on the previous example, you could assign a function handle,
roadfilterfcn
, and use it in the selector:
roadfilterfcn = @roadfilter s = shaperead('concord_roads',... 'Selector', {roadfilterfcn, 'CLASS', 'LENGTH'}) roadfilterfcn = @roadfilter s = 115x1 struct array with fields: Geometry BoundingBox X Y STREETNAME RT_NUMBER CLASS ADMIN_TYPE LENGTH
Having to define predicate functions in files of their own, or even as local functions, may sometimes be awkward. Anonymous functions allow the predicate function to be defined right where it is needed. For example:
roadfilterfcn = ... @(roadclass, roadlength) (roadclass >= 4) && ... (roadlength >= 200) roadfilterfcn = @(roadclass, roadlength) (roadclass >= 4) ... && (roadlength >= 200) s = shaperead('concord_roads','Selector', ... {roadfilterfcn, 'CLASS', 'LENGTH'}) s = 115x1 struct array with fields: Geometry BoundingBox X Y STREETNAME RT_NUMBER CLASS ADMIN_TYPE LENGTH
There is actually no need to introduce a function handle variable when defining the predicate as an anonymous function. Instead, you can place the whole expression within the selector cell array itself, resulting in somewhat more compact code. This pattern is used in many examples throughout the Mapping Toolbox documentation and function help.
s = shaperead('concord_roads', 'Selector', ... {@(roadclass, roadlength)... (roadclass >= 4) && (roadlength >= 200),... 'CLASS', 'LENGTH'}) s = 115x1 struct array with fields: Geometry BoundingBox X Y STREETNAME RT_NUMBER CLASS ADMIN_TYPE LENGTH
In the previous patterns, the predicate involves two hard-coded parameters (called
minimumClass
and minimumLength
in
roadfilter.m
), as well as the roadclass
and roadlength
input variables. If you use any of these patterns
in a program, you need to decide on minimum cut-off values for
roadclass
and roadlength
at the time you
write the program. But suppose that you wanted to wait and decide on parameters like
minimumClass
and minimumLength
at run
time?
Fortunately, nested functions provide the additional power that you need to do
this; they allow you to utilize workspace variables in as parameters, rather than
requiring that the parameters be hard-coded as constants within the predicate
function. In the following example, the workspace variables
minimumClass
and minimumLength
could have
been assigned through a variety of computations whose results were unknown until
run-time, yet their values can be made available within the predicate as long as it
is defined as a nested function. In this example the nested function is wrapped in a
file called constructroadselector.m
, which returns a complete
selector: a handle to the predicate (named nestedroadfilter
) and
the two attribute names:
function roadselector = ... constructroadselector(minimumClass, minimumLength) roadselector = {@nestedroadfilter, 'CLASS', 'LENGTH'}; function result = nestedroadfilter(roadclass, roadlength) result = (roadclass >= minimumClass) && ... (roadlength >= minimumLength); end end
The following four lines show how to use constructroadselector
:
minimumClass = 4; % Could be run-time dependent minimumLength = 200; % Could be run-time dependent roadselector = constructroadselector(... minimumClass, minimumLength); s = shaperead('concord_roads', 'Selector', roadselector) s = 115x1 struct array with fields: Geometry BoundingBox X Y STREETNAME RT_NUMBER CLASS ADMIN_TYPE LENGTH