Skip to content

Commit

Permalink
port UnitfulRecipes docs
Browse files Browse the repository at this point in the history
  • Loading branch information
t-bltg committed Sep 26, 2022
1 parent 9cba12a commit c2f632c
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ InspectDR = "d0351b0e-4b05-5898-87b3-e2a8edfddd1d"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925"
Expand Down
20 changes: 19 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Documenter, PlotDocs, Plots, PlotThemes, DemoCards
using Documenter, PlotDocs, Plots, PlotThemes, DemoCards, Literate
import StatsPlots

# Set matplotlib gui backend
Expand Down Expand Up @@ -53,6 +53,23 @@ push!(galleries_assets, assets)

unique!(galleries_assets)

##################
# `UnitfulRecipes`
src = joinpath(@__DIR__, "src/unitfulrecipes")
lit = joinpath(@__DIR__, "src/unitfulrecipes/lit")

notebooks = joinpath(src, "notebooks")
execute = true # set to true for executing notebooks and documenter!
nb = true # set to true to generate the notebooks
for (root, _, files) in walkdir(lit), file in files
splitext(file)[2] == ".jl" || continue
ipath = joinpath(root, file)
opath = splitdir(replace(ipath, lit=>src))[1]
Literate.markdown(ipath, opath, documenter = execute)
nb && Literate.notebook(ipath, notebooks, execute = execute)
end
##################

