Skip to content

Commit

Permalink
Merge f4dc81f into 0ec6d6d
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomas Lycken committed Sep 5, 2016
2 parents 0ec6d6d + f4dc81f commit 262854e
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 70 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
docs/build
docs/site
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ julia:
notifications:
- email: false
after_success:
- julia -e 'cd(Pkg.dir("Contour")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())'
- julia -e 'Pkg.add("Documenter"); Pkg.add("Coverage");'
- julia -e 'cd(Pkg.dir("Contour")); using Coverage; Coveralls.submit(process_folder()); Codecov.submit(process_folder())'
- julia -e 'cd(Pkg.dir("Contour")); include(joinpath("docs", "make.jl"))'
69 changes: 1 addition & 68 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Contour
# Contour.jl

CI Status:
[![Build Status](https://travis-ci.org/tlycken/Contour.jl.svg?branch=master)](https://travis-ci.org/tlycken/Contour.jl)
Expand All @@ -11,72 +11,5 @@ PkgEvaluator Status:

A generic library for tracing contour curves on a scalar 2D field.

The idea with this library is to separate the contouring algorithm(s) from the various visualization tools, so that all tools can benefit from advances made here - as well as in other applications, independently of choice of visualization tool. The current implementation uses the [marching squares algorithm](http://en.wikipedia.org/wiki/Marching_squares) to calculate contours.

## Usage Examples

The Contour module currently expects input data to be on a Cartesian grid,
and supports both uniform and non-uniform grid spacings. For the following
examples, `x` and `y` are 1D sorted arrays that contain the grid coordinates,
and `z` is a matrix arranged such that `z[xi,yi]` correspond to the location
`(x[xi], y[yi])`.

```julia
x = -3:0.01:3
y = -4:0.02:5

z = [Float64((xi^2 + yi^2)) for xi in x, yi in y]
```

Let's find the contour line corresponding to `z = 4.0`:

```julia
h = 4.0
c = contour(x, y, z, h)
```

This returns a `ContourLevel` type containing the contour value as well
an array of lines. In the current example, we expect a single line that
traces out a circle with radius 2:

```julia
julia> level(c)
4.0

julia> lines(c)
1 contour lines
```

The format of the output data is intented to give as extensive information as possible about the contour line. However, it can admittedly be a little difficult to use this information in an application. For example, if we want to plot a contour level, it is much more practical to have the coordinates of the contour vertices as two lists instead of this complicated structure. No worries, just use `coordinates`:

```julia
for l in lines(c) # each contour level can be represented by multiple lines
xs, ys = coordinates(l) # xs and ys are now Vectors of equal length
plot(xs, ys) # using your favorite plotting tool
end
```

`Contour.jl` makes sure that the coordinates are ordered correctly, and contours that close on themselves are given cyclically, so that e.g. `xs[1]==xs[end]` - in other words, plotting the contour does not require you to add the first point at the end manually to close the curve.

We can also find the contours at multiple levels using `contours`,
which returns an array of `ContourLevel` types.

```julia
julia> h = [4.0, 5.0, 6.0];
julia> c = contours(x, y, z, h)
Collection of 3 levels.
```

Instead of specifying all the levels explicitly, we can also
specify the number of levels we want.

```julia
julia> N = 3;
julia> c = contours(x, y, z, N)
Collection of 3 levels
```

`contours` will pick `N` levels that evenly span the extrema of `z`.

## Credits
The main authors of this package are [Darwin Darakananda](https://github.com/darwindarak/) and [Tomas Lycken](https://github.com/tlycken).
Binary file added docs/.documenter.enc
Binary file not shown.
16 changes: 16 additions & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Documenter, Contour

makedocs(
format = Documenter.Formats.HTML,
sitename = "Contour.jl",
pages = [
"index.md",
"tutorial.md",
"reference.md"
]
)

deploydocs(
repo = "github.com/tlycken/Contour.jl",
julia = "0.5"
)
9 changes: 9 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Introduction

Contour.jl uses the [marching squares algorithm](http://en.wikipedia.org/wiki/Marching_squares)
to find [isolines](https://en.wikipedia.org/wiki/Contour_line) of a discrete
data set representing a function ``z = f(x, y)``.

[Tutorial](@ref)

[Reference](@ref)
11 changes: 11 additions & 0 deletions docs/src/reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Reference

```@docs
contour
contours
level
levels
lines
coordinates
Contour.contourlevels
```
212 changes: 212 additions & 0 deletions docs/src/tutorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# Tutorial

## TL;DR: If you read nothing else, read this

```@meta
CurrentModule = Contour
DocTestSetup = quote
using Contour
x = -3:0.01:3
y = -4:0.02:5
z = [Float64((xi^2 + yi^2)) for xi in x, yi in y]
plot(x,y,z) = nothing
end
```

The most common use case for this package is plotting iso lines. Here's a
complete example that lets you do that, while showing off all of the most
important features of the package:

```jldoctest
for cl in levels(contours(x,y,z))
lvl = level(cl) # the z-value of this contour level
for line in lines(cl)
xs, ys = coordinates(line) # coordinates of this line segment
plot(xs, ys, color=lvl) # pseuod-code; use whatever plotting package you prefer
end
end
# output
```

## Preface: some test data...

The Contour module expects input data to be on a Cartesian grid, and supports
both uniform and non-uniform grid spacings. For the following examples, `x` and
`y` are 1D sorted arrays that contain the grid coordinates, and `z` is a matrix
arranged such that `z[xi,yi]` correspond to the location `(x[xi], y[yi])`.

Let's consider the function ``z(x,y) = x^2 + y^2``:

```julia
x = -3:0.01:3
y = -4:0.02:5

z = [Float64((xi^2 + yi^2)) for xi in x, yi in y]
```

`x` and `y` don't have to be evenly spaced - they can just as well be (sorted)
arrays of coordinate values.

## Example: plotting isolines

Usually, you'll start by calling [`contours`](@ref):

```jldoctest
c = contours(x,y,z)
# output
Contour.ContourCollection{Contour.ContourLevel{Float64}}
with 10 level(s).
```

The package is designed so that you shouldn't have to worry about the types of
the outputs - instead, there are functions that let you extract the data you
need. So, instead of simply returning a `Vector{ContourLevel}`, we return a
special object which supports the [`levels`](@ref) function. `levels` in turn
returns a collection of `ContourLevel`s which you can iterate over:

```@meta
DocTestSetup = quote
using Contour
x = -3:0.01:3
y = -4:0.02:5
z = [Float64((xi^2 + yi^2)) for xi in x, yi in y]
c = contours(x,y,z)
end
```

```jldoctest
for cl in levels(c)
# do something
end
# output
```

On each level (`cl` in the snippet above) there are two pieces of information
that can be of interest. You find the ``z``-value of the isoline with the
[`level`](@ref) function, while [`lines`](@ref) yields an iterable collection
of line segments (remember that there might be more than one isoline for a given
``z``-value):

```@meta
DocTestSetup = quote
using Contour
x = -3:0.01:3
y = -4:0.02:5
z = [Float64((xi^2 + yi^2)) for xi in x, yi in y]
c = contours(x,y,z)
cl = first(levels(c))
end
```

```jldoctest
level(cl), length(lines(cl))
# output
(3.090909090909091,1)
```

This contour level only had one line. An isoline is represented as a sequence of
vertices, which either starts and ends at the boundaries of the data set, or
closes on itself, in which case the first and last points are equal.

The ``x``- and ``y``-coordinates of an isoline are extracted using the
[`coordinates`](@ref) function:

```@meta
DocTestSetup = quote
using Contour
x = -3:0.01:3
y = -4:0.02:5
z = [Float64((xi^2 + yi^2)) for xi in x, yi in y]
c = contours(x,y,z)
cl = first(levels(c))
l = first(lines(cl))
end
```

```jldoctest
l = first(lines(cl))
xs, ys = coordinates(l)
typeof(xs)
# output
Array{Float64,1}
```

Now we understand all the parts of the plotting example at the top:

```@meta
DocTestSetup = quote
using Contour
x = -3:0.01:3
y = -4:0.02:5
z = [Float64((xi^2 + yi^2)) for xi in x, yi in y]
end
```

```jldoctest
for cl in levels(contours(x,y,z))
lvl = level(cl) # the z-value of this contour level
for line in lines(cl)
xs, ys = coordinates(line) # coordinates of this line segment
plot(xs, ys, color=lvl) # pseuod-code; use whatever plotting package you prefer
end
end
# output
```

## Affecting the choice of contour levels

There are several ways to affect the choice of contour levels.

First, you can specify them manually:

```jldoctest
contours(x, y, z, [2,3])
# output
Contour.ContourCollection{Contour.ContourLevel{Float64}}
with 2 level(s).
```

You can also just specify the number of levels you want, and let the package
choose them:

```jldoctest
contours(x, y, z, 2)
# output
Contour.ContourCollection{Contour.ContourLevel{Float64}}
with 2 level(s).
```

The package uses [`Contour.contourlevels`](@ref) to choose the levels, so it's
entirely possible to investigate what levels would be traced without doing any
plotting:

```jldoctest
Contour.contourlevels(z, 4)
# output
6.8:6.8:27.2
```

If you only want a single contour level, use the [`contour`](@ref) function
directly - its fourth parameter is the ``z``-value at which to trace the isolines:

```jldoctest
contour(x, y, z, 2.3)
# output
Contour.ContourLevel{Float64}
at 2.3 with 1 line(s)
```

0 comments on commit 262854e

Please sign in to comment.