|
| 1 | +```@setup contour |
| 2 | +using Plots |
| 3 | +Plots.reset_defaults() |
| 4 | +``` |
| 5 | + |
| 6 | +# [Contour Plots](@id contour) |
| 7 | + |
| 8 | +The easiest way to get started with contour plots is to use the PyPlot backend. PyPlot requires the `PyPlot.jl` |
| 9 | +package which can be installed by typing `]` and then `add PyPlot` into the REPL. The first time you call `pyplot()`, |
| 10 | +Julia may install matplotlib for you. All of the plots generated on this page use PyPlot, although the code will work |
| 11 | +for the default GR backend as well. |
| 12 | + |
| 13 | +Let's define some ranges and a function `f(x, y)` to plot. Notice the `'` in the line defining `z`. |
| 14 | +This is the adjoint operator and makes `x` a row vector. You can check the shape of `x'` by typing `size(x')`. In the |
| 15 | +tutorial, we mentioned that the `@.` macro evaluates whatever is to the right of it in an element-wise manner. More |
| 16 | +precisely, the dot `.` is shorthand for broadcasting; since `x'` is of size `(1, 100)` and y is of size `(50, )`, |
| 17 | +`z = @. f(x', y)` will broadcast the function `f` over `x'` and `y` and yield a matrix of size `(50, 100)`. |
| 18 | + |
| 19 | +```@example contour |
| 20 | +using Plots; pyplot() |
| 21 | +
|
| 22 | +f(x, y) = (3x + y^2) * abs(sin(x) + cos(y)) |
| 23 | +
|
| 24 | +x = range(0, 5, length=100) |
| 25 | +y = range(0, 3, length=50) |
| 26 | +z = @. f(x', y) |
| 27 | +contour(x, y, z) |
| 28 | +``` |
| 29 | + |
| 30 | +Much like with `plot!` and `scatter!`, the `contour` function also has a mutating version `contour!` which can be |
| 31 | +used to modify the plot after it has been generated. |
| 32 | + |
| 33 | +With the PyPlot backend, `contour` can also take in a row vector for `x`, so alternatively, you can define `x` as |
| 34 | +a row vector as shown below and PyPlot will know how to plot it correctly. Beware that this will NOT work for other |
| 35 | +backends such as the default GR backend, which require `x` and `y` to both be column vectors. |
| 36 | + |
| 37 | +```julia |
| 38 | +x = range(0, 5, length=100)' |
| 39 | +y = range(0, 3, length=50) |
| 40 | +z = @. f(x, y) |
| 41 | +contour(x, y, z) |
| 42 | +``` |
| 43 | + |
| 44 | +## Common Attributes |
| 45 | + |
| 46 | +Let's make this plot more presentable with the following attributes: |
| 47 | + |
| 48 | +1. The number of levels can be changed with `levels`. |
| 49 | +2. Besides the title and axes labels, we can also add contour labels via the attribute `contour_labels`, which has the |
| 50 | +alias `clabels`. We'll use the LaTeXStrings.jl package to write the function expression in the title. (To install this |
| 51 | +package, type `]` and then `add LaTeXStrings` into the REPL.) |
| 52 | +3. The colormap can be changed using `seriescolor`, which has the alias `color`, or even `c`. The default colormap is |
| 53 | +`:inferno`, from matplotlib. A full list of colormaps can be found in the ColorSchemes section of the manual. |
| 54 | +4. The colorbar location can be changed with the attribute `colorbar`, alias `cbar`. We can remove it by setting |
| 55 | +`cbar=false`. |
| 56 | +5. The widths of the isocontours can be changed using `linewidth`, or `lw`. |
| 57 | + |
| 58 | +Note that `levels`, `color`, and `contour_labels` need to be specified in `contour`. |
| 59 | + |
| 60 | +```@example contour |
| 61 | +using LaTeXStrings |
| 62 | +
|
| 63 | +f(x, y) = (3x + y^2) * abs(sin(x) + cos(y)) |
| 64 | +
|
| 65 | +x = range(0, 5, length=100) |
| 66 | +y = range(0, 3, length=50) |
| 67 | +z = @. f(x', y) |
| 68 | +
|
| 69 | +contour(x, y, z, levels=10, color=:turbo, clabels=true, cbar=false, lw=1) |
| 70 | +title!(L"Plot of $(3x + y^2)|\sin(x) + \cos(y)|$") |
| 71 | +xlabel!(L"x") |
| 72 | +ylabel!(L"y") |
| 73 | +``` |
| 74 | + |
| 75 | +If only black lines are desired, you can set the `color` attribute like so: |
| 76 | + |
| 77 | +```julia |
| 78 | +contour(x, y, z, color=[:black]) |
| 79 | +``` |
| 80 | + |
| 81 | +and for alternating black and red lines of a specific hex value, you could type `color=[:black, "#E52B50"]`, and so on. |
| 82 | + |
| 83 | +To get a full list of the available values that an attribute can take, type `plotattr("attribute")` into the REPL. For |
| 84 | +example, `plotattr("cbar")` shows that it can take either symbols from a predefined list (e.g. `:left` and `:top`), |
| 85 | +which move the colorbar from its default location; or a boolean `true` or `false`, the latter of which hides the |
| 86 | +colorbar. |
| 87 | + |
| 88 | +## Filled Contours |
| 89 | + |
| 90 | +We can also specify that the contours should be filled in. One way to do this is by using the attribute `fill`: |
| 91 | + |
| 92 | +```julia |
| 93 | +contour(x, y, z, fill=true) |
| 94 | +``` |
| 95 | + |
| 96 | +Another way is to use the function `contourf`, along with its mutating version `contourf!`: |
| 97 | + |
| 98 | +```@example contour |
| 99 | +contourf(x, y, z, levels=20, color=:turbo) |
| 100 | +title!(L"(3x + y^2)|\sin(x) + \cos(y)|") |
| 101 | +xlabel!(L"x") |
| 102 | +ylabel!(L"y") |
| 103 | +``` |
| 104 | + |
| 105 | +If you are using the GR backend to plot filled contours, there will be black lines separating the filled regions. If |
| 106 | +these lines are undesirable, you can set the line width to 0: `lw=0`. |
| 107 | + |
| 108 | +## Logarithmic Contour Plots |
| 109 | + |
| 110 | +Much like with line and scatter plots, the X and Y axes can be made logarithmic through the `xscale` and `yscale` |
| 111 | +attributes. If both axes need to be logarithmic, then you can set `scale=:log10`. |
| 112 | + |
| 113 | +It will be easier for the backend to generate the plot if the attributes are specified in the `contourf` command |
| 114 | +directly instead of using their mutating versions. |
| 115 | + |
| 116 | +```@example contour |
| 117 | +g(x, y) = log(x*y) |
| 118 | +
|
| 119 | +x = 10 .^ range(0, 6, length=100) |
| 120 | +y = 10 .^ range(0, 6, length=100) |
| 121 | +z = @. g(x', y) |
| 122 | +contourf(x, y, z, color=:plasma, scale=:log10, |
| 123 | + title=L"\log(xy)", xlabel=L"x", ylabel=L"y") |
| 124 | +``` |
| 125 | + |
| 126 | +It is often desired that the colorbar be logarithmic. The process to get this working correctly is a bit more involved |
| 127 | +and will require some manual tweaking. First, we define a function `h(x, y) = exp(x^2 + y^2)`, which we will plot the |
| 128 | +logarithm of. Then we adjust the `levels` and `colorbar_ticks` attributes. |
| 129 | + |
| 130 | +The `colorbar_ticks` attribute can take in a tuple of two vectors `(tickvalues, ticklabels)`. Since `h(x, y)` varies |
| 131 | +from 10<sup>0</sup> to 10<sup>8</sup> over the prescribed domain, tickvalues will be a vector `tv = 0:8`. We can format |
| 132 | +the labels with superscripts by using LaTeXStrings again. Note that the string interpolation operator changes from `$` |
| 133 | +to `%$` when working within `L"..."` to avoid clashing with `$` as normally used in LaTeX. |
| 134 | + |
| 135 | +```@example contour |
| 136 | +h(x, y) = exp(x^2 + y^2) |
| 137 | +
|
| 138 | +x = range(-3, 3, length=100) |
| 139 | +y = range(-3, 3, length=100) |
| 140 | +z = @. h(x', y) |
| 141 | +
|
| 142 | +tv = 0:8 |
| 143 | +tl = [L"10^{%$i}" for i in tv] |
| 144 | +contourf(x, y, log10.(z), color=:turbo, levels=8, |
| 145 | + colorbar_ticks=(tv, tl), aspect_ratio=:equal, |
| 146 | + title=L"\exp(x^{2} + y^{2})", xlabel=L"x", ylabel=L"y") |
| 147 | +``` |
| 148 | + |
| 149 | +If you want the fill boundaries to correspond to the orders of magnitude, `levels=8`. Depending on the data, this |
| 150 | +number may require some tweaking. If you want a smoother plot, then you can set `levels` to a much larger number. |
0 commit comments