const PAGES = Any[
"Home"=>"index.md",
"Getting Started"=>[
Expand Down Expand Up @@ -87,6 +104,7 @@ const PAGES = Any[
"Introduction" => "graphrecipes/introduction.md",
"Examples" => "graphrecipes/examples.md",
"Attributes" => "generated/graph_attributes.md",
"UnitfulRecipes" => "unitfulrecipes/unitfulrecipes.md",
"Overview" => "ecosystem.md",
],
],
Expand Down
211 changes: 211 additions & 0 deletions docs/src/unitfulrecipes/lit/1_Examples.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#---------------------------------------------------------
# # [Simple Examples](@id 1_Examples)
#---------------------------------------------------------

#md # [![](https://mybinder.org/badge_logo.svg)](@__BINDER_ROOT_URL__/notebooks/1_Examples.ipynb)
#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/notebooks/1_Examples.ipynb)

#md # !!! note
#md # These examples are available as Jupyter notebooks.
#md # You can execute them online with [binder](https://mybinder.org/) or just view them with [nbviewer](https://nbviewer.jupyter.org/) by clicking on the badges above!

# These examples show what UnitfulRecipes is all about.

# First we need to tell Julia we are using Plots, Unitful, and UnitfulRecipes

using Plots, Unitful

# ## Simplest plot

# This is the most basic example

y = randn(10)*u"kg"
plot(y)

# Add some more plots, and it will be aware of the units you used previously (note `y2` is about 10 times smaller than `y1`)

y2 = 100randn(10)*u"g"
plot!(y2)


# UnitfulRecipes will not allow you to plot with different unit-dimensions, so
# ```julia
# plot!(rand(10)*u"m")
# ```
# won't work here.
#
# But you can add inset subplots with different axes that have different dimensions

plot!(rand(10)*u"m", inset=bbox(0.5, 0.5, 0.3, 0.3), subplot=2)

# ## Axis label

# If you specify an axis label, the unit will be appended to it.

plot(y, ylabel="mass")

# Unless you want it untouched, in which case you can use a "protected" string using the `@P_str` macro.

plot(y, ylabel=P"mass in kilograms")

# Just like with the `label` keyword for legends, no axis label is added if you specify the axis label to be an empty string.

plot(y, ylabel="")

# ### Unit formatting

# If you prefer some other formatting over the round parentheses, you can
# supply a keyword `unitformat`, which can be a number of different things:

# `unitformat` can be a boolean or `nothing`:

plot([plot(y, ylab="mass", title=repr(s), unitformat=s) for s in (nothing, true, false)]...)

# `unitformat` can be one of a number of predefined symbols, defined in

URsymbols = keys(UnitfulRecipes.UNIT_FORMATS)

# which correspond to these unit formats:

plot([plot(y, ylab="mass", title=repr(s), unitformat=s) for s in URsymbols]...)

# `unitformat` can also be a `Char`, a `String`, or a `Tuple` (of `Char`s or
# `String`s), which will be inserted around the label and unit depending on the
# length of the tuple:

URtuples = [", in ", (", in (", ")"), ("[", "] = (", ")"), ':', ('$', '$'), (':', ':', ':')]
plot([plot(y, ylab="mass", title=repr(s), unitformat=s) for s in URtuples]...)

# For *extreme* customizability, you can also supply a function that turns two
# arguments (label, unit) into a string:

formatter(l, u) = string("\$\\frac{\\textrm{", l, "}}{\\mathrm{", u, "}}\$")
plot(y, ylab="mass", unitformat=formatter)

# ## Axis unit

# You can use the axis-specific keyword arguments to convert units on the fly

plot(y, yunit=u"g")

# ## Axis limits and ticks

# Setting the axis limits and ticks can be done with units

x = (1:length(y)) * u"μs"
plot(x, y, ylims=(-1000u"g",2000u"g"), xticks = x[[1,end]])

# or without

plot(x, y, ylims=(-1,2), xticks=1:3:length(x))

# ## Multiple series

# You can plot multiple series as 2D arrays

x, y = rand(10,3)*u"m", rand(10,3)*u"g"
plot(x, y)

# Or vectors of vectors (of potentially different lengths)

x, y = [rand(10), rand(15), rand(20)]*u"m", [rand(10), rand(15), rand(20)]*u"g"
plot(x, y)

# ## 3D

# It works in 3D

x, y = rand(10)*u"km", rand(10)*u"hr"
z = x ./ y
plot(x, y, z)

# ## Heatmaps

# For which colorbar limits (`clims`) can have units

heatmap((1:5)u"μs", 1:4, rand(5,4)u"m", clims=(0u"m", 2u"m"))

# ## Scatter plots

# You can do scatter plots

scatter(x, y, zcolor=z, clims=(5,20).*unit(eltype(z)))

# and 3D scatter plots too

scatter(x, y, z, zcolor=z)


# ## Contour plots

# for contours plots

x, y = (1:0.01:2)*u"m", (1:0.02:2)*u"s"
z = x' ./ y
contour(x, y, z)

# and filled contours, again with optional `clims` units

contourf(x, y, z, clims=(0u"m/s", 3u"m/s"))


# ## Error bars

# For example, you can use the `yerror` keyword argument with units,
# which will be converted to the units of `y` and plot your errorbars:

using Unitful: GeV, MeV, c
x = (1.0:0.1:10) * GeV/c
y = @. (2 + sin(x / (GeV/c))) * 0.4GeV/c^2 # a sine to make it pretty
yerror = 10.9MeV/c^2 * exp.(randn(length(x))) # some noise for pretty again
plot(x, y; yerror, title="My unitful data with yerror bars", lab="")


# ## Ribbon

# You can use units with the `ribbon` feature:

x = 1:10
plot(x, -x.^2 .* 1u"m", ribbon=500u"cm")


# ## Functions
#
# In order to plot a unitful function on a unitful axis, supply as a second argument a
# vector of unitful sample points, or the unit for the independent axis:

model(x) = 1u"V"*exp(-((x-0.5u"s")/0.7u"s")^2)
t = randn(10)u"s" # Sample points
U = model.(t) + randn(10)u"dV" .|> u"V" # Noisy acquicisions
plot(t, U; xlabel="t", ylabel="U", st=:scatter, label="Samples")
plot!(model, t; st=:scatter, label="Noise removed")
plot!(model, u"s"; label="True function")

# ## Initializing empty plot
#
# A plot can be initialized with unitful axes but without datapoints by
# simply supplying the unit:

plot(u"m", u"s")
plot!([2u"ft"], [1u"minute"], st=:scatter)

# ## Aspect ratio
#
# Unlike in a normal unitless plot, the aspect ratio of a unitful plot is in turn a unitful
# number $r$, such that $r\cdot \hat{y}$ would take as much space on the $x$ axis as
# $\hat{y}$ does on the $y$ axis.
#
# By default, `aspect_ratio` is set to `:auto`, which lets you ignore this.
#
# Another special value is `:equal`, which (possibly unintuitively) corresponds to $r=1$.
# Consider a rectangle drawn in a plot with $\mathrm{m}$ on the $x$ axis and
# $\mathrm{km}$ on the $y$ axis. If the rectangle is
# $100\;\mathrm{m} \times 0.1\;\mathrm{km}$, `aspect_ratio=:equal` will make it appear
# square.

plot(
plot(randn(10)u"m", randn(10)u"dm"; aspect_ratio=:equal, title=":equal"),
plot(randn(10)u"m", randn(10)u"s"; aspect_ratio=2u"m/s",
title="\$2\\;\\mathrm{m}/\\mathrm{s}\$"),
plot(randn(10)u"m", randn(10); aspect_ratio=5u"m", title="\$5\\;\\mathrm{m}\$")
)
23 changes: 23 additions & 0 deletions docs/src/unitfulrecipes/unitfulrecipes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
*for plotting data with units seamlessly in Julia*

`UnitfulRecipes` provides recipes for plotting figures ([Plots.jl](https://github.com/JuliaPlots/Plots.jl)) when using data with units ([Unitful.jl](https://github.com/PainterQubits/Unitful.jl)).


---

### Documentation

The goal is that if you can plot something with [Plots.jl](https://github.com/JuliaPlots/Plots.jl) then you should be able to plot the same thing with units.

Essentially, `UnitfulRecipes` strips the units of your data and appends them to the corresponding axis labels.

Pictures speak louder than words, so we wrote some examples (accessible through the links on the left) for you to get an idea of what this package does or to simply try it out for yourself!

!!! note "You can run the examples!"
These examples are available as Jupyter notebooks (through [nbviewer](https://nbviewer.jupyter.org/) or [binder](https://mybinder.org/))!

---

### Ommissions, bugs, and contributing

Please do not hesitate to raise an [issue](https://github.com/JuliaPlots/Plots.jl/issues) or submit a [PR](https://github.com/JuliaPlots/Plots.jl/pulls) if you would like a new recipe to be added.

0 comments on commit c2f632c

Please sign in to comment.