Copyright | (c) Colin Woodbury 2018 - 2020 |
---|---|
License | BSD3 |
Maintainer | Colin Woodbury <colin@fosskers.ca> |
Safe Haskell | None |
Language | Haskell2010 |
This library is an implementation of Map Algebra as described in the book
GIS and Cartographic Modeling (GaCM) by Dana Tomlin. The fundamental
primitive is the Raster
, a rectangular grid of data that usually describes
some area on the earth. A Raster
need not contain numerical data, however,
and need not just represent satellite imagery. It is essentially a matrix,
which of course forms a Functor
, and thus is available for all the
operations we would expect to run on any Functor. /GIS and Cartographic
Modeling/ doesn't lean on this fact, and so describes many seemingly custom
operations which to Haskell are just applications of fmap
or zipWith
with
pure functions.
Here are the main classes of operations ascribed to Map Algebra and their corresponding approach in Haskell:
- Single-Raster Local Operations ->
fmap
with pure functions - Multi-Raster Local Operations ->
foldl
withzipWith
and pure functions - Focal Operations ->
massiv
-based smartStencil
operations - Zonal Operations -> Not yet implemented
Whether it is meaningful to perform operations between two given Raster
s
(i.e. whether the Rasters properly overlap on the earth) is not handled in
this library and is left to the application.
The "colour ramp" generation functions (like greenRed
) gratefully borrow
colour sets from Gretchen N. Peterson's book Cartographer's Toolkit.
A Word on Massiv: Fused, Parallel Arrays
Thanks to the underlying Array
library
massiv, most operations over
and between Rasters are fused, meaning that no extra memory is allocated in
between each step of a composite operation.
Take the Enhanced Vegetation Index calculation:
evi :: Raster D p r c Double -> Raster D p r c Double -> Raster D p r c Double -> Raster D p r c Double evi nir red blue = 2.5 * (numer / denom) where numer = nir - red denom = nir + (6 * red) - (7.5 * blue) + 1
8 binary operators are used here, but none allocate new memory. It's only
when some lazy
Raster is made strict
that calculations occur and memory
is allocated.
Provided your machine has more than 1 CPU, Rasters read by functions like
fromRGBA
will automatically be in Par
allel mode. This means that forcing
calculations with strict
will cause evaluation to be done with every CPU
your machine has. The effect of this is quite potent for Focal Operations,
which yield special, cache-friendly windowed (DW
) Rasters.
Familiarity with Massiv will help in using this library. A guide can be found here.
Compilation Options for Best Performance
When using this library, always compile your project with -threaded
and
-with-rtsopts=-N
. These will ensure your executables will automatically use
all the available CPU cores.
As always, -O2
is your friend. The {-# INLINE ... #-}
pragma is also
very likely to improve the performance of code that uses functions from this
library. Make sure to benchmark proactively.
For particularly mathy operations like fmean
, compiling with -fllvm
grants about a 2x speedup.
Synopsis
- newtype Raster u p (r :: Nat) (c :: Nat) a = Raster {}
- lazy :: Source u Ix2 a => Raster u p r c a -> Raster D p r c a
- strict :: (Load v Ix2 a, Mutable u Ix2 a) => u -> Raster v p r c a -> Raster u p r c a
- data RGBARaster p r c a = RGBARaster {}
- constant :: (KnownNat r, KnownNat c, Construct u Ix2 a) => u -> Comp -> a -> Raster u p r c a
- fromFunction :: forall u p r c a. (KnownNat r, KnownNat c, Construct u Ix2 a) => u -> Comp -> (Ix2 -> a) -> Raster u p r c a
- fromVector :: forall v p r c a. (KnownNat r, KnownNat c, Vector v a, Mutable (ARepr v) Ix2 a, Typeable v) => Comp -> v a -> Either String (Raster (ARepr v) p r c a)
- fromRGBA :: forall p r c a. (Elevator a, KnownNat r, KnownNat c) => FilePath -> IO (Either String (RGBARaster p r c a))
- fromGray :: forall p r c a. (Elevator a, KnownNat r, KnownNat c) => FilePath -> IO (Either String (Raster S p r c a))
- grayscale :: Functor (Raster u p r c) => Raster u p r c a -> Raster u p r c (Pixel Y a)
- newtype Histogram = Histogram {
- _histogram :: Vector Word
- histogram :: Source u Ix2 Word8 => Raster u p r c Word8 -> Histogram
- breaks :: Histogram -> [Word8]
- invisible :: Pixel RGBA Word8
- greenRed :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- spectrum :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- blueGreen :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- purpleYellow :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- brownBlue :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- grayBrown :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- greenPurple :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- brownYellow :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- purpleGreen :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- purpleRed :: Ord k => [k] -> Map k (Pixel RGBA Word8)
- writeImage :: (Source r Ix2 (Pixel cs e), ColorSpace cs e) => FilePath -> Image r cs e -> IO ()
- writeImageAuto :: (Source r Ix2 (Pixel cs e), ColorSpace cs e, ToYA cs e, ToRGBA cs e, ToYCbCr cs e, ToCMYK cs e) => FilePath -> Image r cs e -> IO ()
- displayImage :: Writable (Auto TIF) (Image r cs e) => Image r cs e -> IO ()
- png :: (Source u Ix2 (Pixel cs a), ColorSpace cs a) => Raster u p r c (Pixel cs a) -> ByteString
- class Projection p where
- reproject :: (Projection p, Projection r) => Point p -> Point r
- data Sphere
- data LatLng
- data WebMercator
- data Point p = Point {}
- zipWith :: (Source u Ix2 a, Source u Ix2 b) => (a -> b -> d) -> Raster u p r c a -> Raster u p r c b -> Raster D p r c d
- classify :: (Ord a, Functor f) => b -> Map a b -> f a -> f b
- lmax :: (Ord a, Source u Ix2 a) => Raster u p r c a -> Raster u p r c a -> Raster D p r c a
- lmin :: (Ord a, Source u Ix2 a) => Raster u p r c a -> Raster u p r c a -> Raster D p r c a
- lmean :: (Real a, Fractional b, KnownNat r, KnownNat c) => NonEmpty (Raster D p r c a) -> Raster D p r c b
- lvariety :: (KnownNat r, KnownNat c, Eq a) => NonEmpty (Raster D p r c a) -> Raster D p r c Word
- lmajority :: (KnownNat r, KnownNat c, Ord a) => NonEmpty (Raster D p r c a) -> Raster D p r c a
- lminority :: (KnownNat r, KnownNat c, Ord a) => NonEmpty (Raster D p r c a) -> Raster D p r c a
- lvariance :: forall p a r c. (Real a, KnownNat r, KnownNat c) => NonEmpty (Raster D p r c a) -> Maybe (Raster D p r c Double)
- fsum :: (Num a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a
- fproduct :: (Num a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a
- fmonoid :: (Monoid a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a
- fmean :: (Fractional a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a
- fmax :: (Ord a, Bounded a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a
- fmin :: (Ord a, Bounded a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a
- fmajority :: (Ord a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a
- fminority :: (Ord a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a
- fvariety :: (Ord a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Word
- fpercentage :: (Eq a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Double
- fpercentile :: (Ord a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Double
- newtype Line = Line {}
- flinkage :: (Default a, Eq a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Line
- flength :: Functor (Raster u p r c) => Raster u p r c Line -> Raster u p r c Double
- data Corners = Corners {
- _topLeft :: !Surround
- _bottomLeft :: !Surround
- _bottomRight :: !Surround
- _topRight :: !Surround
- data Surround
- = Complete
- | OneSide
- | Open
- | RightAngle
- | OutFlow
- fpartition :: (Default a, Eq a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Corners
- fshape :: (Default a, Eq a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Corners
- ffrontage :: Functor (Raster u p r c) => Raster u p r c Corners -> Raster u p r c Double
- farea :: Functor (Raster u p r c) => Raster u p r c Corners -> Raster u p r c Double
- newtype Drain = Drain {}
- data Direction
- direction :: Direction -> Drain -> Bool
- directions :: Drain -> Set Direction
- drainage :: Set Direction -> Drain
- fvolume :: (Fractional a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a
- fgradient :: Manifest u Ix2 Double => Raster u p r c Double -> Raster DW p r c Double
- faspect :: Manifest u Ix2 Double => Raster u p r c Double -> Raster DW p r c (Maybe Double)
- faspect' :: Manifest u Ix2 Double => Raster u p r c Double -> Raster DW p r c Double
- fdownstream :: Manifest u Ix2 Double => Raster u p r c Double -> Raster DW p r c Drain
- fupstream :: Manifest u Ix2 Drain => Raster u p r c Drain -> Raster DW p r c Drain
- leftPseudo :: Matrix Double
- tau :: Double
- data D = D
- data DW = DW
- data S = S
- data P = P
- data U = U
- data B = B
- data N = N
- data Ix2 where
- data Comp where
- data family Pixel cs e :: Type
- data RGBA
- data Y
Types
Rasters
newtype Raster u p (r :: Nat) (c :: Nat) a Source #
A rectangular grid of data representing some area on the earth.
u
: What is the underlying representation of this Raster? (seemassiv
)p
: WhatProjection
is this Raster in?r
: How many rows does this Raster have?c
: How many columns does this Raster have?a
: What data type is held in this Raster?
By having explicit p, r, and c, we make impossible any operation between two Rasters of differing size or projection. Conceptually, we consider Rasters of different size and projection to be entirely different types. Example:
-- | A lazy 256x256 Raster with the value 5 at every index. Uses DataKinds -- and "type literals" to achieve the same-size guarantee. myRaster :: Raster D WebMercator 256 256 Int myRaster = constant D Par 5 >>> length myRaster 65536
Instances
Functor (Raster DI p r c) Source # | |
Functor (Raster D p r c) Source # | |
Functor (Raster DW p r c) Source # | |
(KnownNat r, KnownNat c) => Applicative (Raster D p r c) Source # | |
Defined in Geography.MapAlgebra pure :: a -> Raster D p r c a # (<*>) :: Raster D p r c (a -> b) -> Raster D p r c a -> Raster D p r c b # liftA2 :: (a -> b -> c0) -> Raster D p r c a -> Raster D p r c b -> Raster D p r c c0 # (*>) :: Raster D p r c a -> Raster D p r c b -> Raster D p r c b # (<*) :: Raster D p r c a -> Raster D p r c b -> Raster D p r c a # | |
Foldable (Raster D p r c) Source # |
|
Defined in Geography.MapAlgebra fold :: Monoid m => Raster D p r c m -> m # foldMap :: Monoid m => (a -> m) -> Raster D p r c a -> m # foldr :: (a -> b -> b) -> b -> Raster D p r c a -> b # foldr' :: (a -> b -> b) -> b -> Raster D p r c a -> b # foldl :: (b -> a -> b) -> b -> Raster D p r c a -> b # foldl' :: (b -> a -> b) -> b -> Raster D p r c a -> b # foldr1 :: (a -> a -> a) -> Raster D p r c a -> a # foldl1 :: (a -> a -> a) -> Raster D p r c a -> a # toList :: Raster D p r c a -> [a] # null :: Raster D p r c a -> Bool # length :: Raster D p r c a -> Int # elem :: Eq a => a -> Raster D p r c a -> Bool # maximum :: Ord a => Raster D p r c a -> a # minimum :: Ord a => Raster D p r c a -> a # | |
Eq a => Eq (Raster D p r c a) Source # | |
Eq a => Eq (Raster B p r c a) Source # | |
(Eq a, NFData a) => Eq (Raster N p r c a) Source # | |
(Eq a, Prim a) => Eq (Raster P p r c a) Source # | |
(Eq a, Storable a) => Eq (Raster S p r c a) Source # | |
(Eq a, Unbox a) => Eq (Raster U p r c a) Source # | |
(Fractional a, KnownNat r, KnownNat c) => Fractional (Raster D p r c a) Source # | |
(Num a, KnownNat r, KnownNat c) => Num (Raster D p r c a) Source # | |
Defined in Geography.MapAlgebra (+) :: Raster D p r c a -> Raster D p r c a -> Raster D p r c a # (-) :: Raster D p r c a -> Raster D p r c a -> Raster D p r c a # (*) :: Raster D p r c a -> Raster D p r c a -> Raster D p r c a # negate :: Raster D p r c a -> Raster D p r c a # abs :: Raster D p r c a -> Raster D p r c a # signum :: Raster D p r c a -> Raster D p r c a # fromInteger :: Integer -> Raster D p r c a # | |
(Show a, Load (R u) Ix2 a, Extract u Ix2 a) => Show (Raster u p r c a) Source # | Warning: This will evaluate (at most) the 10x10 top-left corner of your
|
Semigroup a => Semigroup (Raster D p r c a) Source # | |
(Monoid a, KnownNat r, KnownNat c) => Monoid (Raster D p r c a) Source # | |
strict :: (Load v Ix2 a, Mutable u Ix2 a) => u -> Raster v p r c a -> Raster u p r c a Source #
Evaluate some lazy (D
, DW
, or DI
) Raster
to some explicit
Manifest
type (i.e. to a real memory-backed Array). Will follow the
Comp
utation strategy of the underlying massiv
Array
.
Note: If using the Par
computation strategy, make sure you're compiling
with -with-rtsopts=-N
to automatically use all available CPU cores at
runtime. Otherwise your "parallel" operations will only execute on one core.
data RGBARaster p r c a Source #
An RGBA image whose colour bands are distinct.
Creation
constant :: (KnownNat r, KnownNat c, Construct u Ix2 a) => u -> Comp -> a -> Raster u p r c a Source #
Create a Raster
of any size which has the same value everywhere.
fromFunction :: forall u p r c a. (KnownNat r, KnownNat c, Construct u Ix2 a) => u -> Comp -> (Ix2 -> a) -> Raster u p r c a Source #
\(\mathcal{O}(1)\). Create a Raster
from a function of its row and column
number respectively.
fromVector :: forall v p r c a. (KnownNat r, KnownNat c, Vector v a, Mutable (ARepr v) Ix2 a, Typeable v) => Comp -> v a -> Either String (Raster (ARepr v) p r c a) Source #
fromRGBA :: forall p r c a. (Elevator a, KnownNat r, KnownNat c) => FilePath -> IO (Either String (RGBARaster p r c a)) Source #
fromGray :: forall p r c a. (Elevator a, KnownNat r, KnownNat c) => FilePath -> IO (Either String (Raster S p r c a)) Source #
Read a grayscale image. If the source file has more than one colour band, they'll be combined automatically.
Colouring
To colour a Raster
:
- Fully evaluate it with
strict
S
. - Use
histogram
to analyse the spread of its values. Currently onlyWord8
is supported. - Use
breaks
on theHistogram
to generate a list of "break points". - Pass the break points to a function like
greenRed
to generate a "colour ramp" (aMap
). - Use this ramp with
classify
to colour yourRaster
in \(\mathcal{O}(n\log(n))\).invisible
can be used as the default colour for values that fall outside the range of the Map.
colourIt :: Raster D p r c Word8 -> Raster S p r c (Pixel RGBA Word8) colourIt (strict S -> r) = strict S . classify invisible cm $ lazy r where cm = blueGreen . breaks $ histogram r
If you aren't interested in colour but still want to render your Raster
,
consider grayscale
. Coloured Raster
s can be unwrapped with _array
and
then output with functions like writeImage
.
grayscale :: Functor (Raster u p r c) => Raster u p r c a -> Raster u p r c (Pixel Y a) Source #
Convert a Raster
into grayscale pixels, suitable for easy output with
functions like writeImage
.
greenRed :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 32 of Cartographer's Toolkit.
spectrum :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 33 of Cartographer's Toolkit.
blueGreen :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 34 of Cartographer's Toolkit.
purpleYellow :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 35 of Cartographer's Toolkit.
brownBlue :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 36 of Cartographer's Toolkit.
grayBrown :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 37 of Cartographer's Toolkit.
greenPurple :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 38 of Cartographer's Toolkit.
brownYellow :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 39 of Cartographer's Toolkit.
purpleGreen :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 40 of Cartographer's Toolkit.
purpleRed :: Ord k => [k] -> Map k (Pixel RGBA Word8) Source #
From page 41 of Cartographer's Toolkit.
Output and Display
For coloured output, first use classify
over your Raster
to produce a
Raster u p r c (Pixel RGBA Word8)
. Then unwrap it with _array
and output
with something like writeImage
.
For quick debugging, you can visualize a Raster
with displayImage
:
raster :: Raster D p 512 512 Word8 >>> displayImage . _array . strict S . grayscale
writeImage :: (Source r Ix2 (Pixel cs e), ColorSpace cs e) => FilePath -> Image r cs e -> IO () #
This function will guess an output file format from the file extension and will write to file
any image with the colorspace that is supported by that format. Precision of the image might be
adjusted using Elevator
if precision of the source array is not supported by the image file
format. For instance an (
being saved as Image
r RGBA
Double
)PNG
file would be written as
(
, thus using highest supported precision Image
r RGBA
Word16
)Word16
for that
format. If automatic colors space is also desired, writeImageAuto
can be used instead.
Can throw ConvertError
, EncodeError
and other usual IO errors.
writeImageAuto :: (Source r Ix2 (Pixel cs e), ColorSpace cs e, ToYA cs e, ToRGBA cs e, ToYCbCr cs e, ToCMYK cs e) => FilePath -> Image r cs e -> IO () #
Write an image to file while performing all necessary precisiona and color space conversions.
displayImage :: Writable (Auto TIF) (Image r cs e) => Image r cs e -> IO () #
Makes a call to an external viewer that is set as a default image viewer by the OS. This is a non-blocking function call, so it might take some time before an image will appear.
png :: (Source u Ix2 (Pixel cs a), ColorSpace cs a) => Raster u p r c (Pixel cs a) -> ByteString Source #
Render a PNG-encoded ByteString
from a coloured Raster
. Useful for
returning a Raster
from a webserver endpoint.
Projections
class Projection p where Source #
The Earth is not a sphere. Various schemes have been invented throughout
history that provide Point
coordinates for locations on the earth, although
all are approximations and come with trade-offs. We call these Projections,
since they are a mapping of Sphere
coordinates to some other approximation.
The Projection used most commonly for mapping on the internet is called
WebMercator
.
A Projection is also known as a Coordinate Reference System (CRS).
Use reproject
to convert Point
s between various Projections.
Note: Full support for Projections is still pending.
reproject :: (Projection p, Projection r) => Point p -> Point r Source #
Reproject a Point
from one Projection
to another.
A perfect geometric sphere. The earth isn't actually shaped this way, but
it's a convenient middle-ground for converting between various Projection
s.
data WebMercator Source #
The most commonly used Projection
for mapping in internet applications.
A location on the Earth in some Projection
.
Map Algebra
Local Operations
Operations between Raster
s. All operations are element-wise:
1 1 + 2 2 == 3 3 1 1 2 2 3 3 2 2 * 3 3 == 6 6 2 2 3 3 6 6
If an operation you need isn't available here, use our zipWith
:
zipWith :: (a -> b -> d) -> Raster u p r c a -> Raster u p r c b -> Raster D p r c d -- Your operation. foo :: Int -> Int -> Int bar :: Raster u p r c Int -> Raster u p r c Int -> Raster D p r c Int bar a b = zipWith foo a b
zipWith :: (Source u Ix2 a, Source u Ix2 b) => (a -> b -> d) -> Raster u p r c a -> Raster u p r c b -> Raster D p r c d Source #
Combine two Raster
s, element-wise, with a binary operator.
Unary
If you want to do simple unary Raster -> Raster
operations (called
LocalCalculation in GaCM), Raster
is a Functor
so you can use fmap
as normal:
myRaster :: Raster D p r c Int -- Add 17 to every value in the Raster. fmap (+ 17) myRaster
Binary
You can safely use these with the foldl
family on any Foldable
of
Raster
s. You would likely want foldl1'
which is provided by both List
and Vector.
Keep in mind that Raster
D
has a Num
instance, so you can use all the
normal math operators with them as well.
lmax :: (Ord a, Source u Ix2 a) => Raster u p r c a -> Raster u p r c a -> Raster D p r c a Source #
Finds the maximum value at each index between two Raster
s.
lmin :: (Ord a, Source u Ix2 a) => Raster u p r c a -> Raster u p r c a -> Raster D p r c a Source #
Finds the minimum value at each index between two Raster
s.
Other
There is no binary form of these functions that exists without
producing numerical error, so you can't use the foldl
family with these.
Consider the average operation, where the following is not true:
\[
\forall abc \in \mathbb{R}. \frac{\frac{a + b}{2} + c}{2} = \frac{a + b + c}{3}
\]
lmean :: (Real a, Fractional b, KnownNat r, KnownNat c) => NonEmpty (Raster D p r c a) -> Raster D p r c b Source #
Averages the values per-index of all Raster
s in a collection.
lvariety :: (KnownNat r, KnownNat c, Eq a) => NonEmpty (Raster D p r c a) -> Raster D p r c Word Source #
The count of unique values at each shared index.
lmajority :: (KnownNat r, KnownNat c, Ord a) => NonEmpty (Raster D p r c a) -> Raster D p r c a Source #
The most frequently appearing value at each shared index.
lminority :: (KnownNat r, KnownNat c, Ord a) => NonEmpty (Raster D p r c a) -> Raster D p r c a Source #
The least frequently appearing value at each shared index.
lvariance :: forall p a r c. (Real a, KnownNat r, KnownNat c) => NonEmpty (Raster D p r c a) -> Maybe (Raster D p r c Double) Source #
A measure of how spread out a dataset is. This calculation will fail with
Nothing
if a length 1 list is given.
Focal Operations
Operations on one Raster
, given some polygonal neighbourhood. Your
Raster
must be of a Manifest
type (i.e. backed by real memory) before
you attempt any focal operations. Without this constraint, wayward users
run the risk of setting up operations that would perform terribly. Use
strict
to easily convert a lazy Raster
to a memory-backed one.
myRaster :: Raster D p r c Float averaged :: Raster DW p r c Float averaged = fmean $ strict P myRaster
fproduct :: (Num a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a Source #
Focal Product.
fmonoid :: (Monoid a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a Source #
Focal Monoid - combine all elements of a neighbourhood via their Monoid
instance. In terms of precedence, the neighbourhood focus is the "left-most",
and all other elements are "added" to it.
This is not mentioned in GaCM, but seems useful nonetheless.
fmean :: (Fractional a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a Source #
Focal Mean.
fmax :: (Ord a, Bounded a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a Source #
Focal Maximum.
fmin :: (Ord a, Bounded a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a Source #
Focal Minimum.
fmajority :: (Ord a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a Source #
Focal Majority - the most frequently appearing value in each neighbourhood.
fminority :: (Ord a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a Source #
Focal Minority - the least frequently appearing value in each neighbourhood.
fvariety :: (Ord a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Word Source #
Focal Variety - the number of unique values in each neighbourhood.
fpercentage :: (Eq a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Double Source #
Focal Percentage - the percentage of neighbourhood values that are equal to
the neighbourhood focus. Not to be confused with fpercentile
.
fpercentile :: (Ord a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Double Source #
Focal Percentile - the percentage of neighbourhood values that are less
than the neighbourhood focus. Not to be confused with fpercentage
.
Lineal
Focal operations that assume that groups of data points represent
line-like objects in a Raster
. GaCM calls these lineal characteristics
and describes them fully on page 18 and 19.
Instances
Eq Line Source # | |
Ord Line Source # | |
Show Line Source # | |
Storable Line Source # | |
Defined in Geography.MapAlgebra | |
Default Line Source # | |
Defined in Geography.MapAlgebra | |
NFData Line Source # | |
Defined in Geography.MapAlgebra | |
Prim Line Source # | |
Defined in Geography.MapAlgebra alignment# :: Line -> Int# # indexByteArray# :: ByteArray# -> Int# -> Line # readByteArray# :: MutableByteArray# s -> Int# -> State# s -> (#State# s, Line#) # writeByteArray# :: MutableByteArray# s -> Int# -> Line -> State# s -> State# s # setByteArray# :: MutableByteArray# s -> Int# -> Int# -> Line -> State# s -> State# s # indexOffAddr# :: Addr# -> Int# -> Line # readOffAddr# :: Addr# -> Int# -> State# s -> (#State# s, Line#) # writeOffAddr# :: Addr# -> Int# -> Line -> State# s -> State# s # setOffAddr# :: Addr# -> Int# -> Int# -> Line -> State# s -> State# s # |
flinkage :: (Default a, Eq a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Line Source #
Focal Linkage - a description of how each neighbourhood focus is connected to its neighbours. Foci of equal value to none of their neighbours will have a value of 0.
flength :: Functor (Raster u p r c) => Raster u p r c Line -> Raster u p r c Double Source #
Focal Length - the length of the lineal structure at every location. The result is in "pixel units", where 1 is the height/width of one pixel.
Areal
Focal operations that assume that groups of data points represent 2D
areas in a Raster
. GaCM calls these areal characteristics and describes
them fully on page 20 and 21.
A layout of the areal conditions of a single Raster
pixel. It describes
whether each pixel corner is occupied by the same "areal zone" as the pixel
centre.
Corners | |
|
A state of surroundedness of a pixel corner. For the examples below, the bottom-left pixel is considered the focus and we're wondering about the surroundedness of its top-right corner.
Complete | A corner has three of the same opponent against it. The corner is considered "occupied" by the opponent value, thus forming a diagonal areal edge. [ 1 1 ] [ 0 1 ] |
OneSide | One edge of a corner is touching an opponent, but the other edge touches a friend. [ 1 1 ] or [ 0 1 ] [ 0 0 ] [ 0 1 ] |
Open | A corner is surrounded by friends. [ 0 0 ] or [ 0 0 ] or [ 1 0 ] [ 0 0 ] [ 0 1 ] [ 0 0 ] |
RightAngle | Similar to [ 1 2 ] [ 0 1 ] |
OutFlow | Similar to [ 0 1 ] [ 0 0 ] |
fpartition :: (Default a, Eq a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Corners Source #
Focal Partition - the areal form of each location, only considering the top-right edge.
fshape :: (Default a, Eq a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c Corners Source #
Like fpartition
, but considers the Surround
of all corners. Is alluded
to in GaCM but isn't given its own operation name.
If preparing for ffrontage
or farea
, you almost certainly want this
function and not fpartition
.
ffrontage :: Functor (Raster u p r c) => Raster u p r c Corners -> Raster u p r c Double Source #
Focal Frontage - the length of areal edges between each pixel and its neighbourhood.
Usually, the output of fshape
is the appropriate input for this function.
farea :: Functor (Raster u p r c) => Raster u p r c Corners -> Raster u p r c Double Source #
Focal Area - the area of the shape made up by a neighbourhood focus and its surrounding pixels. Each pixel is assumed to have length and width of 1.
Usually, the output of fshape
is the appropriate input for this function.
Surficial
Focal operations that work over elevation Raster
s. GaCM calls elevation
features surficial characteristics and describes them fully on page 21
and 22.
Some of these operations require finding a "best-fit plane" that approximates the surficial shape of each pixel. Each pixel has 9 "facet points" calculated for it based on its surrounding pixels. We then use these facets to determine a plane which adheres to this equation:
\[ ax + by + c = z \] This is a linear equation that we can solve for in the form \(Ax = B\). For facet points \((x_i, y_i, z_i)\), we have:
\[ \begin{bmatrix} x_0 & y_0 & 1 \\ x_1 & y_1 & 1 \\ \vdots & \vdots & \vdots \\ x_n & y_n & 1 \end{bmatrix} \begin{bmatrix} a\\ b\\ c \end{bmatrix} = \begin{bmatrix} z_0\\ z_1\\ \vdots\\ z_n \end{bmatrix} \]
Since this system of equations is "over determined", we rework the above to
find the coefficients of the best-fitting plane via:
\[
\begin{bmatrix}
a\\
b\\
c
\end{bmatrix} = \boxed{(A^{T}A)^{-1}A^{T}}B
\]
The boxed section is called the "left pseudo inverse" and is available as
leftPseudo
. The actual values of \(A\) don't matter for our purposes,
hence \(A\) can be fixed to avoid redundant calculations.
The main type for fdownstream
and fupstream
, used to calculate Focal
Drainage. This scheme for encoding drainage patterns is described on page 81
of GaCM.
Full Explanation
Fluid can flow in or out of a square pixel in one of 256 ways. Imagine a pit, whose neighbours are all higher in elevation: liquid would flow in from all eight compass directions, but no liquid would flow out. Consider then a neighbourhood of random heights - fluid might flow in or out of the focus in any permutation of the eight directions.
The scheme for encoding these permutations in a single Word8
as described
in GaCM is this:
Flow in a particular direction is represented by a power of 2:
[ 1 2 4 ] [ 8 16 ] [ 32 64 128 ]
Direction values are summed to make the encoding. If there were drainage to the North, East, and SouthEast, we'd see a sum of \(2 + 16 + 128 = 146\) to uniquely represent this.
Analysing a drainage pattern from a Drain
is just as easy: check if the bit
corresponding to the desired direction is flipped. The direction
function
handles this.
Instances
Eq Drain Source # | |
Ord Drain Source # | |
Show Drain Source # | |
Storable Drain Source # | |
Default Drain Source # | |
Defined in Geography.MapAlgebra | |
NFData Drain Source # | |
Defined in Geography.MapAlgebra | |
Prim Drain Source # | |
Defined in Geography.MapAlgebra alignment# :: Drain -> Int# # indexByteArray# :: ByteArray# -> Int# -> Drain # readByteArray# :: MutableByteArray# s -> Int# -> State# s -> (#State# s, Drain#) # writeByteArray# :: MutableByteArray# s -> Int# -> Drain -> State# s -> State# s # setByteArray# :: MutableByteArray# s -> Int# -> Int# -> Drain -> State# s -> State# s # indexOffAddr# :: Addr# -> Int# -> Drain # readOffAddr# :: Addr# -> Int# -> State# s -> (#State# s, Drain#) # writeOffAddr# :: Addr# -> Int# -> Drain -> State# s -> State# s # setOffAddr# :: Addr# -> Int# -> Int# -> Drain -> State# s -> State# s # |
Directions that neighbourhood foci can be connected by.
Instances
Enum Direction Source # | |
Defined in Geography.MapAlgebra succ :: Direction -> Direction # pred :: Direction -> Direction # fromEnum :: Direction -> Int # enumFrom :: Direction -> [Direction] # enumFromThen :: Direction -> Direction -> [Direction] # enumFromTo :: Direction -> Direction -> [Direction] # enumFromThenTo :: Direction -> Direction -> Direction -> [Direction] # | |
Eq Direction Source # | |
Ord Direction Source # | |
Defined in Geography.MapAlgebra | |
Show Direction Source # | |
fvolume :: (Fractional a, Default a, Manifest u Ix2 a) => Raster u p r c a -> Raster DW p r c a Source #
Focal Volume - the surficial volume under each pixel, assuming the Raster
represents elevation in some way.
fgradient :: Manifest u Ix2 Double => Raster u p r c Double -> Raster DW p r c Double Source #
Focal Gradient - a measurement of surficial slope for each pixel relative to the horizonal cartographic plane. Results are in radians, with a flat plane having a slope angle of 0 and a near-vertical plane approaching \(\tau / 4\).
faspect :: Manifest u Ix2 Double => Raster u p r c Double -> Raster DW p r c (Maybe Double) Source #
Focal Aspect - the compass direction toward which the surface descends most
rapidly. Results are in radians, with 0 or \(\tau\) being North, \(\tau / 4\)
being East, and so on. For areas that are essentially flat, their aspect will
be Nothing
.
faspect' :: Manifest u Ix2 Double => Raster u p r c Double -> Raster DW p r c Double Source #
Like faspect
, but slightly faster. Beware of nonsense results when the
plane is flat.
fdownstream :: Manifest u Ix2 Double => Raster u p r c Double -> Raster DW p r c Drain Source #
Focal Drainage - downstream portion. This indicates the one or more compass
directions of steepest descent from each location. Appropriate as the input
to fupstream
.
Note: Peak-like surfaces will not flow equally in all 8 directions. Consider this neighbourhood:
[ 1 1 1 ] [ 1 3 1 ] [ 1 1 1 ]
According to the rules in GaCM for calculating the intermediate surficial "facet" points for the focus, 3, we arrive at the following facet height matrix:
[ 1.5 2 1.5 ] [ 2 3 2 ] [ 1.5 2 1.5 ]
With these numbers it's clear that the corners would yield a steeper angle,
so our resulting Drain
would only contain the directions of the diagonals.
fupstream :: Manifest u Ix2 Drain => Raster u p r c Drain -> Raster DW p r c Drain Source #
Focal Drainage - upstream portion. This indicates the one of more compass
directions from which liquid would flow into each surface location. See also
fdownstream
.
Utilities
leftPseudo :: Matrix Double Source #
The first part to the "left pseudo inverse" needed to calculate a best-fitting plane of 9 points.
Massiv Re-exports
For your convenience.
Delayed representation.
Instances
Show D | |
Num e => Numeric D e | |
Defined in Data.Massiv.Array.Delayed.Pull plusScalar :: Index ix => Array D ix e -> e -> Array D ix e # minusScalar :: Index ix => Array D ix e -> e -> Array D ix e # multiplyScalar :: Index ix => Array D ix e -> e -> Array D ix e # absPointwise :: Index ix => Array D ix e -> Array D ix e # additionPointwise :: Index ix => Array D ix e -> Array D ix e -> Array D ix e # subtractionPointwise :: Index ix => Array D ix e -> Array D ix e -> Array D ix e # multiplicationPointwise :: Index ix => Array D ix e -> Array D ix e -> Array D ix e # powerPointwise :: Index ix => Array D ix e -> Int -> Array D ix e # unsafeLiftArray :: Index ix => (a -> e) -> Array D ix a -> Array D ix e # unsafeLiftArray2 :: Index ix => (a -> b -> e) -> Array D ix a -> Array D ix b -> Array D ix e # | |
Floating e => NumericFloat D e | |
Defined in Data.Massiv.Array.Delayed.Pull | |
Index ix => Resize D ix | |
Defined in Data.Massiv.Array.Delayed.Pull | |
Index ix => Stream D ix e | |
Index ix => Construct D ix e | |
Index ix => Extract D ix e | |
Defined in Data.Massiv.Array.Delayed.Pull | |
Index ix => Source D ix e | |
Defined in Data.Massiv.Array.Delayed.Pull unsafeIndex :: Array D ix e -> ix -> e # unsafeLinearIndex :: Array D ix e -> Int -> e # | |
Index ix => Load D ix e | |
Defined in Data.Massiv.Array.Delayed.Pull getComp :: Array D ix e -> Comp # size :: Array D ix e -> Sz ix # loadArrayM :: Monad m => Scheduler m () -> Array D ix e -> (Int -> e -> m ()) -> m () # defaultElement :: Array D ix e -> Maybe e # maxSize :: Array D ix e -> Maybe (Sz ix) unsafeLoadIntoS :: (Mutable r' ix e, PrimMonad m) => MArray (PrimState m) r' ix e -> Array D ix e -> m (MArray (PrimState m) r' ix e) unsafeLoadInto :: (Mutable r' ix e, MonadIO m) => MArray RealWorld r' ix e -> Array D ix e -> m (MArray RealWorld r' ix e) | |
Index ix => StrideLoad D ix e | |
Defined in Data.Massiv.Array.Delayed.Pull | |
(Elt D ix e ~ Array D (Lower ix) e, Index ix) => OuterSlice D ix e | |
Defined in Data.Massiv.Array.Delayed.Pull | |
(Elt D ix e ~ Array D (Lower ix) e, Index ix) => InnerSlice D ix e | |
(Index ix, Index (Lower ix), Elt D ix e ~ Array D (Lower ix) e) => Slice D ix e | |
Defined in Data.Massiv.Array.Delayed.Pull unsafeSlice :: MonadThrow m => Array D ix e -> ix -> Sz ix -> Dim -> m (Elt D ix e) # | |
Functor (Array D ix) | |
Index ix => Applicative (Array D ix) | |
Defined in Data.Massiv.Array.Delayed.Pull | |
Index ix => Foldable (Array D ix) | Row-major sequential folding over a Delayed array. |
Defined in Data.Massiv.Array.Delayed.Pull fold :: Monoid m => Array D ix m -> m # foldMap :: Monoid m => (a -> m) -> Array D ix a -> m # foldr :: (a -> b -> b) -> b -> Array D ix a -> b # foldr' :: (a -> b -> b) -> b -> Array D ix a -> b # foldl :: (b -> a -> b) -> b -> Array D ix a -> b # foldl' :: (b -> a -> b) -> b -> Array D ix a -> b # foldr1 :: (a -> a -> a) -> Array D ix a -> a # foldl1 :: (a -> a -> a) -> Array D ix a -> a # toList :: Array D ix a -> [a] # null :: Array D ix a -> Bool # length :: Array D ix a -> Int # elem :: Eq a => a -> Array D ix a -> Bool # maximum :: Ord a => Array D ix a -> a # minimum :: Ord a => Array D ix a -> a # | |
(Eq e, Index ix) => Eq (Array D ix e) | |
(Index ix, Floating e) => Floating (Array D ix e) | |
Defined in Data.Massiv.Array.Delayed.Pull exp :: Array D ix e -> Array D ix e # log :: Array D ix e -> Array D ix e # sqrt :: Array D ix e -> Array D ix e # (**) :: Array D ix e -> Array D ix e -> Array D ix e # logBase :: Array D ix e -> Array D ix e -> Array D ix e # sin :: Array D ix e -> Array D ix e # cos :: Array D ix e -> Array D ix e # tan :: Array D ix e -> Array D ix e # asin :: Array D ix e -> Array D ix e # acos :: Array D ix e -> Array D ix e # atan :: Array D ix e -> Array D ix e # sinh :: Array D ix e -> Array D ix e # cosh :: Array D ix e -> Array D ix e # tanh :: Array D ix e -> Array D ix e # asinh :: Array D ix e -> Array D ix e # acosh :: Array D ix e -> Array D ix e # atanh :: Array D ix e -> Array D ix e # log1p :: Array D ix e -> Array D ix e # expm1 :: Array D ix e -> Array D ix e # | |
(Index ix, Fractional e) => Fractional (Array D ix e) | |
(Index ix, Num e) => Num (Array D ix e) | |
Defined in Data.Massiv.Array.Delayed.Pull (+) :: Array D ix e -> Array D ix e -> Array D ix e # (-) :: Array D ix e -> Array D ix e -> Array D ix e # (*) :: Array D ix e -> Array D ix e -> Array D ix e # negate :: Array D ix e -> Array D ix e # abs :: Array D ix e -> Array D ix e # signum :: Array D ix e -> Array D ix e # fromInteger :: Integer -> Array D ix e # | |
(Ord e, Index ix) => Ord (Array D ix e) | |
Defined in Data.Massiv.Array.Delayed.Pull | |
(Ragged L ix e, Show e) => Show (Array D ix e) | |
Functor (Raster D p r c) Source # | |
(KnownNat r, KnownNat c) => Applicative (Raster D p r c) Source # | |
Defined in Geography.MapAlgebra pure :: a -> Raster D p r c a # (<*>) :: Raster D p r c (a -> b) -> Raster D p r c a -> Raster D p r c b # liftA2 :: (a -> b -> c0) -> Raster D p r c a -> Raster D p r c b -> Raster D p r c c0 # (*>) :: Raster D p r c a -> Raster D p r c b -> Raster D p r c b # (<*) :: Raster D p r c a -> Raster D p r c b -> Raster D p r c a # | |
Foldable (Raster D p r c) Source # |
|
Defined in Geography.MapAlgebra fold :: Monoid m => Raster D p r c m -> m # foldMap :: Monoid m => (a -> m) -> Raster D p r c a -> m # foldr :: (a -> b -> b) -> b -> Raster D p r c a -> b # foldr' :: (a -> b -> b) -> b -> Raster D p r c a -> b # foldl :: (b -> a -> b) -> b -> Raster D p r c a -> b # foldl' :: (b -> a -> b) -> b -> Raster D p r c a -> b # foldr1 :: (a -> a -> a) -> Raster D p r c a -> a # foldl1 :: (a -> a -> a) -> Raster D p r c a -> a # toList :: Raster D p r c a -> [a] # null :: Raster D p r c a -> Bool # length :: Raster D p r c a -> Int # elem :: Eq a => a -> Raster D p r c a -> Bool # maximum :: Ord a => Raster D p r c a -> a # minimum :: Ord a => Raster D p r c a -> a # | |
Eq a => Eq (Raster D p r c a) Source # | |
(Fractional a, KnownNat r, KnownNat c) => Fractional (Raster D p r c a) Source # | |
(Num a, KnownNat r, KnownNat c) => Num (Raster D p r c a) Source # | |
Defined in Geography.MapAlgebra (+) :: Raster D p r c a -> Raster D p r c a -> Raster D p r c a # (-) :: Raster D p r c a -> Raster D p r c a -> Raster D p r c a # (*) :: Raster D p r c a -> Raster D p r c a -> Raster D p r c a # negate :: Raster D p r c a -> Raster D p r c a # abs :: Raster D p r c a -> Raster D p r c a # signum :: Raster D p r c a -> Raster D p r c a # fromInteger :: Integer -> Raster D p r c a # | |
Semigroup a => Semigroup (Raster D p r c a) Source # | |
(Monoid a, KnownNat r, KnownNat c) => Monoid (Raster D p r c a) Source # | |
data Array D ix e | |
type R D | |
Defined in Data.Massiv.Array.Delayed.Pull |
Delayed Windowed Array representation.
Instances
Representation for Storable
elements
Instances
Representation for Prim
itive elements
Instances
Representation for Unbox
ed elements
Instances
Array representation for Boxed elements. This structure is element and spine strict, but elements are strict to Weak Head Normal Form (WHNF) only.
Instances
Array representation for Boxed elements. This structure is element and
spine strict, and elements are always in Normal Form (NF), therefore NFData
instance is required.
Instances
2-dimensional index. This is also a base index for higher dimensions.
Since: massiv-0.1.0
pattern Ix2 :: Int -> Int -> Ix2 | 2-dimensional index constructor. Useful when infix notation is inconvenient. Since: massiv-0.1.0 |