Full Code of mbaz/Gaston.jl for AI

master c1c21e9a6c12 cached
55 files
338.2 KB
110.5k tokens
1 requests
Download .txt
Showing preview only (358K chars total). Download the full file or copy to clipboard to get everything.
Repository: mbaz/Gaston.jl
Branch: master
Commit: c1c21e9a6c12
Files: 55
Total size: 338.2 KB

Directory structure:
gitextract__535gg22/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       └── tagbot.yml
├── .gitignore
├── CHANGELOG.md
├── COPYING
├── LICENSE.txt
├── Project.toml
├── README.md
├── docs/
│   ├── notebook/
│   │   ├── how-to-plot-a-torus.jl
│   │   ├── tutorial-3d.jl
│   │   └── tutorial-essentials.jl
│   ├── v1/
│   │   ├── 2d-gallery.md
│   │   ├── 2dplots.md
│   │   ├── 3d-gallery.md
│   │   ├── 3dplots.md
│   │   ├── api.md
│   │   ├── examples.md
│   │   ├── extending.md
│   │   ├── extguide.md
│   │   ├── faq.md
│   │   ├── figures.md
│   │   ├── index.md
│   │   ├── introduction.md
│   │   └── plotguide.md
│   └── v2/
│       ├── .gitignore
│       ├── Project.toml
│       ├── _extensions/
│       │   └── jjallaire/
│       │       └── code-visibility/
│       │           ├── _extension.yml
│       │           └── code-visibility.lua
│       ├── _quarto.yml
│       ├── assets/
│       │   ├── cairolatex.tex
│       │   ├── lorenz.jl
│       │   └── test.tex
│       ├── examples.qmd
│       ├── index.qmd
│       ├── manual.qmd
│       ├── migrate.qmd
│       ├── recipes.qmd
│       ├── reference.qmd
│       ├── styles.css
│       └── tutorial.qmd
├── src/
│   ├── Gaston.jl
│   ├── gaston_aux.jl
│   ├── gaston_builtinthemes.jl
│   ├── gaston_figures.jl
│   ├── gaston_llplot.jl
│   ├── gaston_options.jl
│   ├── gaston_plot.jl
│   └── gaston_recipes.jl
└── test/
    ├── Project.toml
    ├── downstream.jl
    ├── downstream_dev.jl
    ├── manualtests.txt
    ├── preferences.jl
    └── runtests.jl

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/dependabot.yml
================================================
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "monthly"
  - package-ecosystem: "julia"
    directory: "/"
    schedule:
      interval: "weekly"


================================================
FILE: .github/workflows/ci.yml
================================================
name: ci

on:
  pull_request:
  workflow_dispatch:
  push:
    branches: [master]

concurrency: 
  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

permissions:
  actions: write
  contents: read

jobs:
  test:
    name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
    continue-on-error: ${{ matrix.experimental }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        version:
          - 'lts'
          - '1'
        experimental:
          - false
        os: [ubuntu-latest, windows-latest, macos-latest]
        arch: [x64]
        include:
          - os: ubuntu-latest
            experimental: true
            version: 'pre'
            arch: x64

    steps:
      - uses: actions/checkout@v6
      - uses: julia-actions/setup-julia@v3
        with:
          version: ${{ matrix.version }}
          arch: ${{ matrix.arch }}
      - uses: julia-actions/cache@v3
      - uses: julia-actions/julia-buildpkg@latest
      - uses: julia-actions/julia-runtest@latest
      - uses: julia-actions/julia-processcoverage@latest
      - uses: codecov/codecov-action@v6
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: false
          files: lcov.info


================================================
FILE: .github/workflows/tagbot.yml
================================================
name: tagbot

on:
  issue_comment:
    types: ['created']
  workflow_dispatch:
    inputs:
      lookback:
        default: 10

jobs:
  tagbot:
    if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
    runs-on: ubuntu-latest
    steps:
      - uses: JuliaRegistries/TagBot@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          ssh: ${{ secrets.DOCUMENTER_KEY }}


================================================
FILE: .gitignore
================================================
docs/build

Manifest-v*.toml
Manifest.toml

docs/v2/.quarto/
docs/v2/_site/
docs/v1/_site/
docs/v1/assets


================================================
FILE: CHANGELOG.md
================================================
New in version 2
================

Gaston v2 is a breaking release. A
[migration guide](https://mbaz.github.io/Gaston.jl/v2/migrate.html) is available.

* A recipe system for plotting arbitrary Julia types.
  * Recipes can be written without depending on Gaston using a new package,
    GastonRecipes, which is very small, has only one dependency (`MacroTools`),
    and no exports.
* New, simpler but more flexible syntax.
  * Axis settings and curve appearance are distinguished by their position in the
    `plot` command (before and after data, respectively). Example:

    `plot("set grid", x, y, "linecolor 'blue'")`

  * `@plot` and `@splot` macros that take key-value arguments, as in:

    `@plot {title = Q"A Plot"} x y {with = "lp"}`

  * The string macro `Q_str` converts string `Q"A b"` to `"'A b'"`
  * The macro `@gpkw` allows any plot command to take key-value arguments:
    `@gpkw surf({grid}, x, y, z)`
  * Support for gnuplot datasets, including reading back data after plotting
    `with table`.
* Overhauled multiplot support.
  * Axes are placed by indexing a figure: `plot(f[2], x, y)` will place the plot
    as the second axis in figure `f`.
  * Curves can be pushed into axes and axes into figures arbitrarily.
  * `p1 = plot(...); p2 = plot(...); plot(p1, p2)` is also supported (creates a
    multiplot with figures `p1` and `p2`.
  * Automatic layout keeps a square aspect ratio, or user may take complete
    control over layout.
* Every figure is backed up by a separate gnuplot process.
* Simpler interace for saving plots: `save([figure,], filename, terminal)`.
* Better support for animations in notebooks.
* Support for themes.
  * More than 20 pre-defined plotting styles (`surf`, `heatmap`, `histogram`, etc)
    based on built-in themes.
* Simpler configuration, by changing values of a few `Gaston.config` fields.
* Re-written [documentation](https://mbaz.github.io/Gaston.jl/v2/).

# version 1.1.2

* Bug fixes

# version 1.1.1

* Bug fixes

# version 1.1

* Require Julia 1.6

# version 1.0.6

* Bug fixes

# version 1.0.5

* Bug fixes

# version 1.0.4

* Bug fixes

# version 1.0.3

* Bug fixes

# version 1.0.2

* Bug fixes

# version 1.0.1

* Bug fixes

# version 1.0

* New plot syntax, using key-value pairs for line configuration and
  Axes() for axis settings.
* Parse key-value pairs to extend/simplify gnuplot's syntax
* Use palettes from colorschemes
* Generate linetypes from colorschemes
* Gaston now does not validate that commands/data sent to gnuplot is valid.
  This opens the door to a much simplified and more flexible design.
* Extended support for multiplot.
* Bug fixes
* Debug mode
* New plot styles
* Support for more terminals

# version 0.10

* Bug fixes
* Introduce precompilation
* Refactor exceptions to use correct types
* Improve terminal configuration
* Extended support for gnuplot terminals
* More plot styles

# version 0.9

* Bug fixes
* Add ranges to imagesc
* Default to svg in notebooks


# version 0.7.4

* Add support for `dumb` text terminal
* Add a `null` terminal that does not display anything
* Tests for 0.7 pass

# version 0.7.3

* fix default size for pdf-like terminals.

# version 0.7.2

* add `linestyle` option (corresponds to gnuplot's `dashtype`)
* update docs
* fix indexing bug in image plotting

# version 0.7.1

* add `palette` option
* Use empty string as defaults for axis labels and title
* Add missing `plot!()` commands
* Update .travis.yml
* Fix tempdir problem in Windows
* Update changelog

# version 0.7

* Require Julia 0.6
* New tutorial
* New syntax for plotting
* New `set` command to set defaults
* Add support for plotting complex vectors
* Improve and add tests
* Many internal fixes and code optimization

# version 0.6

* Add support for grids
* Fix deprecations
* Restore histogram functionality broken by Julia update
* Remove support for Julia 0.3

# version 0.5.7

* Update tests to use Julia's infrastructure

# version 0.5.6

* Require Julia 0.5.

# version 0.5.5

* Update syntax again. Convert into a Julia package.

# version 0.5.4

* Update syntax to keep up with Julia.

# version 0.5.3:

User visible:

* New terminals: aqua (OS X only) and EPS.
* Improved documentation.
* Compatibility with latest Julia syntax changes.

Under the hood:

* A few bug fixes and performance improvements.

# version 0.5:

User visible:

* New high-level command imagesc.
* New high-level command surf.
* Support for printing to file; SVG, PNG, GIF and PDF formats supported.
* Add support for 'dots' plotstyle.
* Add a test framework and 93 tests.
* Remove artificial restrictions on mixing many images and curves on the
  same figure.
* Images support explicit x, y coordinates.
* Updated and improved documentation.

Under the hood:

* A few small bug fixes.
* Code has been simplified in many places.

# version 0.4:

User visible:

* Add support for x11 terminal
* Add support for printing to files (gif and svg)
* Add support for setting default values for all plot properties
* Improved documentation

Under the hood:

* Improved detection of invalid configurations
* No longer require 'figs' global variable
* Add new 'config' type to store configuration: this will allow the user
  to configure many aspects of Gaston's behavior
* File organization has been completely revamped

# version 0.3:

* Add 'high-level' plot() and histogram() functions
* Add error checking of arguments and types, to minimise risk of gnuplot
	barfing on us on misconfigured plots
* Change type names to conform to Julia conventions (no underscores)
* Improved PDF documentation
* Fixed a few bugs

# version 0.2:

* Add support for histograms, via the "boxes" plot style.
* Add example histogram to demos.
* Add support for rgbimage plot style
* Add rgbimage example to demos.
* Fix bug (issue #1 on bitbucket) in the way figure handles were used.


================================================
FILE: COPYING
================================================
Copyright (c) 2012 Miguel Bazdresch

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: LICENSE.txt
================================================
Copyright (c) 2013 Miguel Bazdresch

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: Project.toml
================================================
name = "Gaston"
uuid = "4b11ee91-296f-5714-9832-002c20994614"
version = "2.0.2"

[deps]
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
GastonRecipes = "39356fd2-1f9e-4efe-8abf-5745c7d9f608"
Gnuplot_jll = "e5af9688-3aeb-5ed5-8c7e-253e55323d3e"
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"

[compat]
GastonRecipes = "1"
Gnuplot_jll = "60.0.4000"
ColorSchemes = "3.27"
DelimitedFiles = "1"
MacroTools = "0.5"
PrecompileTools = "1"
Preferences = "1"
StatsBase = "0.34"
julia = "1.10"


================================================
FILE: README.md
================================================
[![Docs stable](https://img.shields.io/badge/docs-stable-blue.svg)](
  https://mbaz.github.io/Gaston.jl/v2/
)
[![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](
  LICENSE.txt
)
<br>
[![CI](https://github.com/mbaz/Gaston.jl/actions/workflows/ci.yml/badge.svg)](
  https://github.com/mbaz/Gaston.jl/actions/workflows/ci.yml
)
[![Coverage Status](https://codecov.io/gh/mbaz/Gaston.jl/branch/master/graphs/badge.svg?branch=master)](
  https://app.codecov.io/gh/mbaz/Gaston.jl
)
[![PkgEval](https://juliaci.github.io/NanosoldierReports/pkgeval_badges/G/Gaston.named.svg)](
  https://juliaci.github.io/NanosoldierReports/pkgeval_badges/G/Gaston.html
)
<br>
[![JuliaHub deps](https://juliahub.com/docs/General/Gaston/stable/deps.svg)](
  https://juliahub.com/ui/Packages/General/Gaston?t=2
)
[![Downloads](https://img.shields.io/badge/dynamic/json?url=http%3A%2F%2Fjuliapkgstats.com%2Fapi%2Fv1%2Fmonthly_downloads%2FGaston&query=total_requests&suffix=%2Fmonth&label=Downloads)](
  https://juliapkgstats.com/pkg/Gaston
)

Gaston: Julia plotting using gnuplot
==================================== 

Gaston is a [Julia](https://julialang.org) package for plotting. It provides an interface to [gnuplot](http://gnuplot.info), a powerful plotting package available on all major platforms.

Current stable release is v2.0, and it has been tested with Julia LTS (1.10) and stable (1.11), on
Linux. Gaston _should_ work on any platform that runs julia and gnuplot.

Version 1.1.2 runs with Julia 1.6 and later, but it is no longer maintained. All
users are encouraged to move to version 2.

Documentation
-------------

`Gaston.jl`'s documentation can be found [here](https://mbaz.github.io/Gaston.jl/v2/).

The documentation for the older v1.x releases is [here](https://mbaz.github.io/Gaston.jl/v1/).

Why use Gaston?
--------------

Why use Gaston, when there are powerful alternatives such as Plots.jl and Makie.jl? These are some Gaston features that may be attractive to you:

* Gaston can plot:
    * Using graphical windows, and keeping multiple plots active at a time, with mouse interaction
    * Arbitrary Julia types, using recipes.
    * Directly to the REPL, using text (ASCII) or sixels
    * In Jupyter, Pluto and other IDEs
* Supports popular 2-D plots: regular function plots, stem, step, histograms, images, etc.
* Supports surface, contour and heatmap 3-D plots.
* Can save plots to multiple formats, including pdf, png and svg.
* Provides a simple interface for knowledgeable users to access gnuplot features.
* It is fast.

Installation
------------

Gaston requires gnuplot to be installed in your system. It has been tested with versions 5.4 and above, but it should work with any recent version. Gnuplot version
6 is recommended.

To install Gaston using Julia's packaging system, enter Julia's package manager prompt with `]`, and run

    pkg> add Gaston

Contributing
------------

Contributions are encouraged, in the form of issue reports, pull requests, new
tests, and new recipes.



================================================
FILE: docs/notebook/how-to-plot-a-torus.jl
================================================
### A Pluto.jl notebook ###
# v0.20.10

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    #! format: off
    return quote
        local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
        el
    end
    #! format: on
end

# ╔═╡ 4bd21a1f-900c-4837-b121-6e708ed9e178
import Pkg

# ╔═╡ 4a857a54-37f5-45d5-a715-95614ee569fe
# ╠═╡ show_logs = false
Pkg.add("PlutoUI")

# ╔═╡ fd4dbf2c-3e9d-4a9e-8d45-0976c6fbd46c
# ╠═╡ show_logs = false
Pkg.develop(path="/home/miguel/rcs/jdev/Gaston")

# ╔═╡ 2fd048bc-2e87-490a-afc2-5c216d260e77
using Gaston

# ╔═╡ 4ccbcb36-2fb7-495a-ac80-3d4eab0f4471
using PlutoUI

# ╔═╡ 05614214-fb38-4170-acfe-66b90b88c283
md"# Gaston demo/tutorial

## How to plot one (or two) torus

This demo/tutorial shows how to use Gaston in a Pluto notebook, including interactive plots. Some auxiliary functions used throughout the tutorial are defined at the end of the notebook. 

Let's start by loading Gaston and PlutoUI."

# ╔═╡ 8fa8505a-98c8-46bf-a716-dba45626b98a
PlutoUI.TableOfContents(title = "Contents")

# ╔═╡ a87cb7e3-18e4-49d3-a8db-31b7bbeacae0
import LinearAlgebra: norm, cross, dot

# ╔═╡ 65a53ffa-c8c0-448b-957a-ea9c55928057
md"""### Step 1: plotting a circle in three dimensions

Our first task is to draw circles of arbitrary size at arbitrary postions in space.

Consider a circle of radius $r$ centered at $p \in \mathbb{R}^3$ on the plane defined by the orthonormal vectors $\mathbf{v}_1$ and $\mathbf{v}_2$. The parametric equation of this circle is

$[x, y, z] = p + r\cos(t)\mathbf{v}_1 + r\sin(t)\mathbf{v}_2.$

Let's test this out:
"""

# ╔═╡ 053a7600-c582-4498-a848-e704fc1dd927
md"""#### Parameters
center x: $(@bind cx Slider(-5:0.1:5, default = 0, show_value = true))

center y: $(@bind cy Slider(-5:0.1:5, default = 0, show_value = true))

center z: $(@bind cz Slider(-5:0.1:5, default = 0, show_value = true))

radius: $(@bind r Slider(0.1:0.1:3, default = 1, show_value = true))

orientation θ: $(@bind θ Slider(0:0.05:π, default = 0, show_value = true))

orientation ρ: $(@bind ρ Slider(0:0.05:2π, default = 0, show_value = true))
"""

# ╔═╡ 3480c76e-a643-4856-a51a-a4b621c7b545
md"""### Step 2: Plotting a donut frame

Now that we know how to plot arbitrary circles, we'll draw a bunch of small circles making a ring around a larger one. These will form the frame of "skeleton" of the torus. 

Let's draw the frame of a torus of major radius $r_M$ and minor radius $r_m$."""

# ╔═╡ e7906ae5-e460-4d28-af8b-948415310d3d
md"#### Radii

rM $(@bind rM Slider(0.1:0.1:2, default = 1, show_value = true))
rm $(@bind rm Slider(0.1:0.1:1, default = 0.1, show_value = true))"

# ╔═╡ 036ae8fa-e6ba-4d06-94f9-c64c7b87507f
md"""### Step 3: Plotting the torus' surface

In order to "fill" the torus' frame, we need to stack the coordinates of all the small circles and pass them to `splot`. Gnuplot will automatically create a wireframe connecting the vertices of neighboring circles. Using the `pm3d` plotstyle, gnuplot will apply surface and lighting effects to the torus frame. To see the wireframe, plot using `with lines`.

"""

# ╔═╡ 1de39361-2264-4bdd-8694-462d41436a81
md"""#### Center
cx: $(@bind c2x Slider(-5:0.1:5, default = 0, show_value = true))

cy: $(@bind c2y Slider(-5:0.1:5, default = 0, show_value = true))

cz: $(@bind c2z Slider(-5:0.1:5, default = 0, show_value = true))
"""

# ╔═╡ 4a0cdeda-1d93-4be9-8e79-e1510a9fe1e7
md"""### Step 4: Rotate the torus

Now, we will apply a rotation to the torus using angles along the x, y and z axes."""

# ╔═╡ 07294d8b-b01c-4528-8217-0572466f9eaa
md"""#### Center
cx: $(@bind c3x Slider(-5:0.1:5, default = 0, show_value = true))

cy: $(@bind c3y Slider(-5:0.1:5, default = 0, show_value = true))

cz: $(@bind c3z Slider(-5:0.1:5, default = 0, show_value = true))

#### Angle

θx: $(@bind θx Slider(0:0.05:3.15, default = 0, show_value = true))

θy: $(@bind θy Slider(0:0.05:3.15, default = 0, show_value = true))

θz: $(@bind θz Slider(0:0.05:6.3, default = 0, show_value = true))
"""

# ╔═╡ 7e89c619-c951-45eb-adfc-8e91f42d7e60
md"""### Conclusion

Now that we know how to plot arbitrary torii, let's draw two of them with high resolution."""

# ╔═╡ e47bb743-75ba-427d-9301-a15cea857be3
md"Support code"

# ╔═╡ 22941298-cc85-45d1-9fc7-96b2a1e6d863
begin
	ft = Figure("torus")
	fti = Figure("torii")
	nothing
end

# ╔═╡ 9d71d2ee-c194-49cf-ab41-c99500d36298
"Circle parametric equation"
function paramcircle(p, r, v1, v2, t)
	x = p[1] + r*cos(t)*v1[1] + r*sin(t)*v2[1]
	y = p[2] + r*cos(t)*v1[2] + r*sin(t)*v2[2]
	z = p[3] + r*cos(t)*v1[3] + r*sin(t)*v2[3]
	return (x, y, z)
end

# ╔═╡ f55bf207-fad4-44b1-b5d9-d7efe686bf42
"""Given 3-D orientation vector `o`, return orthonormal vectors
   `v1`, `v2` that span the plane to which `o` is normal."""
function normals(o)
	ex = [1., 0., 0.]; ey = [0., 1., 0.]; ez = [0., 0., 1.]
	ox = o[1]; oy = o[2]; oz = o[3]
	if all(iszero, o)
		v1 = ey
	elseif (ox == 0) && (oy == 0)
		v1 = sign(oz)*ey
	elseif (ox == 0) && (oz == 0)
		v1 = -sign(oy)*ex
	elseif (oy == 0) && (oz == 0)
		v1 = sign(ox)*ey
	else
#		if (oz > 0)
#	    	v1 = [-sign(ox)*oy/ox, sign(ox), 0]
#		else
#			v1 = [oy/ox, -1, 0]
#		end
		v1 = [ox == 0 ? 0 : -sign(ox)*oy/ox, sign(ox), 0]
	end
	v2 = cross(collect(o), v1)
	return (v1./norm(v1), v2./norm(v2))
end

# ╔═╡ 5cdd317a-de26-4093-8651-615bcb46ffa9
let
	c = [cx, cy, cz]; ox, oy, oz = sin(θ)*cos(ρ), sin(θ)*sin(ρ), cos(θ)
	o_ = [ox, oy, oz]
	o = 0.35 .* o_ ./ norm(o_)
	v1, v2 = normals(o)
	v1p = 0.35 .* v1; v2p = 0.35 .* v2;
	cir = stack(t -> paramcircle(c, r, v1, v2, t), range(0, 2π, 20), dims=1)
	@splot(:unitranges, {xyplane = "at 0"},
	       cx, cy, cz, ox, oy, oz, "w vectors lc 'black'")
	splot!(cx, cy, cz, v1p[1], v1p[2], v1p[3], "w vectors lc 'blue'")
	splot!(cx, cy, cz, v2p[1], v2p[2], v2p[3], "w vectors lc 'dark-green'")
	splot!(cir[:,1], cir[:,2], cir[:,3], "lc 'black'")
	cr = cross(v1, v2)
	splot!(cx, cy, cz, cr[1], cr[2], cr[3], "w vectors lc 'red'")
end

# ╔═╡ f4334764-5ada-424d-a0eb-8a9f7ee55c32
"""Central diff of `f` at `t` with step `h = 1e-6`"""
function cendiff(f, t, h = 1e-6)
	(f(t.+h/2) .- f(t.-h/2))./h
end

# ╔═╡ 398a6f8b-b783-4a38-82c9-b01012b347d4
let ft = ft
	N = 16 # number of circles to draw
	#c = [c2x, c2y, c2z] # torus center
	#ox, oy, oz = sin(θt)*cos(ρt), sin(θt)*sin(ρt), cos(θt)
	#o_ = [ox, oy, oz]
	#o = 0.2 .* o_ ./ norm(o_)
	#v1, v2 = normals(o)
	c = [0,0,0]; v1 = [1,0,0]; v2 = [0,1,0]
	pc(t) = paramcircle(c, rM, v1, v2, t)  # torus core
	cir = stack(pc, range(0, 2π, 20), dims=1)
	@splot(ft, :notics, :labels, {view=(60,30), view = "equal xy", ranges = (-3,3), xyplane = "at 0"}, cir[:,1], cir[:,2], cir[:,3])
	# center of each circle in the frame
	pcenters = range(0, 2π-2π/N, N)
	centers = [paramcircle(c, rM, v1, v2, t) for t in pcenters]
	for n in 1:N
		# orientation of each circle -- tangent to torus core
		oc = cendiff(pc, pcenters[n])
		n1, n2 = normals(oc); #display((oc, n1,n2))
		d = stack(t -> paramcircle(centers[n], rm, n1, n2, t), range(0,2π,10), dims=1)
		# plots
		splot!(ft, d[:,1], d[:,2], d[:,3], "lc 'black'")
		#splot!(ft, d[1,1], d[1,2], d[1,3], "w p pt '0'")
		#splot!(ft, d[3,1], d[3,2], d[3,3], "w p pt '3'")
		#splot!(ft, d[:,1], d[:,2], d[:,3], "lc 'black'")
		#splot!(ft, centers[n][1], centers[n][2], centers[n][3], centers[n][1]+oc[1], centers[n][2]+oc[2], centers[n][3]+oc[3], "w vectors lc 'green'")
	end
	ft
end

# ╔═╡ d25d04f9-c8c9-4b25-af01-1b67b4c1999f
let ft = ft
	res = 64 # points per circle
	N = 64 # number of circles to draw
	c = [c2x, c2y, c2z] # torus center
	ox, oy, oz = sin(θ)*cos(ρ), sin(θ)*sin(ρ), cos(θ) # torus orientation
	o_ = [ox, oy, oz]
	o = 0.2 .* o_ ./ norm(o_)
	v1, v2 = normals(o)
	pc(t) = paramcircle(c, rM, v1, v2, t)  # torus core
	cir = stack(pc, range(0, 2π, res), dims=1)
	# center of each circle in the frame
	pcenters = range(0, 2π, N)
	centers = [paramcircle(c, rM, v1, v2, t) for t in pcenters]
	x = zeros(res, N); y = zeros(res, N); z = zeros(res, N)
	for n in 1:N
		# orientation of each circle -- tangent to torus core
		oc = cendiff(pc, pcenters[n])
		n1, n2 = normals(oc)
		d = stack(t -> paramcircle(centers[n], rm, n1, n2, t), range(0,2π,res), dims=1)
		x[:,n] .= d[:,1]; y[:,n] .= d[:,2]; z[:,n] .= d[:,3]
	end
	@splot(ft, {pm3d = "depthorder", pm3d = "lighting", ranges=(-3,3),
	            hidden3d, cbrange = (-rm,rm),
	            palette = :plasma,
	            xyplane = "at 0",
	            colorbox = false}, :notics,
	            x, y, z, "w pm3d fillcolor 'dark-turquoise'")
end

# ╔═╡ e6c5661f-c864-4834-9ac5-1fc1b799bed0
""" torus

Calculate torus coordinates."""
function torus(c, θx, θy, θz, rM, rm, N, n)
	# step 1: calculate a torus in the origin
	x, y, z = torus(rM, rm, N, n)
	# step 2: calculate rotation matrices
	Rx = [1 0      0      ;
	      0 cos(θx) -sin(θx);
	      0 sin(θx)  cos(θx)]
	Ry = [ cos(θy) 0 sin(θy);
	       0      1 0     ;
	      -sin(θy) 0 cos(θy)]
	Rz = [cos(θz) -sin(θz) 0;
	      sin(θz)  cos(θz) 0;
	      0       0      1]
	R = Rz*Ry*Rx
	# step 3: rotate and translate each torus point
	p = zeros(3); q = zeros(3)
	for col in 1:N
		for row = 1:n
			p[1] = x[row, col]; p[2] = y[row, col]; p[3] = z[row, col]
			q = R*p;
			x[row, col] = q[1] + c[1]
			y[row, col] = q[2] + c[2]
			z[row, col] = q[3] + c[3]
		end
	end
	x, y, z
end

# ╔═╡ 1a407189-602e-4f79-9c68-8c0ec9527336
function torus(rM, rm, N, n)
	c = (0, 0, 0)
	v1, v2 = normals([0, 0, 1])
	# calculate torus core
	core(t) = paramcircle(c, rM, v1, v2, t)
	# find center of each torus slice
	pcenters = range(0, 2π, N)
	centers = [paramcircle(c, rM, v1, v2, t) for t in range(0, 2π, N)]
	x = zeros(n, N); y = zeros(n, N); z = zeros(n, N)
	d = zeros(n, 3)
	for k in 1:N
		# orientation of each circle -- tangent to torus core
		oc = cendiff(core, pcenters[k])
		n1, n2 = normals(oc)
		d .= stack(t -> paramcircle(centers[k], rm, n1, n2, t), range(0, 2π, n), dims = 1)
		x[:,k] .= d[:,1]; y[:,k] .= d[:,2]; z[:,k] .= d[:,3]
	end
	x, y, z
end

# ╔═╡ 45904d7b-3b2e-411d-8715-372220b5cd00
let
	all(iszero, (θx, θy, θz)) && (θz = 1.0)
	c = [c3x, c3y, c3z] # torus center
	x, y, z = torus(c, θx, θy, θz, rM, rm, 32, 32)
	splot("set xrange [-3:3]", "set yrange [-3:3]", "set zrange [-2:2]", :labels, "set pm3d depthorder", "set view 60,30", "set view equal xyz", "unset colorbox", "set pm3d lighting", x, y, z, "w pm3d fillcolor 'dark-turquoise'")
end

# ╔═╡ 6b476e91-aa7d-48ad-8cee-00630818238a
let
	c1 = [0,0,0]; x1 = 0; y1 = 0; z1 = 1; rM1 = 1; rm1 = 0.4;
	c2 = [1,0,0]; x2 = π/2; y2 = 0; z2 = 0; rM2 = 1; rm2 = 0.4;
	t1x, t1y, t1z = torus(c1, x1, y1, z1, rM1, rm1, 128, 128)
	t2x, t2y, t2z = torus(c2, x2, y2, z2, rM2, rm2, 128, 128)
	@splot(fti, {pm3d = "depthorder",
	             pm3d = "lighting",
	             tics = false,
	             colorbox = false,
	             view = "equal xyz",
	             view = (40, 20, 2)},
	            t1x, t1y, t1z, "w pm3d fillcolor 'dark-turquoise'")
	splot!(fti, t2x, t2y, t2z, "w pm3d fillcolor 'salmon'")
end

# ╔═╡ Cell order:
# ╟─05614214-fb38-4170-acfe-66b90b88c283
# ╠═4bd21a1f-900c-4837-b121-6e708ed9e178
# ╠═4a857a54-37f5-45d5-a715-95614ee569fe
# ╠═fd4dbf2c-3e9d-4a9e-8d45-0976c6fbd46c
# ╠═2fd048bc-2e87-490a-afc2-5c216d260e77
# ╠═4ccbcb36-2fb7-495a-ac80-3d4eab0f4471
# ╠═8fa8505a-98c8-46bf-a716-dba45626b98a
# ╠═a87cb7e3-18e4-49d3-a8db-31b7bbeacae0
# ╟─65a53ffa-c8c0-448b-957a-ea9c55928057
# ╟─053a7600-c582-4498-a848-e704fc1dd927
# ╠═5cdd317a-de26-4093-8651-615bcb46ffa9
# ╟─3480c76e-a643-4856-a51a-a4b621c7b545
# ╟─e7906ae5-e460-4d28-af8b-948415310d3d
# ╠═398a6f8b-b783-4a38-82c9-b01012b347d4
# ╟─036ae8fa-e6ba-4d06-94f9-c64c7b87507f
# ╟─1de39361-2264-4bdd-8694-462d41436a81
# ╠═d25d04f9-c8c9-4b25-af01-1b67b4c1999f
# ╟─4a0cdeda-1d93-4be9-8e79-e1510a9fe1e7
# ╟─07294d8b-b01c-4528-8217-0572466f9eaa
# ╠═45904d7b-3b2e-411d-8715-372220b5cd00
# ╟─7e89c619-c951-45eb-adfc-8e91f42d7e60
# ╠═6b476e91-aa7d-48ad-8cee-00630818238a
# ╟─e47bb743-75ba-427d-9301-a15cea857be3
# ╟─22941298-cc85-45d1-9fc7-96b2a1e6d863
# ╟─9d71d2ee-c194-49cf-ab41-c99500d36298
# ╟─f55bf207-fad4-44b1-b5d9-d7efe686bf42
# ╟─f4334764-5ada-424d-a0eb-8a9f7ee55c32
# ╟─e6c5661f-c864-4834-9ac5-1fc1b799bed0
# ╟─1a407189-602e-4f79-9c68-8c0ec9527336


================================================
FILE: docs/notebook/tutorial-3d.jl
================================================
### A Pluto.jl notebook ###
# v0.20.10

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    #! format: off
    return quote
        local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
        el
    end
    #! format: on
end

# ╔═╡ 93b3b71e-0a4e-4165-9f92-b770c06a5964
# ╠═╡ show_logs = false
begin
	import Pkg
	Pkg.add("PlutoUI")
	Pkg.develop(path="/home/miguel/rcs/jdev/Gaston")
	using Revise
	using Gaston
	using PlutoUI
	pkgversion(Gaston)
end

# ╔═╡ a86a096a-f66b-11ed-3c0d-f3dce992f2d7
md"# Gaston demo/tutorial: 3-D Plots

Let's start by loading needed packages: Gaston."

# ╔═╡ 198a01e0-fa6c-426f-b485-ae2922da121f
PlutoUI.TableOfContents(title = "Contents")

# ╔═╡ af9f5b7f-84ec-4f53-a4ba-df4dd73933b6
Gaston.config.term = "pngcairo font ',10' size 700,400"

# ╔═╡ 1851bc4f-c625-4c14-96b3-c8fce30b2182
md"## 3-D plots

To create a 3-D plot, use the `splot` function or the `@splot` macro. The following examples illustrate their use."

# ╔═╡ 9a92ee79-8db5-4532-ad7b-046700d1cd84
md"##### z values as an array"

# ╔═╡ 5e3d28f4-9500-44ec-82fb-dc6ee8f8d239
let
    z = [10 10 10 10 ;
		 10  5  1  0 ;
		 10 10 10 10 ]
	splot("set title 'A Valley'
		   set hidden3d
	       set view 75, 38",
		  z,
		  "lc 'dark-green'") 
end

# ╔═╡ 97dc9773-310d-44bf-b518-baead81cd252
md"##### x, y vectors or ranges; z an array"

# ╔═╡ 4586bc09-8556-4627-b473-8f168f62bfb5
let
	x = -2:1
    y = [2, 3, 4]
    z = [10 10 10 10 ;
		 10  5  1  0 ;
		 10 10 10 10 ]
	splot("set title 'A Valley'
		   set hidden3d
	       set view 75, 38
	       set xlabel 'x' offset -1.5,-1.5 
	       set ylabel 'y' offset 1,1
	       set zlabel 'z'",
		  x, y, z,
		  "lc 'dark-green'") 
end

# ╔═╡ 6d34cafc-164e-4731-b0fc-0f586bf7e994
md"##### x and y vectors or ranges; z a function"

# ╔═╡ e7697a24-f587-4215-9cfa-5416e0b2627f
let
	x = y = -15:0.4:15
	f1(x,y) = @. sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)
	splot("set title 'Sombrero'
		   set hidden3d",
		  x, y, f1,
		  "lc 'turquoise'") 
end

# ╔═╡ 3dc0145f-49df-4c29-a5e1-12d158f901bc
md"If `x` and `y` are not provided, then `range(-10, 10, 100)` is used by default."

# ╔═╡ b09cfaf6-b56b-4818-bda8-83a9a98e7b6d
md"##### x and/or y tuples; z a function"

# ╔═╡ a73fbdfa-452a-4fbc-821a-1e00046c602d
let
	splot("set hidden3d",
		  (-6, 6, 20), (-3, 3, 20), (x,y) -> cos.(x./2).*sin.(y./2))
end

# ╔═╡ 470f890e-9010-4ee4-abc3-f5c5c73c233b
md"The format is either `(min, max)` or `(min, max, samples)`. The default number of samples is 100. If only one tuple is provided, it's assumed to specify values for both `x` and `y`. The default is `(-10, 10, 100)`."

# ╔═╡ 1ceb96e8-fecb-4f1e-9457-3717532766d9
md"## Plot styles

The following plot styles are provided:

* `surf` and `surf!` to plot surfaces.
* `contour` for contour plots.
* `surfcontour` combines the previous two styles.
* `scatter3` and `scatter3!` for scatter plots.
* `wireframe` and `wireframe!` for wireframe plots.
* `wiresurf` and `wiresurf!` combine a surface and a wireframe.
* `heatmap` is a projection of a surface or 3-D histogram to a plane.

The following examples illustrate these styles."

# ╔═╡ b67cf328-1659-46f4-afcd-d393836035bc
md"##### Surface plots"

# ╔═╡ ebe88c25-eded-4643-aac5-175013a8bd3d
let
	f1(x,y) = sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)
	@gpkw surf({title = "'Sombrero Surface'",
	            hidden3d,
	            palette = :matter},
		        (-15, 15, 200), f1)
end

# ╔═╡ 24893b90-a180-4df2-a5cb-c252920f74d6
md"##### Contour plots"

# ╔═╡ de4c0f15-e0b9-406f-b777-a8eea53491dc
let
	f1(x,y) = cos(x/2)*sin(y/2)
	contour("set title  'Sombrero Contours'", (-10, 10, 50), f1)
end

# ╔═╡ 3ba30e9c-3ce5-4e02-8225-b611f9631675
md"Labels can be removed with the `labels = false` argument:"

# ╔═╡ 426d3c69-d7c2-4bfa-a63d-79da7d0f4c8f
let
	f1(x,y) = cos(x/2)*sin(y/2)
	contour("set title  'Sombrero Contours; no labels'",
		    (-10, 10, 50), f1, labels = false)
end

# ╔═╡ 57e27251-9723-429c-976e-61208dcd61f0
let
	f1(x,y) = @. sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)
	surfcontour("set title 'Sombrero Wireframe and Contours'",
		        (-15, 15, 40), f1, "lc 'orange'")
end

# ╔═╡ 59efd1da-b92d-4edf-b8e1-4ac375cf9485
md"##### Scatter plots"

# ╔═╡ 015d489d-a51d-47ae-8899-4ee04a064ec0
md"Scatter plots use the `points` pointstyle."

# ╔═╡ dbeeaaa0-d0da-455d-b3c5-e1a3405014e0
let
	scatter3("set title 'A 3-D scatter plot",
		     randn(10), randn(10), randn(10))
end

# ╔═╡ 070eb594-80f9-48ed-a416-ef7eeb53a97e
let
	x = 0:0.1:6π
	@splot({title = "'Trigonometric spiral'",
	        colorbox = false,
	        palette = :matter},
		   x, x.*cos.(x), x.*sin.(x), x./10,
	       "with p pt 7 lc palette ps variable")
end

# ╔═╡ 09901ab7-298f-456b-aa92-db1d642c36ce
md"##### Wireframe plots"

# ╔═╡ ebd8dc6f-3d5b-4ce6-992e-41be7a19767d
md"Wireframe plots use the `lines` plotstyle, which is `gnuplot`'s default and is illustraded above. The following example shows how to plot a surface and a wireframe:"

# ╔═╡ c76118f4-9e8f-4c8c-8cce-df23126551c9
let
	f1(x, y) = cos(x/2) * sin(y/2)
	theme = @gpkw {palette = :matter, title = Q"Wiresurf plot"}
	wiresurf(theme, :notics, :labels, (-10, 10, 30), f1)
end

# ╔═╡ d10136b4-b397-4388-9bc6-b3194341a918
md"##### Heatmap plots"

# ╔═╡ 729f87a6-e861-425a-a405-cad1ec4fb320
let
	f1(x, y) = cos(x/2) * sin(y/2)
	theme = @gpkw {palette = :matter, title = Q"Heatmap"}
	heatmap(theme, :notics, :labels, (-10, 10, 70), f1)
end

# ╔═╡ 5f3c4090-417f-4616-b268-735be74fc3ae
md"## Interactivity"

# ╔═╡ 7bc6cd91-ce7c-4800-a36a-ec12dedf5a9d
md"Interaction with notebook sliders and other widgets works in a similar way to regular 2-D plots."

# ╔═╡ dca8473a-dac9-438b-9d86-987bdc1631ba
md"Azimuth: $(@bind az Slider(0:180, default = 115, show_value = true))"

# ╔═╡ 094b2a61-30b8-4739-a125-cb1e1a37dff7
md"Altitude: $(@bind al Slider(0:90, default = 55, show_value = true))"

# ╔═╡ 77843582-1942-471d-987b-4b4a03adfecf
md"""Palette: $(@bind p Select([:viridis => "viridis", :matter => "matter", :ice => "ice", :thermal => "thermal"]))"""

# ╔═╡ 5a5a8dae-526d-4122-856a-f712cfaaf858
let al = al, az = az
	f1(x, y) = cos(x/2) * sin(y/2)
	theme = @gpkw {view = (al, az),
	               palette = p,
				   title = Q"Wiresurf plot"}
	wiresurf(theme, :notics, :labels, (-8, 8, 30), f1)
end

# ╔═╡ 28b107c9-4f20-415e-b68e-d204798c94c8
md"## Animation

Animation works in a similar way to 1-D plots."

# ╔═╡ 40b076e3-92ba-48fe-90bf-f94078370b20
let
	f = Figure()
	function z(x, y, i)
		if 1.8 < atan(y, x)+π < 2.7
			return NaN
		end
		d = sqrt(x*x+y*y)
		i*sin(2d) / d
	end
	x = y = range(-10, 10, 35)
	theme = @gpkw {zrange = (-1.5, 1.5),
	               cbrange = (-0.5, 1),
				   colorbox = false,
	               palette = :matter}
	frames = 20
	for (idx, i) in enumerate(range(-1, 1, frames))
		wiresurf(f[idx], theme, :notics, x, y, (x, y) -> z(x, y, i))
	end
	for (idx, i) in enumerate(range(1, -1, frames))
		wiresurf(f[idx+frames], theme, :notics, x, y, (x, y) -> z(x, y, i))
	end
	animate(f, "gif animate loop 0 size 700,400")
end

# ╔═╡ Cell order:
# ╟─a86a096a-f66b-11ed-3c0d-f3dce992f2d7
# ╠═93b3b71e-0a4e-4165-9f92-b770c06a5964
# ╠═198a01e0-fa6c-426f-b485-ae2922da121f
# ╠═af9f5b7f-84ec-4f53-a4ba-df4dd73933b6
# ╟─1851bc4f-c625-4c14-96b3-c8fce30b2182
# ╟─9a92ee79-8db5-4532-ad7b-046700d1cd84
# ╠═5e3d28f4-9500-44ec-82fb-dc6ee8f8d239
# ╟─97dc9773-310d-44bf-b518-baead81cd252
# ╠═4586bc09-8556-4627-b473-8f168f62bfb5
# ╟─6d34cafc-164e-4731-b0fc-0f586bf7e994
# ╠═e7697a24-f587-4215-9cfa-5416e0b2627f
# ╟─3dc0145f-49df-4c29-a5e1-12d158f901bc
# ╟─b09cfaf6-b56b-4818-bda8-83a9a98e7b6d
# ╠═a73fbdfa-452a-4fbc-821a-1e00046c602d
# ╟─470f890e-9010-4ee4-abc3-f5c5c73c233b
# ╟─1ceb96e8-fecb-4f1e-9457-3717532766d9
# ╟─b67cf328-1659-46f4-afcd-d393836035bc
# ╠═ebe88c25-eded-4643-aac5-175013a8bd3d
# ╟─24893b90-a180-4df2-a5cb-c252920f74d6
# ╠═de4c0f15-e0b9-406f-b777-a8eea53491dc
# ╟─3ba30e9c-3ce5-4e02-8225-b611f9631675
# ╠═426d3c69-d7c2-4bfa-a63d-79da7d0f4c8f
# ╠═57e27251-9723-429c-976e-61208dcd61f0
# ╟─59efd1da-b92d-4edf-b8e1-4ac375cf9485
# ╟─015d489d-a51d-47ae-8899-4ee04a064ec0
# ╠═dbeeaaa0-d0da-455d-b3c5-e1a3405014e0
# ╠═070eb594-80f9-48ed-a416-ef7eeb53a97e
# ╟─09901ab7-298f-456b-aa92-db1d642c36ce
# ╟─ebd8dc6f-3d5b-4ce6-992e-41be7a19767d
# ╠═c76118f4-9e8f-4c8c-8cce-df23126551c9
# ╟─d10136b4-b397-4388-9bc6-b3194341a918
# ╠═729f87a6-e861-425a-a405-cad1ec4fb320
# ╟─5f3c4090-417f-4616-b268-735be74fc3ae
# ╟─7bc6cd91-ce7c-4800-a36a-ec12dedf5a9d
# ╟─dca8473a-dac9-438b-9d86-987bdc1631ba
# ╟─094b2a61-30b8-4739-a125-cb1e1a37dff7
# ╟─77843582-1942-471d-987b-4b4a03adfecf
# ╠═5a5a8dae-526d-4122-856a-f712cfaaf858
# ╟─28b107c9-4f20-415e-b68e-d204798c94c8
# ╠═40b076e3-92ba-48fe-90bf-f94078370b20


================================================
FILE: docs/notebook/tutorial-essentials.jl
================================================
### A Pluto.jl notebook ###
# v0.20.10

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    #! format: off
    return quote
        local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
        el
    end
    #! format: on
end

# ╔═╡ ccdce6f8-f1d8-11ed-19e9-fddf2407113b
import Pkg

# ╔═╡ 7076fc20-8f0c-449c-9cfc-edf9801e85cd
# ╠═╡ show_logs = false
Pkg.add("PlutoUI")

# ╔═╡ c55fca39-9251-4593-b7f4-4342119e76e1
# ╠═╡ show_logs = false
Pkg.develop(path="/home/miguel/rcs/jdev/Gaston")

# ╔═╡ a64f470c-a8d3-4c28-99f4-8149ac65ff58
using Revise

# ╔═╡ 93d7c222-6755-4b71-b4cb-3ad82f4515f1
using Gaston

# ╔═╡ dab403c8-f4ae-4029-a8c8-ef5ae161142c
using PlutoUI

# ╔═╡ d4e94a70-866a-46e2-98c2-6babc7745fd2
md"# Gaston demo/tutorial: Essentials

Let's start by loading Gaston and PlutoUI."

# ╔═╡ ff57c40b-615d-4902-9810-8d874220f626
pkgversion(Gaston)

# ╔═╡ a66e7e1d-b3a4-4504-be15-2324808607be
PlutoUI.TableOfContents(title = "Contents")

# ╔═╡ 1a521882-7ee0-413d-9738-3a025499883e
md"## Introduction to Gaston

Gaston is a plotting package for Julia. It provides an interface between Julia and [gnuplot](https://gnuplot.info). Gaston has two main functions:
* Convert Julia data variables to gnuplot's format.
* Provide plot commands with familiar syntax, e.g. `plot(x, y)`.
It also provides some additional functionality:
* Manage multiple figures simultaneously.
* Work seamlessly in notebooks.
* Convenient syntax for configuring gnuplot.
* Recipes (styles) for common plot types.
* Lightweight themes.
* Can be extended to plot user-defined data types.
Familiarity with both Julia and gnuplot is assumed throughout the documentation.
"

# ╔═╡ 8f50fd19-5ce4-447e-a7f9-7b16d59af6c0
md"""## Basic syntax

The `plot` function is Gaston's workhorse for 1-D plotting. It takes three different kinds of arguments, in order: axis settings, data, and curve settings. Axis settings correspond to gnuplot's `set` commands, while curve settings determine how a curve is plotted (its color, width, markers, etc.)

Axis settings and curve settings are strings; any number of them can be used. The signature of `plot` is:

    plot(axis_settings..., data..., curve_settings...)

For example, the command

    plot("set title 'a plot'", "set grid", x, y, "w p lc 'green'")

is converted to the following sequence of gnuplot commands:

    set title 'a plot'
    set grid
    plot '/tmp/data' w p lc 'green'

where `x` and `y` are written to the temporary file `data` in the format gnuplot expects.
"""

# ╔═╡ ab0aba7c-d841-44bb-8e6a-2e5515ef9aa5
md"## Configuring the terminal

When working in a notebook (whether Juno, IJulia, Pluto or VS Code), the terminal is automatically set to `pngcairo`. This terminal is very good for plotting on a notebook, since it's very fast and produces small files. We still want to configure the terminal ourselves, though, to set a good plot size (in pixels) and font size. This is done as follows:"

# ╔═╡ 0e8236b4-6d1f-46ae-9c0e-ee1d4f605c0d
Gaston.config.term = "pngcairo font ',10' size 700,400"

# ╔═╡ fc31bafd-eb7b-4204-b781-6e06cf95fd25
md"## 2-D plots

### Plotting coordinates

Following are some examples of basic plots, with different data arguments.

##### Only `y` is given

The `x` coordinates are implicitly defined as the range `firstindex(y):lastindex(y)`."

# ╔═╡ 804b8b60-8976-43a3-a5b7-86cedf9118e4
plot(rand(10))

# ╔═╡ e467671a-62a2-406d-99e4-9ecfa7f55b5e
md"##### Both `x` and `y` are given"

# ╔═╡ a25f483f-f5c7-4949-9690-3d126a12e86a
plot(range(0, 1, length=10), rand(10))

# ╔═╡ 26fe4805-3b08-4750-b0f8-f210a72a502b
md"##### Multiple columns

Many `gnuplot` plot styles take multiple columns. Each data argument to `plot` is interpreted as a column, and you can use as many as you need:"

# ╔═╡ 21e1f17f-4fb2-490e-ade7-77725fb24f61
let
	x = 1:10
	boxmin = 0.1*rand(10) .+ 0.2
	whiskmin = boxmin .- 0.1*rand(10)
	boxmax = boxmin .+ 0.5*rand(10)
	whiskmax = boxmax .+ 0.2*rand(10)
	ym = minimum(whiskmin)-0.1
	yM = maximum(whiskmax)+0.1
	plot("set yrange [$ym:$yM]
	      set boxwidth 0.3 relative
	      set style fill solid 0.25
	      set title 'A random candlesticks plot'",
	      x, boxmin, whiskmin, whiskmax, boxmax,
	      "w candlesticks whiskerbars 0.75")
end

# ╔═╡ cedb6fa7-e8c7-4a48-8935-1ce6385f1185
md"### Plotting functions

##### Only a function is given

When a function is passed to `plot`, the function is first evaluated in the range from -10 to 10, with 100 samples."

# ╔═╡ 8a50be7a-bcfa-468c-914a-9b1aa2c970ad
fun(x) = exp(-abs(x/8))*cos(x)

# ╔═╡ 6d72504e-fede-41a6-bfef-0aef52936e1b
plot(fun)

# ╔═╡ e15e224f-834c-459e-b355-15d1fb8975fb
md"##### A function and a range

The range can be given explicitly as `(start, stop)`; the function is still sampled 100 times."

# ╔═╡ 162ccb40-92b0-43fe-a89e-676864ac9883
plot((-1, 5), fun)

# ╔═╡ 0b229ed3-868a-42d3-b669-6cacaf213c90
md"The number of samples can be specified with `(start, stop, samples)`."

# ╔═╡ fbce3eb9-6691-4945-ac6b-4b0bcf31e003
plot((-1, 5, 10), fun)

# ╔═╡ 262faf7b-ac62-45d9-bc18-3860e6e10fb7
md"### Plotting multiple curves

To plot multiple curves on the same axis, use `plot!`.

(Note that `plot!` ignores any provided axis settings, which must be specified with `plot`)."

# ╔═╡ 57f66b17-8c2d-4737-84e1-c456a7dacc89
begin
	plot("set key box top left", fun, "lc 'dark-green' title 'fun'")
	plot!(cos, "lc 'orange' title 'cos'")
end

# ╔═╡ a0762a24-26be-40a6-a333-92bd8999a5a3
md"### Plot styles

The following commands plot data with a specific plot style:
* `scatter`, `scatter!`
* `stem`, `stem!`
* `bar`, `bar!`
* `barerror`, `barerror!`
* `histogram`
* `imagesc`
The following examples illustrate these styles."

# ╔═╡ d66d3ef3-130f-45a7-81d6-0cac24e9b1d2
md"##### Scatter plot"

# ╔═╡ 4f145f29-f99d-4f36-9ebf-5cc632f956c1
let
	xg = randn(20)
	yg = randn(20)
	scatter("set title 'Scatter plot'
	         set key outside",
		    xg, yg,
		    "title 'gaussian'")
	xu = rand(20)
	yu = rand(20)
	scatter!(xu, yu, "title 'uniform'")
end

# ╔═╡ 970fd5da-91e2-44bb-a427-6823b03c79e9
md"##### Stem plot"

# ╔═╡ 881e794d-bc5e-49d0-b240-2cb58abe82ce
stem("set title 'stem plot'", fun)

# ╔═╡ 996ef179-f5fd-4345-a6af-a74709bd2a6b
md"Avoid printing the circular marks with the `onlyimpulses` argument."

# ╔═╡ f395e87b-39f6-4f79-83b1-1b44bcb37feb
stem("set title 'only impulses'", fun, onlyimpulses = true)

# ╔═╡ 9db5812e-47a3-4b17-b3f0-9e74a38e3f54
md"##### Bar plots

`bar` uses gnuplot's `with boxes` style."

# ╔═╡ 061a881c-220c-4183-8f5b-12fd91a8f358
bar("set title 'bar plot'", rand(10), "lc 'turquoise'")

# ╔═╡ 8c14838e-fcb6-4b49-83cd-a3ef5f267b24
let
	bar("set title 'Two bar plots'",
        rand(10),
		"lc 'dark-violet'")
	bar!(1.5:10.5, 0.5*rand(10), "lc 'plum' fill pattern 4")
end

# ╔═╡ be09ba73-cabb-40ce-aa06-6bfe0705f6e2
md"`barerror` uses gnuplot's `boxerrorbars` style."

# ╔═╡ 33731005-bb8c-48a9-863a-93e25d579930
barerror("set title 'Error bars'",
         1:10, rand(10), 0.1*rand(10).+0.1,
         "lc 'sandybrown'")

# ╔═╡ 906770c9-07bd-4447-af21-de487c7a1e02
md"##### Histograms

The `histogram` function takes these keyword arguments:
* `nbins`: specifies the number of bins. Defaults to 10.
* `norm::Bool`: if `true`, the area of the histogram is normalized.
* `mode::Symbol`: Controls histogram normalization mode; passed to [`StatsBase.normalize`](https://juliastats.org/StatsBase.jl/stable/empirical/#LinearAlgebra.normalize). Defaults to `:pdf`, which makes the histogram area equal to 1.
* `edges`: a vector or a range specifying the bin edges; takes precedence over `nbins`.
* `horizontal::Bool`: if `true`, the histogram is drawn horizontally.
2-D histograms are supported, by passing two datasets.
"

# ╔═╡ 38a71681-dc2d-4af5-be14-1682924abf51
histogram("set title 'histogram (nbins)'",
	      randn(10_000), nbins = 20, norm = true)

# ╔═╡ 5c25b0e3-9a45-4ad5-92ae-314cfce5c117
histogram("set title 'histogram (edges)'",
	      randn(10_000), edges = -5:5,
          "lc 'dark-khaki'")

# ╔═╡ 4f4fb009-cf62-4e64-a519-77f340f83f69
histogram("set title 'horizontal histogram'",
	      rand(1000), nbins = 10, horizontal = true,
          "lc 'orchid'")

# ╔═╡ 84ccf2ff-472b-4b34-9472-2006f70684e6
md"In the case of 2-D histograms, `nbins` or `egdes` may be a tuple; otherwise, both axes use the same configuration."

# ╔═╡ b42213a1-f27a-4c96-a6a7-b5a8a200ef19
let
	x = randn(100_000)
	y = randn(100_000)
	histogram("set palette gray
	           unset colorbox
	           set title '2-D histogram'",
		      x, y, nbins = 50, norm = true)
end

# ╔═╡ e1e93d06-4565-4625-8fcf-fe8dbc9fe55e
md"##### Images"

# ╔═╡ 8ab2a66a-df03-4aeb-a736-1336b75dadaa
md"Arrays may be plotted as images using `imagesc`. Note that, in contrast to other plotting packages, the array columns are plotted with the first row at the top."

# ╔═╡ ca7554bc-6f9c-4574-bf78-20afd42dc647
let
	X = [0 1 2 3;
	     0 3 2 1;
	     0 2 2 0;
	     3 0 0 0]
	imagesc("unset tics", X)
end

# ╔═╡ 5acd956b-e22d-4638-be19-1ad090cac7d2
md"""## Plot options

Gnuplot provides many possibilities to fine-tune a plot. There are two main kinds of configuration options:
* Axes-wide options, corresponding to `set` commands; for example, `set grid` turns on the grid.
* Specific curve settings, such as line width and color; for example, `with points linecolor 'red'`.

Gaston provides a few different ways to specify these plot options. In all cases, axes-wide options come before the data to plot, and curve-specific options come afterward.

One way to specify the options is with strings enclosing `gnuplot` commands:
"""

# ╔═╡ 20a9dc74-0324-4d76-88fa-1c55ac281e5e
plot("set title 'A nice sinusoid'
	  set key box left
      unset grid
      set xlabel 'time'
      set ylabel 'voltage'",
	  sin,
      "w points lc 'orange' title 'sin'")

# ╔═╡ a0720ae4-8da5-4ed6-acd9-0471b840fa1d
md"Options may also be given using the following syntax:"

# ╔═╡ dc989e43-20ad-4f03-86a3-655c00c02a4e
@plot({title = "'Another sinusoid'",
        key = "box left",
        grid = false,
        xlabel = "'time'",
        ylabel = "'voltage'"
	   },
       sin,
       {w = "points",
        lc = "'orange'",
        title = "'sin'"
       })

# ╔═╡ 564caa1c-222f-4655-9505-162f5e23b234
md"""##### Axis-wide options

For axis-wide options (first argument to `@plot` above), `{option = value}` is converted to `"set option value"`. To unset an option, set it to false: `{tics = false}` is converted to `unset tics`.

Curve-specific options (last argument to `@plot` above) are handled similary, but they are used to "build" the plot command given to `gnuplot`.

This syntax offers some convenience features:
* Specify a range as a tuple: `{xrange = (1, 2)}` is converted to `set xrange [1:2]`, while `{yrange = (-Inf, 5)}` is converted to `set yrange [*:5]`.
* To set all ranges (`x`, `y`, `z` and `cb`) simultaneously, use `{ranges = (min, max)}`.
* Specify tics conveniently:
    * `{xtics = 1:2}` is equivalent to `set xtics 1,1,2`
    * `{ztics = 1:2:7})` to `set ztics 1,2,7`
    * `{tics = (0,5)}` to `set tics (0, 5)`
    * `{tics = (labels = ("one", "two"), positions = (0, 5))}` to `set tics ('one' 0, 'two' 5, )`
* Specify a color palette from [Colorschemes.jl](https://juliapackages.com/p/colorschemes). For example, `{palette = :viridis}` is converted to a `set palette` command with the appropriate colors. The palette name must be given as a symbol.
    * To reverse the palette order, specify it as `{palette = (:viridis, :reverse)}`.
* You may also use any custom palette (for example, one created with `ColorSchemes.resample)`
* A line type may be specified similary: `{lt = :viridis}`.
* In 3D plots, specify the view as a tuple: `{view = (50, 60)}` is converted to `set view 50, 60`.
* Specify margins, useful for multiplot with arbitrary layouts: `{margins = (0.33, 0.66, 0.2, 0.8)}` is converted to `set lmargin at screen 0.33...`. The margins are specified in the order left, right, bottom, top.

An option may be specified more than one time: `{tics, tics = 1:2}` is converted to

    set tics
    set tics 1,1,2

Any number of option arguments may be given before the data to plot, and they will be combined.
"""

# ╔═╡ 52a654cf-9aac-47ba-82d4-6d7b4320d79e
md"Options can also be given as `gnuplot` commands in strings:"

# ╔═╡ 44930880-7dd2-4120-b097-6c19f8e7022a
@plot({title = "'A nice sinusoid'"}, "set key box left", {grid = false},
       "set xlabel 'time'\nset ylabel 'voltage'",
	   sin,
	   {w = "points"}, "lc 'orange' title 'sin'")

# ╔═╡ 5809cde8-fa4d-49a5-bc4f-4baa0133b21f
md"""##### Quoted strings

String arguments given to gnuplot must be quoted. To simplify this, the `@Q_str` string macro might come in handy. The string `Q"a title"` is converted to `"'a title'"`."""

# ╔═╡ 1b7dfb67-6047-40fa-9b91-c48aa8e8aa9c
@plot({title = Q"A nice sinusoid"}, "set key box left", {grid = false},
       {xlabel = Q"time", ylabel = Q"voltage"},
	   sin,
	   {w = "points"}, "lc 'orange' title 'sin'")

# ╔═╡ beb2b6cd-ee6b-4bd8-bf8e-5d071adbd857
md"""##### Curve-specific options

These options affect the way a curve is plotted (line style, color, etcetera), and may be specified as a string (which is passed directly to `gnuplot`) and/or as a set of options inside `{}` brackets. These options are passed to `gnuplot` as part of the `plot` command. For example, `@plot sin {with = "points", lc = Q"red"}` is converted to a `gnuplot` command `plot <datafile> with points lc 'red'`.

When using the bracketed options format, the following convenient syntax is available:
* `marker` is available as synonym of `pointtype`
* `markersize` and `ms` are available as synonyms of `pointsize`.
* `legend` is available as a synonym of `title`.
* `plotstyle` is a synonym of `with`.
* A point type may be specified by name (instead of just by number as in native `gnuplot`):
| name | gnuplot pt number |
|-----:|:------------------|
| dot | 0 |
| ⋅ | 0 |
| + | 1 |
|  plus     | 1 |
|  x        | 2 |
|  *        | 3 |
|  star     | 3 |
|  esquare  | 4 |
|  fsquare  | 5 |
|  ecircle  | 6 |
|  fcircle  | 7 |
|  etrianup | 8 |
|  ftrianup | 9 |
|  etriandn | 10 |
|  ftriandn | 11 |
|  edmd     | 12 |
|  fdmd     | 13 |
Here a prefix "e" stands for "empty", "f" for "full"; "up" and "dn" stand for "pointing up" and "pointing down"; "trian" is a triangle and "dmd" is a diamond (rhombus). Note that this mapping of marker shapes to numbers is compatible with the most popular `gnuplot` terminals, but the specific mapping may be different for a given terminal.
"""

# ╔═╡ ea4e84ab-4820-4f91-8782-3bfc3ef4ba6a
md"""##### Themes

It is possible to create themes with the `@gpkw` macro (stands for "gnuplot keywords"):"""

# ╔═╡ 1c0d72b4-992a-4a0e-b9bc-24a62a26da02
let
	theme = @gpkw {grid, xlabel = "'x'", ylabel = Q"voltage"}
	@plot(theme, sin)
end

# ╔═╡ 59fd1827-6592-473a-9baf-e17c4c93adb4
md"""A couple of lightweight themes are included:

|Axis themes | Description |
|-----------:|:------------|
| :notics | Removes all tics |
| :labels | Generic axis labels |
| :nocb | Removes the colorbox |
| :unitranges | Set all ranges to `[-1:1]` |

Note that `plot` accepts any number of option arguments. Arguments before data are assumed to correspond to `gnuplot` `set` commands; arguments after the data affect the curve attributes.
"""

# ╔═╡ 83d697a8-3a33-4d37-a173-c31309c112e3
md"## Interactivity"

# ╔═╡ afc4dfba-eb72-42de-aec0-d68cf20514be
md"In a notebook, it is easy to tie plot variables to sliders or other UI elements."

# ╔═╡ 8c124c3d-d444-41d6-8187-6058f4b5808f
md"""Frequency: $(@bind freq Slider(1:10, default = 5, show_value = true))"""

# ╔═╡ c2bc72a9-e96d-4216-92dd-71a0e51a647d
md"""Line color: $(@bind color Select(
                   ["'red'" => "red",
                    "'blue'" => "blue",
                    "'orange'" => "orange",
                    "'dark-green'" => "dark green",
                    "'chartreuse'" => "chartreuse"]))"""

# ╔═╡ d253f4ea-b633-4255-8308-e1182c680df2
plot((-1, 1, 200), t -> sin(2π*freq*t), "lw 2 lc $(color)")

# ╔═╡ 6245bfd6-a945-4e84-825d-57fbaa63ffd1
md"## Multiplot"

# ╔═╡ 80e46def-fb34-426a-9883-18a8e99e72ce
md"A multiplot can be easily generated and automatically laid out by adding more axes to an existing figure:"

# ╔═╡ 52e760d6-3848-4705-a9d2-5968e2ad9b03
begin
	f = Figure() # create an empty figure
	plot(sin)
	plot(f[2], cos) # figures are row-major
	plot(f[3], (1:10).^2) # Gaston adjusts the layout as the number of
	plot(f[4], rand(10))  #  suplots grows.
end

# ╔═╡ 91cbc979-b191-45cd-8aba-2ecc31f09a38
md"Add another plot to a subplot using indexing:"

# ╔═╡ 379428f6-1007-457c-95ad-7f090947f72a
plot!(f[4], randn(10))

# ╔═╡ 4779cbbb-9b02-4ffa-b393-c19d0423a967
md"Full control over gnuplot multiplot options can be obtained using margins, as follows:"

# ╔═╡ 6ae49346-1bc5-46dc-9fb1-7530f6606474
let
	f = Figure(multiplot = "title 'Arbitrary layout demo'", autolayout = false)
	x = randn(100)
	y = randn(100)
	@plot({margins = (0.1, 0.65, 0.1, 0.65)},
	      x, y,
	      "w p pt '+' lc 'dark-green'")
	@gpkw histogram(f[2],
	                {margins = (0.7, 0.9, 0.1, 0.65), tics = false},
	                y,
	                {lc = Q"dark-green"},
	                nbins = 10, horizontal = true)
	@gpkw histogram(f[3],
	                {margins = (0.1, 0.65, 0.7, 0.9),
	                boxwidth = "1 relative"},
	                x,
	                {lc = "'dark-green'"},
					nbins = 10)
end

# ╔═╡ c860dea5-1a8a-4516-98d6-97122962345d
md"## Animations

Animations require use of a terminal that supports it (such as `gif` or `webp`). Make sure your notebook supports the `webp` file format before using it. Gif is supported almost everywhere.

Creating an animation is similar to multiplotting: multiple axes are drawn on the same figure. When using the `animate` option of the `gif` or `webp` terminals, however, the plot is rendered as an animation.

Note that `gnuplot` will output a message to STDERR indicating how many frames were recorded; this message is purely informative and not actually an error.

A difficulty arises when mixing plot formats in a notbook (say, `png` and `gif`): the terminal is specified in the global variable `Gaston.config.term`; however, Pluto executes cells in arbitrary order. This means that changing the terminal in one cell may affect other cells.

To solve this problem, `Gaston` provides a way to ignore the global terminal configuration when rendering a plot. A figure `f` can be rendered with a given terminal by calling `animate(f, term)`. The default value of `term` is stored in `Gaston.config.altterm` and defaults to `gif animate loop 0`.

The following examples illustrate how to create and display animations in a notebook:"

# ╔═╡ 5895f542-8a5b-42a4-a1d6-6e4103a71308
let
	f = Figure()
	frames = 20
	x = range(-1, 1, 200)
	ϕ = range(0, 2π-1/frames, frames)
	for i = 1:frames
		plot(f[i], x, sin.(5π*x .+ ϕ[i]), "lw 2")
	end
	animate(f, "gif animate loop 0 size 700,400")
end

# ╔═╡ 4f0391b9-fdf3-48f1-9cb5-9c722ff89c6c
md"A background can be included in an animation as follows:"

# ╔═╡ 42da1eb0-23f6-4f13-8107-a8a6063e87ef
let
	f = Figure()
	frames = 75
	x_bckgnd = range(-1, 1, 200)
	bckgnd = Gaston.Plot(x_bckgnd, sin.(2π*2*x_bckgnd), "lc 'black'")
	x = range(-1, 1, frames)
	for i in 1:frames
		plot(f[i], x[i], sin(2π*2*x[i]), "w p lc 'orange' pt 7 ps 7")
		push!(f[i], bckgnd)
	end
	for i in frames:-1:1
		plot(f[2frames-i+1], x[i], sin(2π*2*x[i]),
			 "w p lc 'orange' pt 7 ps 7")
		push!(f[2frames-i+1], bckgnd)
	end
	animate(f, "gif animate loop 0 size 700,400")
end

# ╔═╡ Cell order:
# ╟─d4e94a70-866a-46e2-98c2-6babc7745fd2
# ╠═ccdce6f8-f1d8-11ed-19e9-fddf2407113b
# ╠═7076fc20-8f0c-449c-9cfc-edf9801e85cd
# ╠═c55fca39-9251-4593-b7f4-4342119e76e1
# ╠═a64f470c-a8d3-4c28-99f4-8149ac65ff58
# ╠═93d7c222-6755-4b71-b4cb-3ad82f4515f1
# ╠═ff57c40b-615d-4902-9810-8d874220f626
# ╠═dab403c8-f4ae-4029-a8c8-ef5ae161142c
# ╠═a66e7e1d-b3a4-4504-be15-2324808607be
# ╟─1a521882-7ee0-413d-9738-3a025499883e
# ╟─8f50fd19-5ce4-447e-a7f9-7b16d59af6c0
# ╟─ab0aba7c-d841-44bb-8e6a-2e5515ef9aa5
# ╠═0e8236b4-6d1f-46ae-9c0e-ee1d4f605c0d
# ╟─fc31bafd-eb7b-4204-b781-6e06cf95fd25
# ╠═804b8b60-8976-43a3-a5b7-86cedf9118e4
# ╟─e467671a-62a2-406d-99e4-9ecfa7f55b5e
# ╠═a25f483f-f5c7-4949-9690-3d126a12e86a
# ╟─26fe4805-3b08-4750-b0f8-f210a72a502b
# ╠═21e1f17f-4fb2-490e-ade7-77725fb24f61
# ╟─cedb6fa7-e8c7-4a48-8935-1ce6385f1185
# ╠═8a50be7a-bcfa-468c-914a-9b1aa2c970ad
# ╠═6d72504e-fede-41a6-bfef-0aef52936e1b
# ╟─e15e224f-834c-459e-b355-15d1fb8975fb
# ╠═162ccb40-92b0-43fe-a89e-676864ac9883
# ╟─0b229ed3-868a-42d3-b669-6cacaf213c90
# ╠═fbce3eb9-6691-4945-ac6b-4b0bcf31e003
# ╟─262faf7b-ac62-45d9-bc18-3860e6e10fb7
# ╠═57f66b17-8c2d-4737-84e1-c456a7dacc89
# ╟─a0762a24-26be-40a6-a333-92bd8999a5a3
# ╟─d66d3ef3-130f-45a7-81d6-0cac24e9b1d2
# ╠═4f145f29-f99d-4f36-9ebf-5cc632f956c1
# ╟─970fd5da-91e2-44bb-a427-6823b03c79e9
# ╠═881e794d-bc5e-49d0-b240-2cb58abe82ce
# ╟─996ef179-f5fd-4345-a6af-a74709bd2a6b
# ╠═f395e87b-39f6-4f79-83b1-1b44bcb37feb
# ╟─9db5812e-47a3-4b17-b3f0-9e74a38e3f54
# ╠═061a881c-220c-4183-8f5b-12fd91a8f358
# ╠═8c14838e-fcb6-4b49-83cd-a3ef5f267b24
# ╟─be09ba73-cabb-40ce-aa06-6bfe0705f6e2
# ╠═33731005-bb8c-48a9-863a-93e25d579930
# ╟─906770c9-07bd-4447-af21-de487c7a1e02
# ╠═38a71681-dc2d-4af5-be14-1682924abf51
# ╠═5c25b0e3-9a45-4ad5-92ae-314cfce5c117
# ╠═4f4fb009-cf62-4e64-a519-77f340f83f69
# ╟─84ccf2ff-472b-4b34-9472-2006f70684e6
# ╠═b42213a1-f27a-4c96-a6a7-b5a8a200ef19
# ╟─e1e93d06-4565-4625-8fcf-fe8dbc9fe55e
# ╟─8ab2a66a-df03-4aeb-a736-1336b75dadaa
# ╠═ca7554bc-6f9c-4574-bf78-20afd42dc647
# ╟─5acd956b-e22d-4638-be19-1ad090cac7d2
# ╠═20a9dc74-0324-4d76-88fa-1c55ac281e5e
# ╟─a0720ae4-8da5-4ed6-acd9-0471b840fa1d
# ╟─dc989e43-20ad-4f03-86a3-655c00c02a4e
# ╟─564caa1c-222f-4655-9505-162f5e23b234
# ╟─52a654cf-9aac-47ba-82d4-6d7b4320d79e
# ╠═44930880-7dd2-4120-b097-6c19f8e7022a
# ╟─5809cde8-fa4d-49a5-bc4f-4baa0133b21f
# ╠═1b7dfb67-6047-40fa-9b91-c48aa8e8aa9c
# ╟─beb2b6cd-ee6b-4bd8-bf8e-5d071adbd857
# ╟─ea4e84ab-4820-4f91-8782-3bfc3ef4ba6a
# ╟─1c0d72b4-992a-4a0e-b9bc-24a62a26da02
# ╟─59fd1827-6592-473a-9baf-e17c4c93adb4
# ╟─83d697a8-3a33-4d37-a173-c31309c112e3
# ╟─afc4dfba-eb72-42de-aec0-d68cf20514be
# ╟─8c124c3d-d444-41d6-8187-6058f4b5808f
# ╟─c2bc72a9-e96d-4216-92dd-71a0e51a647d
# ╠═d253f4ea-b633-4255-8308-e1182c680df2
# ╟─6245bfd6-a945-4e84-825d-57fbaa63ffd1
# ╟─80e46def-fb34-426a-9883-18a8e99e72ce
# ╠═52e760d6-3848-4705-a9d2-5968e2ad9b03
# ╟─91cbc979-b191-45cd-8aba-2ecc31f09a38
# ╠═379428f6-1007-457c-95ad-7f090947f72a
# ╟─4779cbbb-9b02-4ffa-b393-c19d0423a967
# ╠═6ae49346-1bc5-46dc-9fb1-7530f6606474
# ╟─c860dea5-1a8a-4516-98d6-97122962345d
# ╠═5895f542-8a5b-42a4-a1d6-6e4103a71308
# ╟─4f0391b9-fdf3-48f1-9cb5-9c722ff89c6c
# ╠═42da1eb0-23f6-4f13-8107-a8a6063e87ef


================================================
FILE: docs/v1/2d-gallery.md
================================================
# [2-D Gallery](@id twodeegal)

(Many of these examples taken from, or inspired by, [@lazarusa's amazing gallery](https://lazarusa.github.io/gnuplot-examples/gallery/))

# Glowing curves
```@example 2dgal
using Gaston # hide
set(reset=true) # hide
set(termopts="size 550,325 font 'Consolas,11'") # hide
x = 0:0.3:4
a = exp.(- x)
b =  exp.(- x.^2)
plot(x, a, curveconf = "w lp lw 1 lc '#08F7FE' pt 7 t 'e^{-x}'",
     Axes(object="rectangle from screen 0,0 to screen 1,1 behind fc 'black' fs solid noborder",
          border="lw 1 lc 'white'",
          xtics="textcolor rgb 'white'",
          ytics="textcolor rgb 'white'",
          ylabel="'y' textcolor 'white'",
          xlabel="'x' textcolor 'white'",
          grid="ls 1 lc '#2A3459' dt 4",
          key="t r textcolor 'white'",
          style="fill transparent solid 0.08 noborder")
    )
plot!(x, b, curveconf = "w lp lw 1 lc '#FFE64D' pt 7 t 'e^{-x^2}'")
for i in 1:10
       plot!(x,a,w="l lw $(1 + 1.05*i) lc '#F508F7FE' t ''")
       plot!(x,b,w="l lw $(1 + 1.05*i) lc '#F5FFE64D' t ''")
end
plot!(x, a, curveconf = "w filledcu y=0 lw 1 lc '#08F7FE' t ''")
plot!(x, a, supp= b , curveconf = "w filledcu lw 1 lc '#FFE64D' t ''")
```

# Volcano data

```@example 2dgal
using RDatasets
volcano = Matrix{Float64}(dataset("datasets", "volcano"))
imagesc(volcano,
        Axes(palette = :inferno,
             auto="fix",
             size="ratio -1",
             title = "'Aukland s Maunga Whau Volcano'")
       )
```

# Animation

An animation can be produced by pushing new plots into an existing plot, and then saving the result as a GIF the the `animate` option.

```julia
closeall()  #hide
t = 0:0.01:2π
f(t,i) = sin.(t .+ i/10)
ac = Axes(title = :Animation, xlabel = :x, ylabel = :y);  # axes configuration
cc = "w l lc 'black' notitle"  # curve configuration
F = plot(t, f(t,1), curveconf = cc, ac);  # create the first frame, with handle 1
for i = 2:50
    pi = plot(t, f(t,i), curveconf = cc, ac, handle=2) # frames, with handle 2
    push!(F, pi)  # push the frame to F
end
save(term = "gif", saveopts = "animate size 600,400 delay 1",
     output="anim.gif", handle=1)
```

![](assets/anim.gif)

# Color from palette

```@example 2dgal
x = -2π:0.05:2π
plot(x, sin.(3x), supp = x, curveconf = "w l notitle lw 3 lc palette",
     Axes(palette = :ice)
    )
```

# Categorical data

```@example 2dgal
using RDatasets
dset = dataset("datasets", "iris")
byCat = dset.Species
categ = unique(byCat)
ac = Axes(linetype = :tab10,
          xlabel = "'Sepal length'",
          ylabel = "'Sepal width'",
          auto = "fix",
          title = "'Iris dataset'",
          key = "b r font ',9' tit 'Species' box")
c = categ[1]
indc = findall(x -> x == c, byCat)
p = plot(dset.SepalLength[indc], dset.SepalWidth[indc],
         ac, curveconf = "w p tit '$(c)' pt 7 ps 1.4 ")
c = categ[1]
indc = findall(x -> x == c, byCat)
P = plot(dset.SepalLength[indc], dset.SepalWidth[indc],
         ac, curveconf = "w p tit '$(c)' pt 7 ps 1.4 ");
c = categ[2]
indc = findall(x -> x == c, byCat)
plot!(dset.SepalLength[indc], dset.SepalWidth[indc],
      curveconf = "w p tit '$(c)' pt 7 ps 1.4 ");
c = categ[3]
indc = findall(x -> x == c, byCat)
plot!(dset.SepalLength[indc], dset.SepalWidth[indc],
      curveconf = "w p tit '$(c)' pt 7 ps 1.4 ");
P
```

# Vector fields (arrow plots)

Vector fields can be plotted with the `vectors` plot style. The arrows' `x` and `y` coordinates need to be specified in supplementary columns.

```@example 2dgal
x = range(0, 6π, length = 50)
A = range(0, 2, length = 50)
xdelta = A./7.0.*rand(50)
ydelta = A./3.0.*rand(50)
plot(A.*cos.(x), A.*sin.(x), supp = [xdelta ydelta], w = :vectors, lc = "'dark-turquoise'")
```

# Violin plots

A violin plot is created by plotting `(y, x)` instead of `(x, y)`, using the `filledcurves` style, and mirroring the plot.

```@example 2dgal
x = range(0, 5, length=100)
y = 2cos.(x) + sin.(2x) + 0.5cos.(3x) - sin.(4x) .+ 3
M = maximum(y)
plot(y, x, w = "filledcurves x = $M", lc = :turquoise,
     Axes(title = "'Violin plot'"))
plot!(-y .+ 2M, x, w = "filledcurves x = $M", lc = :turquoise)
```

Violin plot with a superimposed boxplot:

```@example 2dgal
plot(y, x, w = "filledcurves x = $M", lc = :turquoise,
     Axes(title     = "'Violin plot'",
          style     = "fill solid bo -1",
          boxwidth  = 0.075,
          errorbars = "lt black lw 1"))
plot!(-y .+ 2M, x, w="filledcurves x = $M", lc=:turquoise)
plot!(x, y, w = "boxplot", u = "($M):2", fc = :white, lw = 2)
```

# Plotting times/dates

The key to plotting dates and times is converting them to strings, and then telling gnuplot what the format is, using `timefmt`. In Julia, dates and times are defined in module `Dates`. This example is inspired by [this gnuplot demo](http://gnuplot.sourceforge.net/demo_5.2/timedat.html).

```@example 2dgal
using Dates
dates = [DateTime(2013,6,1,0,0),
                DateTime(2013,6,10,9,30),
                DateTime(2013,6,18,13,05),
                DateTime(2013,7,4,20,35),
                DateTime(2013,7,13,17,18)]
concentrations = [0.2, 0.3, 0.5, 0.38, 0.18]
x = Dates.format.(dates, "dd/mm/yy HHMM")
plot(x, values, u = "1:3",
     Axes(xdata   = "time",
          timefmt = "'%d/%m/%y %H%M'",
          style   = "data fsteps",
          format  = "x \"%d/%m\\n%H:%M\"",
          xlabel  = "\"Date\\nTime\"",
          ylabel  = "\"Concentration\\nmg/l\"",
          title   = "'Plot with date and time as x-values'",
          key     = "right"))
plot!(x, values, u="1:3", w=:p, marker="esquare", legend = "'Total P'")
```

# Displaying a flag with bars

This example shows how one can use `set palette defined` to associate particular colors with numerical values.

```@example 2dgal
imagesc([0 0.5 1 ; 0 0.5 1],
        Axes(palette="defined (0 'blue', 0.5 'white', 1 'red')",
             colorbox=:off))
```


================================================
FILE: docs/v1/2dplots.md
================================================
# [2-D plotting tutorial](@id twodeetut)

This section provides a brief tutorial on 2-D plotting, with examples on how to obtain common plot types. For full details, we refer the reader to gnuplot's documentation.

## Basics of plotting

A call to `plot` looks like this:

    plot(x, y, z, supp, curvekwargs..., Axes(axeskwargs...))

`x`, `y`, `z` and `supp` are the data to plot. Only `y` is mandatory for 2-D plots. For most plots, vectors are plotted, but plotting images requires a matrix or 3-D array. `supp` is a keyword argument used for supplementary data, which are additional columns that gnuplot can use, such as the errorbar length, or the marker size. Gaston translates the provided data to the format that gnuplot requires, and writes it to a temporary file.

`curvekwargs` is a set of keyword arguments that are related to the appearance of the plotted data. These typically specify the plot style, the line color, the marker type, etcetera. These arguments are used to build a `plot` command for gnuplot. Note that, instead of using a bunch of individual keyword arguments, you can pass gnuplot a complete plot command using the keyword `curveconf`.

`axeskwargs` is a set of keyword arguments wrapped in `Axes()`, which specify the look of the axes, or figure; this refers to things like the plot title, tics, ranges, grid, etcetera. Essentially, anything that can be `set` in gnuplot, can be configured from Gaston by wrapping it in `Axes()`. The special keyword `axesconf` is used to provide a string with commands that are passed literally to gnuplot.

To add a new curve to an existing figure, use `plot!`. It accepts the same arguments as `plot`, except for `Axes()` arguments, which can only be set from `plot`.

The `plot` command has enough flexibility to plot everything that Gaston is capable of. However, Gaston provides a few specialized commands that make certain plots easier. These are illustrated below.

| Command     | Purpose                          |
|-------------|:---------------------------------|
| `scatter`, `scatter!`   | Plot point clouds    |
| `stem`      | Plot discrete (sampled) signals  |
| `bar`       | Plot bar charts                  |
| `histogram` | Plot histograms                  |
| `imagesc`   | Plot images                      |

(Some of the examples below are taken from lazarusa's [excellent gallery](https://lazarusa.github.io/gnuplot-examples/gallery/)).

## Debug mode

If you want to see exactly what commands Gaston is sending to gnuplot, you can turn on debug mode:

    set(debug = true)

Use `set(debug = false)` to turn this mode off.

## Set the plot style, line color, line pattern, line width, and markers

The plot style is set with the keys `w`, `with`, or `plotstyle`. Gnuplot supports many different plot styles; for example, `lines` means plotting a line, `points` is just the markers, and `linespoints` is a line with markers. See all the details in gnuplot's documentation.

The line color is set with `lc` or `linecolor`; while the line width is specified with `linewidth` or `lw`. The marker type is configured with `pointtype`, `pt` or `marker`. Usually gnuplot identifies each marker type by a number, but Gaston provides some equivalent names (see [Introduction to plotting](@ref). The marker size is configured with `pointsize`, `ps` or `ms`. The number of markers may be configured with `pointnumber` or `pn`.

The line style can be configured in multiple ways; one is to specify `linestyle` or `ls` followed by a pattern of dashes and points such as `'-.-'`.

The plotted curve can be given a legend with `title` or `legend`.

The following examples use all these options.

```@example 2dtut
using Gaston # hide
set(reset=true) # hide
set(termopts="size 550,325 font 'Consolas,11'") # hide
# plot with lines and markers
t = -5:0.05:5
plot(t, sin,
     # linespoints plot style
     w  = :lp,
     # line color
     lc = :turquoise,
     # line width
     lw = 3,
     # empty circles
     marker = "ecircle",
     # marker size
     ms = 1.5,
     # plot only ten markers
     pn = 10,
     # legend
     legend = :A_sine_wave
    )
```

```@example 2dtut
# plot with dashed line
plot(t, sin,
     # lines plot style
     w  = :l,
     # line width
     lw = 3,
     # dashed line
     ls = "'-.-'"
    )
```

## Set the plot title, axis labels, tics, legends and grid

Since these are attributes of the entire figure, they must be wrapped by `Axes()`. The title is set with `title`, the axis labels with `xlabel` and `ylabel`.

The tics are configured with `xtics` and `ytics`. The grid can be turned on with `grid`. The position and shape of the legend box is configured with `key`.

The following example shows how to use these attributes.

```@example 2dtut
plot(t, sin,
    w  = :lp, lc = :turquoise, lw = 3,
    marker = "ecircle", ms = 1.5,
    pn = 10, legend = :A_sine_wave,
    Axes(# set the title
         title = "'Example plot'",
         # turn on the grid
         grid = :on,
         # specify tics
         xtics = -5:2:5,
         ytics = ([-1 0 1], ["- one", "zero", "+ one"]),
         # configure legend box
         key = "outside center bottom")
    )
```

## Logarithmic plots

The axes can be configured to have a logarithmic scale, using `axis = semilogy`, `semilogx`, or `loglog`.

```@example 2dtut
using SpecialFunctions
Q(x) = 0.5erfc(x/sqrt(2))
SNR = 1:15
plot(10log10.(SNR), Q.(sqrt.(SNR)),
     Axes(axis = "semilogy",
          xlabel = "'Signal to Noise Ratio (dB)'",
          ylabel = "'Bit Error Rate'",
          ytics  = "out format '10^{%T}'",
          grid   = "xtics mytics",
          title  = "'BPSK Bit Error Rate'")
    )
```

## Step plots

In step plots, data points are joined with a horizontal line. To obtain a step plot, set the plot style to `steps`, `fsteps`, or `fillsteps`.

```@example 2dtut
t = -2:0.06:2
plot(t, sin.(2π*t),
     plotstyle = :steps,
     Axes(title = "'Steps plot'")
    )
```

```@example 2dtut
plot(t, sin.(2π*t),
     w = :fillsteps,
     Axes(style = "fill solid 0.5",
          title = "'Fillsteps plot'")
    )
```

The color can be specified with `fillcolor`:

```@example 2dtut
plot(t, sin.(2π*t),
     w = :fillsteps,
     fc = :plum,
     Axes(style = "fill solid 0.5",
          title = "'Fillsteps plot'")
    )
```

## Plotting with financial and error bars

Gaston supports plotting using financial and error bars, by setting the plot style appropriately. Supplementary data is passed to gnuplot using the argument `supp`.

```@example 2dtut
x = 1:0.5:8
open = 3*(0.5 .- rand(length(x)))
close = open .+ 1;
low = open .- 1;
high = open .+ 1.5;
fin = [low high close]
plot(x, open, supp = fin, plotstyle = "financebars",
     Axes(title = "'Example of financial bars'")
    )
```

```@example 2dtut
x = 0:2:50
y = @. 2.5x/(5.67+x)^2
err = 0.05*rand(length(x))
plot(x, y, supp = err, plotstyle = :errorlines,
     Axes(title = "'Example of error lines'")
    )
```

## Plotting filled curves

To "fill" the area below a curve, use the plot style "filledcurves". In the example below, we use `curveconf` to pass a full plot command to gnuplot. The `style` is set to `transparent`, so one plot will not obscure those behind it.

```@example 2dtut
x = LinRange(-10,10,200)
fg(x,μ,σ) = exp.(.-(x.-μ).^2 ./(2σ^2))./(σ*√(2π))
plot(x, fg(x, 0.25, 1.5),
     curveconf = "w filledcu lc '#E69F00' dt 1 t '0.25,1.5'",
     Axes(style = "fill transparent solid 0.3 noborder",
          key = "title 'μ,σ' box 3",
          xlabel = "'x'", ylabel="'P(x)'",
          title = "'Example of filled curves'"))
plot!(x, fg(x, 2, 1), curveconf = "w filledcu lc '#56B4E9' dt 1 t '2,1'")
plot!(x, fg(x, -1, 2), curveconf ="w filledcu lc '#009E73' dt 1 t '-1,2'")
```

## Filling the space between two curves

It is possible to fill the space between two curves by providing the second curve as a supplementary column. In this example, gnuplot will fill the space between `sin.(x)` and `sin.(x) .+ 1`.

```@example 2dtut
x = LinRange(-10,10,200)
plot(x, sin.(x) .- 0.2, supp = sin.(x) .+ 0.2,
     curveconf = "w filledcu lc '#56B4E9' fs transparent solid 0.3",
     Axes(title = :Filling_the_space_between_two_curves))
plot!(x, sin.(x), lc = :blue)
```

## Box plots

This example shows the use of supplementary data with the "boxerrorbars" style. the vector `yerr` controls the length of the error bar for each box, while `lcval` assigns each box a color (since `lc palette` is given in `curveconf`). Finally, a color palette is specified using a symbol (`:summer`), which refers to a color scheme from ColorSchemes.jl.

```@example 2dtut
using Random
x = 1:2:20
y = 5*rand(10)
yerr = 0.4*abs.(randn(10))
lcval = 1:10
plot(x, y, supp=[yerr lcval],
     curveconf = "w boxerrorbars notit lc palette fs solid 0.5",
     Axes(palette = :summer,
          xrange=(0,22),
          yrange=(0,6))
    )
```

## Scatter plots (point clouds)

A scatter plot can be generated with the `scatter` command:

```@example 2dtut
c = 2rand(1000).-1 .+ im*(2rand(1000).-1)
p = filter(x->abs(x)<1, c)
scatter(p,
        marker = "fsquare",
        pointsize = 0.25,
        Axes(object = "ellipse at 0,0 size 2,2",
             title = "'Random points within the unit circle'")
       )
```

Note that, when the data to plot is complex, the real part is interpreted as the `x` coordinate and the imaginary part as the `y` coordinate.

Besides the standard markers, any UTF-8 character may be used:

```@example 2dtut
scatter(randn(30), randn(30), marker = "λ")
```

### Bubble plots

This example shows how to generate a scatter plot where the color and size of each point is specified with supplementary data. This example also shows how to turn off the colorbox.

```@example 2dtut
n = 40
x, y, z = randn(n), randn(n), randn(n)
plot(x, y, supp = [5z z],
     curveconf = "w p notit pt 7 ps var lc palette",
     Axes(palette = :ice,
          xrange = (-2.2, 2.5),
          yrange = (-2.2, 2.2),
          colorbox = :off)
    )
```

!!! info "`scatter` with gnuplot"
    Behind the scenes, `scatter` calls `plot` with the `points` plotstyle.

## Stem plots

Stem plots make it obvious one is plotting a discrete-time signal. The `stem` command replicates the behavior of `stem` in Matlab, Octave, et al:

```@example 2dtut
t = -2:0.06:2
stem(t, sin.(2π*t))
```

By default, the line color is blue and the lines are made sligthly thicker. If only the vertical lines ("impulses") are desired, pass the option `onlyimpulses=true` to `stem`:

```@example 2dtut
stem(t, sin.(2π*t), onlyimpulses = true)
```

!!! info "`stem` with gnuplot"
    Behind the scenes, `stem` calls `plot` with the `impulses` plotstyle, followed (if `onlyimpulses == true`) by a call to `plot!` with the `points` plotstyle and the pointtype set to `"ecircle"`.

## Bar plots

Bar plots can be generated with the `bar` command:

```@example 2dtut
year = range(1985, length=20);
data = 0.5 .- rand(20)
bar(year, data,
    fc = "'dark-goldenrod'",
    legend = "'Random number'",
    Axes(xtics = "rotate",
         key = "box under",
         boxwidth = 0.66,
         style = "fill pattern 2")
   )
```

!!! info "`bar` with gnuplot"
   Behind the scenes, `bar` uses gnuplot's `boxes` plotstyle, with a default box width of 0.8 and solid fill.

## Histograms

To plot histograms, use the `histogram` command. This command takes the same properties as `bar`. In addition, `histogram` accepts a `bins` parameter, used to specify the number of bins, and a `norm` parameter that can be used to normalize the area under the histogram.

```@example 2dtut
histogram(rand(10000),
          bins = 15,
          norm = 1,
          Axes(title = :Histogram,
               yrange = "[0:1.8]")
         )
```

It is of course possible to use `histogram` (or any other plot command) along with `plot!` to produce different kinds of plots in the same figure:

```@example 2dtut
x = -5:0.05:5
data = randn(10000)
gaussian = @. exp(-x^2/2)/sqrt(2π)
histogram(data,
          bins = 25,
          norm = 1,
          legend = "'Experimental'",
          linecolor = :turquoise,
          Axes(boxwidth = "0.8 relative",
               title = "'Experimental and Theoretical Gaussian distributions'",
               key = "box top left"))
plot!(x, gaussian,
      linecolor = :black,
      legend = "'Theoretical'")
```

## Images

The command to plot an image is `imagesc`. It can plot a scaled or RGB image, depending on whether the provided coordinates are an array with two or with three dimensions.

Note that `imagesc` interprets the `x` axis as the columns of the matrix. In other words, element `[1,1]` is located in the top-left corner of the plot, and element `[end:1]` is in the bottom-left corner.

### Scaled image

A scaled image is a plot of a matrix whose elements are interpreted as grayscale values (which may be displayed in color with a given palette).

```@example 2dtut
Z = [5 4 3 1 0 ;
     2 2 0 0 1 ;
     0 0 0 1 0 ;
     0 1 2 4 3]
imagesc(Z, Axes(title = "'Simple scaled image'", palette = :summer))
```

To display the image as grayscale, use the `gray` palette.

```@example 2dtut
using Images
using TestImages
img = testimage("lake_gray");
ii = channelview(img)[1,:,:].*255;
imagesc(ii, Axes(palette = :gray))
```

### RGB image

An RGB image is a plot of a 3-D array whose elements are interpreted as the red, green, and blue components of each image pixel. The array's `[1,;,:]` elements are a matrix representing the red channel, while `[2,:,:]` and `[3,:,:]` are the green and blue channels respectively.

```@example 2dtut
img = testimage("lake_color")
imagesc(channelview(img).*255,
        Axes(size = "square", autoscale = "fix"))
```


================================================
FILE: docs/v1/3d-gallery.md
================================================
# [3-D Gallery](@id threedeegal)

(Many of these examples taken from, or inspired by, [@lazarusa's amazing gallery](https://lazarusa.github.io/gnuplot-examples/gallery/))

# Interlocking Tori

```@example 3dgal
using Gaston # hide
set(reset=true) # hide
set(termopts="size 500,500 font 'Consolas,11'") # hide
U = LinRange(-pi, pi, 100)
V = LinRange(-pi, pi, 20)
x = [cos(u) + .5 * cos(u) * cos(v)      for u in U, v in V]
y = [sin(u) + .5 * sin(u) * cos(v)      for u in U, v in V]
z = [.5 * sin(v)                        for u in U, v in V]
surf(x', y', z',
     w = :pm3d,
     Axes(palette = :dense,
          pm3d = "depthorder",
          colorbox = :off,
          key = :false,
          tics = :false,
          border = 0,
          view = "60, 30, 1.5, 0.9",
          style = "fill transparent solid 0.7"))
x = [1 + cos(u) + .5 * cos(u) * cos(v)  for u in U, v in V]
y = [.5 * sin(v)                        for u in U, v in V]
z = [sin(u) + .5 * sin(u) * cos(v)      for u in U, v in V]
surf!(x', y' ,z' , w = :pm3d)
```

# Fill a curve in 3-D

```@example 3dgal
set(saveopts="size 550,325 font 'Consolas,11'") # hide
x = 0.:0.05:3;
y = 0.:0.05:3;
z = @. sin(x) * exp(-(x+y))
surf(x, y, z, supp = [z.*0 z], curveconf = "w zerror t 'Data'", lw = 3,
     Axes(xlabel = :X, ylabel = :Y,
          linetype = :Set1_5,
          style = "fill transparent solid 0.3",
          xyplane = "at 0",
          grid = :on)
    )
surf!(x.*0, y, z, w = :l, lw = 3)
surf!(x, y.*0, z, w = :l, lw = 3)
```

# Variable marker size and color

```@example 3dgal
x = 0:0.1:6π;
scatter3(x, cos.(x), sin.(x), supp = x./10,
         ps = "variable", pt = "fcircle", lc = "palette",
         Axes(colorbox = :off))
```

# Surface with contours

```@example 3dgal
x = y = -10:0.5:10
f1 = (x,y) -> cos.(x./2).*sin.(y./2)
surf(x, y, f1,
     lc = :turquoise,
     Axes(hidden3d = :on,
          contour = "base",
          cntrparam = "levels 10",
          key = :off))
```

# Egg-shaped contours

```@example 3dgal
x = -1:0.05:1
y = -1.5:0.05:2
egg(x,y) = x^2 + y^2/(1.4 + y/5)^2
segg = [egg(x,y) for x in x, y in y]
contour(x, y, segg', labels = false,
        curveconf = "w l lc palette",
        Axes(palette = :cool,
             cntrparam = "levels incremental 0,0.01,1",
             auto = "fix",
             xrange = (-1.2, 1.2),
             yrange = (-1.5, 2),
             cbrange = (0, 1),
             xlabel = :x,
             ylabel = :y,
             size="ratio -1"))
```

# Tubes

```@example 3dgal
U  = LinRange(0,10π, 80)
V = LinRange(0,2π, 20)
x = [(1-0.1*cos(v))*cos(u) for u in U, v in V]
y = [(1-0.1*cos(v))*sin(u) for u in U, v in V]
z = [0.1*(sin(v) + u/1.7 - 10) for u in U, v in V]
surf(x, y, z, w="pm3d",
     Axes(pm3d = "depthorder",
     style = "fill transparent solid 0.7",
     view = "equal xyz",
     xyplane = -0.05,
     palette = :ice,
     xrange = (-1.2, 1.2),
     yrange = (-1.2, 1.2),
     colorbox = :off))
```

# Spheres

```@example 3dgal
Θ = LinRange(0, 2π, 100) # 50
Φ = LinRange(0, π, 20)
r = 0.8
x = [r * cos(θ) * sin(ϕ)      for θ in Θ, ϕ in Φ]
y = [r * sin(θ) * sin(ϕ)      for θ in Θ, ϕ in Φ]
z = [r * cos(ϕ) for θ in Θ, ϕ in Φ]
surf(x, y, z, w = :l, lc = :turquoise,
     Axes(view = "equal xyz",
          pm3d = "depthorder",
          hidden3d = :on))
```

```@example 3dgal
surf(x, y, z, w = :pm3d,
     Axes(style = "fill transparent solid 0.5",
     xyplane = 0,
     palette = :summer,
     view = "equal xyz",
     pm3d = "depthorder"))
```

# Torus

```@example 3dgal
U  = LinRange(-π,π, 50)
V = LinRange(-π,π, 100)
r = 0.5
x = [1 + cos(u) + r * cos(u) * cos(v)  for u in U, v in V]
y = [r * sin(v)                        for u in U, v in V]
z = [sin(u) + r * sin(u) * cos(v)      for u in U, v in V]
axesconf = """set object rectangle from screen 0,0 to screen 1,1 behind fillcolor 'black' fillstyle solid noborder
              set pm3d depthorder
              set style fill transparent solid 0.5
              set pm3d lighting primary 0.05 specular 0.2
              set view 108,2
              unset border
              set xyplane 0
              unset tics
              unset colorbox"""
surf(x, y, z, w = :pm3d, Axes(palette = :cool, axesconf = axesconf))
```

# Animation

```julia
closeall()  # hide
z=0:0.1:10pi;
step = 5;
cc = "w l lc 'turquoise' lw 3 notitle"
ac = Axes(zrange = (0,30), xrange = (-1.2, 1.2), yrange = (-1.2, 1.2),
          tics = :off,
          xlabel = :x, ylabel = :y, zlabel = :z)
F = scatter3(cos.(z[1:step]), sin.(z[1:step]), z[1:step], curveconf = cc, ac);
for i = 2:60
    pi = scatter3(cos.(z[1:i*step]), sin.(z[1:i*step]), z[1:i*step],
                  curveconf = cc, ac, handle = 2);
    push!(F, pi)
end
for i = 60:-1:1
    pi = scatter3(cos.(z[1:i*step]), sin.(z[1:i*step]), z[1:i*step],
                  curveconf = cc, ac, handle = 2);
    push!(F, pi)
end
save(term="gif", saveopts = "animate size 600,400 delay 1", output="anim3d.gif", handle=1)
```

![](assets/anim3d.gif)

```julia
closeall() # hide
x = y = -15:0.4:15
ac = Axes(title = :Sombrero_Surface,
          palette  = :cool,
          cbrange  = (-0.2, 1),
          zrange   = (-0.3, 1),
          hidden3d = :on)
F = surf(x, y, (x,y) -> (@. sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)),
         ac, w = :pm3d);
for i = 1:-0.1:-1
    pi = surf(x, y, (x,y) -> (@. i*sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)),
              ac, w = :pm3d, handle = 2);
    push!(F, pi)
end
for i = -0.9:0.1:1
    pi = surf(x, y, (x,y) -> (@. i*sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)),
              ac, w = :pm3d, handle = 2);
    push!(F, pi)
end
save(term = "gif", saveopts = "animate size 600,400 delay 1",
     output = "anim3db.gif", handle=1)
```

![](assets/anim3db.gif)


================================================
FILE: docs/v1/3dplots.md
================================================
# [3-D plotting tutorial](@id threedeetut)

Three dimensional plots can be created with the commands `surf` and `surf!`. These are very similar to [plot](@ref twodeetut), except for the `z` coordinate, which is a matrix that specifies the z-coordinate of the points specified in `x` and `y`.

In addition, the following commands are specialized for different types of 3-D plots:

| Command     | Purpose                          |
|-------------|:---------------------------------|
| `scatter3`, `scatter3!`   | 3-D point clouds   |
| `contour`      | Contour plots                 |
| `heatmap`      | Heatmap plots                 |

## How to plot a set of 3-D coordinates

A set of 3-D coordinates may be explicitly given. Plotting them is just a matter of providing the data to gnuplot. Note that the data may be plotted as a wireframe (with plot style `lines`, which is the default), or as a surface (`pm3d`) with an optional palette.

```@example 3dtut
using Gaston # hide
set(reset=true) # hide
set(termopts="size 550,325 font 'Consolas,11'") # hide
# plot a wireframe
x = [0,1,2,3]
y = [0,1,2]
z = [10 10 10 10 ; 10 5 1 0 ; 10 10 10 10]
surf(x, y, z,
     Axes(title = "'3D: Valley of the Gnu from gnuplot manual'"))
```

Note that the matrix of `z` coordinates is defined so that the columns are indexed by the `x` coordinates. In other words, `z[1,1]` is the surface at `x = 0, y = 0` and `z[3,1]` is the coordinate at `x = 0, y = 2`.

```@example 3dtut
surf(x, y, z, w = :pm3d,
     Axes(title = "'Surface with palette'",
          palette = :summer))
```

## How to plot a 3-D function

A 3-D function defines a surface for a given set of `x` and `y` samples. Consider the function `(x,y) -> @. sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)`. It may be plotted with

```@example 3dtut
x = y = -15:0.4:15
f1 = (x,y) -> @. sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)
surf(x, y, f1, lc = :turquoise,
     Axes(title    = :Sombrero_Wireframe,
          hidden3d = :on))
```

```@example 3dtut
surf(x, y, f1, w = :pm3d,
     Axes(title    = :Sombrero_Surface,
          palette  = :cool,
          cbrange  = (-0.2, 1),
          hidden3d = :on))
```

## Plotting multiple surfaces with `surf!`

The equivalent to `plot!` is `surf!`:

```@example 3dtut
surf(x,y,f1,w=:pm3d,Axes(title=:Sombrero_Surface,palette=:cool,cbrange=(-0.2,1),hidden3d=:on)) # hide
surf!(x, y , (x,y) -> cos.(x./2).*sin.(y./2)-3, lc = :orange, w = :l)
```

## Plotting contours

Gnuplot's contour support is quite flexible. The `contour` command sets up pretty generic contours, which hopefully are useful in many cases. For much more detail, see gnuplot's documentation.

The contours of a surface can be plotted using:

```@example 3dtut
x = y = -5:0.1:5
contour(x, y, (x,y) -> 5cos.(x/2).*sin.(y/2))
```

The labels can be disabled if `labels=false` is passed as an argument:

```@example 3dtut
contour(x, y, (x,y) -> 5cos.(x/2).*sin.(y/2), labels=false)
```

## Plotting heatmaps

Heatmaps can be plotted using `heatmap`. Just like `contour`, this command sets up a pretty basic heatmap; for more control, see gnuplot's documentation.

```@example 3dtut
heatmap(x, y, (x,y)->cos.(x/2).*sin.(y/2))
```


================================================
FILE: docs/v1/api.md
================================================
# API Reference


================================================
FILE: docs/v1/examples.md
================================================
# Examples

The plots below have been rendered in a png terminal with the following configuration:
```julia
Gaston.config.term = "pngcairo font ',10' size 640,480"
```
In addition, gnuplot's start up file is as described in the Introduction: [Gnuplot startup file](@ref).

## 2-D Plots

```@setup 2dt
using Gaston
Gaston.config.output = :echo
Gaston.config.term = "pngcairo font ',10' size 640,480"
closeall() # hide
```

Let us start with a simple sine wave plot:

```@example 2dt
x = range(0, 0.5, length = 100)
y = sin.(2*pi*10*x)
plot(x, y)
```
Now, let us add a grid and some annotations:
```@example 2dt
@plot {grid, title = Q"{/:Bold A sine wave}", xlabel = Q"Time", ylabel = Q"Volts"} x y
```
Here we have used `@plot` instead of `plot`, which allows us to specify the plot settings
as a list of keyword arguments. These arguments can be stored in a "theme" using `@gpkw`:
```julia
settings = @gpkw {grid, title = Q"{/:Bold A sine wave}", xlabel = Q"Time", ylabel = Q"Volts"}
```
In addition, we have used the `Q` string macro to avoid typing single quotes; `Q"Time"` is
converted to `"'Time'"`.

Now let us change the line color and markers:
```@example 2dt
settings = @gpkw {grid, title = Q"A sine wave", xlabel = Q"Time", ylabel = Q"Volts"}; # hide
@plot settings x y {with = "lp", lc = Q"sea-green", pt = :fcircle, ps = 1.5}
```
Parameters that affect how the curve is plotted are specified *after* the data. These
can also be stored and reused, so that
```julia
plotline = @gpkw {with = "lp", lc = Q"sea-green", pt = :fcircle, ps = 2}
@plot settings x y plotline
```
would produce the same plot. Settings and plotline parameters can also be specified as strings;
see the [Manual](@ref) for all the details. Gaston also has a number of built-in [Themes](@ref).

Use `plot!` or `@plot!` to plot a second curve:
```@example 2dt
plotline = @gpkw {with = "lp", lc = Q"sea-green", pt = :fcircle, ps = 2} # hide
@plot(settings,
      {title = Q"Two sinusoids", key = "columns 1", key = "box outside right top"},
      x, y,
      plotline, {title = "'sin'"})
y2 = cos.(2*pi*10*x)
@plot! x y2 {dashtype = Q".-.", title = Q"cos"}
```
Here we see how multiple settings and plotline arguments can be combined. 
Note that new settings cannot be declared in `plot!` commands; only the plotline for the new curve can be
specified.

#### Plotting functions

In the examples above, the data given to `plot` is stored in vectors. Functions can be plotted
directly, with a given range and number of samples, as follows:
```@example 2dt
g(x) = exp(-abs(x/5))*cos(x)
tt = "set title 'g = x -> exp(-abs(x/5))*cos(x))'"
plot(tt, (-10, 10, 200), g) # plot from x = -10 to 10, using 200 samples
```
Ranges can be specified in the following alternative ways:
```julia
plot(g)            # 100 samples, from -10 to 9.99
plot((a, b), g)    # 100 samples, from a to b
plot((a, b, c), g) # c samples, from a to b
plot(x, g)         # plot g.(x)
```

#### Multiplots

To plot multiple sets of axes in a single figure, we use indexing into the figure as follows:
```@example 2dt
f = plot(x, y) # f is of type Gaston.Figure
plot(f[2], x, sinc.(10x))
```
It is possible to have empty "slots":
```@example 2dt
plot(f[4], x, sinc.(20x), "w lp pn 12")
```
Gaston tries to keep a square figure aspect ratio as more and more axes are included. 
Add another plot to a subplot using indexing:
```@example 2dt
plot!(f[2], x, 0.3randn(length(x)))
```
To gain full control of gnuplot's multiplot options, instantiate a
new `Gaston.Figure` with the string keyword argument `multiplot`; the string is passed to
gnuplot's `set multiplot`:
```@example 2dt
closeall() # hide
f = Figure(multiplot = "title 'Arbitrary multiplot layout demo'")
x = randn(100)
y = randn(100)
@plot({margins = (0.1, 0.65, 0.1, 0.65)},
      x, y,
      "w p pt '+' lc 'dark-green'")
@gpkw histogram(f[2],
                {margins = (0.7, 0.95, 0.1, 0.65), tics = false},
                y,
                {lc = Q"dark-green"}, nbins = 10, horizontal = true)
@gpkw histogram(f[3],
                {margins = (0.1, 0.65, 0.7, 0.9), boxwidth = "1 relative"},
                x,
                {lc = Q"dark-green"}, nbins = 10)
```
Note that margins can be specified as a tuple. The macro `@gpkw` allows us to use keyword
settings in the `histogram` plot command (described below).

The figure's `multiplot` field can be modified *post-hoc*:
```julia
f.multiplot = "title 'New title' layout 2,2"
```
!!! info
    Gaston takes care of the multiplot layout automatically **only** if the figure's `multiplot`
    setting is an empty string (this is the default value). If it's not empty, then the user
    is in charge of handling the layout.

!!! info
    Gaston never clears a figure's `multiplot` setting. If re-using a figure for subsequent
    plots, this setting must be adjusted manually.

## 3-D Plots
Plotting in 3-D is similar to 2-D, except that `splot` (and `@splot`, `splot!`, `@splot!`) are used
instead of `plot`. This example shows how to plot the surface defined by function `s`:
```@example 2dt
x = y = -15:0.2:15
s = (x,y) -> @. sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)
@splot("set title 'Sombrero'\nset hidden3d", {palette = :cool}, x, y, s, "w pm3d")
```
The palette `cool` is defined in [ColorSchemes](https://github.com/JuliaGraphics/ColorSchemes.jl).

## Animations

Animations require use of the `gif` or `webp` terminals (make sure your
notebook supports the `image/webp` MIME type before using it).

Creating an animation is similar to multiplotting: multiple axes are drawn on
the same figure. When using the `animate` option of the `gif` or `webp`
terminals, however, the plot is rendered as an animation.

Note that gnuplot will output a message to `STDERR` indicating how many frames
were recorded; this message is purely informative and not actually an error.

A difficulty arises when mixing plot formats in a notbook (say, `png` and
`gif`): the terminal is specified in the configuration variable `Gaston.config.term`.
However, some notebook programs (such as Pluto) execute cells in arbitrary
order. This means that changing the terminal in one cell may affect other
cells.

To solve this problem, Gaston provides a way to ignore the global terminal
configuration when rendering a plot. A figure `f` can be rendered with a given
terminal by calling `animate(f, term)`. The default value of `term` is stored
in `Gaston.config.altterm` and defaults to `gif animate loop 0`.

The following examples illustrate how to create and display animations, in this case with a
background image:
```@example 2dt
f = Figure()  # new, empty figure
frames = 75
x_bckgnd = range(-1, 1, 200)  # x values for the background image
bckgnd = Plot(x_bckgnd, sin.(2π*2*x_bckgnd), "lc 'black'")  # background image
x = range(-1, 1, frames)
for i in 1:frames
    plot(f[i], x[i], sin(2π*2*x[i]), "w p lc 'orange' pt 7 ps 7") # first plot the function...
    push!(f[i], bckgnd)  # ... then add the background
end
for i in frames:-1:1  # in reverse
    plot(f[2frames-i+1], x[i], sin(2π*2*x[i]), "w p lc 'orange' pt 7 ps 7")
    push!(f[2frames-i+1], bckgnd)
end
save(f, output = "2DAnim.webp", term = "webp animate loop 0 size 640,480")
```
![An animation](2DAnim.webp)

## Themes

Gaston includes several themes for common plot styles. The easiest way to use
them is through the specialized plot commands described below. For more
details, see the [Manual](@ref).

Themes are divided into _settings themes_, which specify gnuplot `set` commands,
and _plotline themes_, which specify how a particular curve is displayed
(color, thickness, etc.) Settings themes are stored in the dictionary
`Gaston.sthemes`, and plotline themes are stored in `Gaston.pthemes`. The
themed commands described below use combinations of these themes to create a
specific type of plot.

In gnuplot, plotlines (as in `plot with lines`) are especially difficult to
theme, because repeated options are errors, and options given in the wrong
order may also cause errors. As an example, consider using `scatter` to plot
some points; we want to use `pointtype` number 4:
```julia
scatter(rand(10), rand(10), "pointtype = 4")
```
This command causes an error because the plotline theme `:scatter` already
specifies the pointtype! To plot a scatter plot using the desired point type,
use plain `plot` with the appropriate settings, create your own theme, or
modify the built-in theme. Here is an example where the theme is modified.
First find out how the theme is set up:
```@example 2dt
Gaston.pthemes[:scatter]
```
Then, modify the entry for the pointtype:
```@example 2dt
Gaston.pthemes[:scatter][2] = "pointtype" => 4
scatter("set title 'Scatter plot with modified theme", rand(10), rand(10), "lc 'dark-green'")
```
Note how the linecolor was specified without causing an error, since it is not included in the theme.

#### Scatter plots

| command | settings theme | plotline theme |
|:--------|:---------------|:---------------|
|`scatter` | none | `:scatter` |
|`scatter3` | `:scatter3` | `:scatter` |

```@example 2dt
# reset theme # hide
@gpkw Gaston.pthemes[:scatter] = {with = "points", pointtype = :fcircle, pointsize = 1.5} # hide
xg = randn(20)
yg = randn(20)
scatter("set title 'Scatter plot'
         set key outside",
        xg, yg,
        "title 'gaussian'")
xu = rand(20)
yu = rand(20)
scatter!(xu, yu, "title 'uniform'")
```
A 3-D scatter plot (the default settings theme (`:scatter3`) draws all the borders):
```@example 2dt
scatter3("set title 'A 3-D scatter plot", randn(10), randn(10), randn(10))
```

#### Stem plots

| command | settings theme | plotline theme |
|:--------|:---------------|:---------------|
|`stem` | none | `:stem`, `:impulses` |

Stem plots are often used in digital signal processing applications to represent
a discrete-time (sampled) signal.
```@example 2dt
stem("set title 'Stem plot'", g)
```
To generate a stem plot, gnuplot actually plots twice: once with style `impulses` and once with
`points` (set to empty circles). Normally, each of these plots would have a different color. To
use the same color for both, use the `color` keyword argument:
```@example 2dt
stem("set title 'Stem plot'", g, color = "'goldenrod'")
```
The circular marks can be omitted with the `onlyimpulses` keyword argument:
```@example 2dt
stem("set title 'Stem plot with onlyimpulses'", g, onlyimpulses = true)
```

#### Bar plots

| command | settings theme | plotline theme |
|:--------|:---------------|:---------------|
|`bar` | `:boxplot` | `:box` |
|`barerror` | `:boxerror` | `:box` |

```@example 2dt
bar("set title 'Bar plot'", rand(10), "lc 'turquoise'")
```
This example shows how to plot two sets of bars, using `bar!`:
```@example 2dt
bar("set title 'Two bar plots'", rand(10), "lc 'dark-violet'")
bar!(1.5:10.5, 0.5*rand(10), "lc 'plum' fill pattern 4")
```
Error bars are handled by `barerror`; there is also `barerror!`.
```@example 2dt
barerror("set title 'Error bars plot'", 1:10, rand(10), 0.1*rand(10).+0.1, "lc 'sandybrown'")
```

#### Histograms

| command | settings theme | plotline theme |
|:--------|:---------------|:---------------|
|`histogram` | `:histplot` | `:box`, `:horhist` (1-D); `:image`  (2-D) |

The `histogram` function takes these optional keyword arguments:
* `nbins`: specifies the number of bins. Defaults to 10.
* `mode::Symbol`: Controls histogram normalization mode; passed to
  [`StatsBase.normalize`](https://juliastats.org/StatsBase.jl/stable/empirical/#LinearAlgebra.normalize).
  Defaults to `:none`.
* `edges`: a vector or a range specifying the bin edges; if specified, takes
  precedence over `nbins`. Defaults to `nothing`.
* `horizontal::Bool`: if `true`, the histogram is drawn horizontally. Defaults
  to `false`.
`histogram` uses the settings theme `:histplot`, and plotline themes `:box` or `:horhist`.
2-D histograms are supported, by passing two datasets.

Using `nbins`:
```@example 2dt
histogram("set title 'Histogram (nbins)'",
          randn(10_000),
          nbins = 20, mode = :pdf)
```

Using `edges`:
```@example 2dt
histogram("set title 'Histogram (edges)'",
          0.75*randn(10_000),
          edges = -2:0.75:3, "lc 'dark-khaki'")
```

A horizontal histogram:
```@example 2dt
histogram("set title 'horizontal histogram'",
          rand(1000),
          nbins = 15, horizontal = true, "lc 'orchid'")
```

In the case of 2-D histograms, `nbins` or `egdes` may be a tuple; otherwise, both axes use the
same settings. The plotline theme is `:image`.
```@example 2dt
x = 2.5*randn(100_000)
y = 2.5*randn(100_000)
th = @gpkw {palette = :matter, colorbox = false, title = Q"2-D histogram",
            xrange = (-10, 10), yrange = (-10, 10)}
histogram(th, x, y, nbins = 50, mode = :pdf)
```

#### Images

| command | settings theme | plotline theme |
|:--------|:---------------|:---------------|
|`imagesc` | `:imagesc` | `:image`, `:rgbimage` |

Arrays may be plotted as images using `imagesc`. Note that, in contrast to other plotting packages,
the first row is plotted at the top.
```@example 2dt
X = [0 1 2 3;
     0 3 2 1;
     0 2 2 0;
     3 0 0 0]
imagesc("unset xtics\nunset ytics", X)
```
To display the image as grayscale, use the `gray` palette.
```@example 2dt
using Images, TestImages
img = testimage("lake_gray");
ii = channelview(img)[1,:,:].*255;
@gpkw imagesc({palette = :gray}, ii)
```
An RGB image is a plot of a 3-D array, where  `[1,;,:]`
is the red channel, `[2,:,:]` is the green channel, and
`[3,:,:]` is the blue channels.
```@example 2dt
img = testimage("lake_color")
@gpkw imagesc({size = "square", autoscale = "fix"}, channelview(img).*255)
```

#### Surfaces

| command | settings theme | plotline theme |
|:--------|:---------------|:---------------|
|`wireframe` | `:hidden3d` | none |
|`surf` | `:hidden3d` | `:pm3d` |

A surface can be plotted as a "wireframe" (or a "mesh") with the `wireframe`
command. By default, `hidden3d` is active, so that elements behind the surface
are not plotted.
```@example 2dt
f1(x,y) = sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)
th = @gpkw {title = Q"Sombrero Wireframe", palette = :matter}
@gpkw wireframe(th, (-15, 15, 30), f1)
```
Solid surfaces can be plot with `surf`:
```@example 2dt
th = @gpkw {title = Q"Sombrero Surface", palette = :matter}
@gpkw surf(th, (-15, 15, 200), f1)
```
When plotting a function and a single range (such as `(-15, 15, 200)` above) is given, it is used for
both `x` and `y` coordinates. Two ranges may be given as well to control the `x` and `y` ranges
separately:
```@example 2dt
@gpkw surf(th, (-15, 15, 200), (-25, 5, 200), f1)
```

#### Contour plots

| command | settings theme | plotline theme |
|:--------|:---------------|:---------------|
|`contour` | `:contour` | `:labels` |
| `surfcountour` | `:contourproj` | `:labels` |

By default, contour plots include numerical labels:
```@example 2dt
f2(x,y) = cos(x/2)*sin(y/2)
contour("set title 'Contour Plot'", (-10, 10, 50), f2)
```
To plot contours without labels, use the keyword argument `labels = false`:
```@example 2dt
contour("set title 'Contour Plot Without Labels'", (-10, 10, 50), f2, labels = false)
```
It's possible to plot a wireframe surface and a contour projected on the base of the plot
using `surfcountour`:
```@example 2dt
surfcontour("set title 'Surface With Projected Contours'", (-5, 5, 40), f2, "lc 'orange'")
```
The same plot without contour labels:
```@example 2dt
surfcontour("set title 'Surface With Contours, No Labels'", (-5, 5, 40), f2, "lc 'orange'", labels = false)
```

#### Heatmap plots

| command | settings theme | plotline theme |
|:--------|:---------------|:---------------|
|`heatmap` | `:heatmap` | `:pm3d` |

```@example 2dt
theme = @gpkw {palette = :matter, title = Q"Heatmap"}
heatmap(theme, :notics, :nocb, :labels, (-10, 10, 70), f2)
```

##### Contour lines on heatmap

It is possible to include contour lines in a heatmap plot. The following example is
taken from [this gnuplot blog post]
(https://gnuplot-tricks.blogspot.com/2009/07/maps-contour-plots-with-labels.html).
The function `Gaston.plotwithtable` returns a `Gaston.DataTable`, which wraps
`IOBuffer`. It can be used as an argument to `plot`.
```@example 2dt
# define function to plot
x = y = range(-5, 5, 100)
f4(x,y) = sin(1.3*x)*cos(0.9*y)+cos(.8*x)*sin(1.9*y)+cos(y*.2*x)

# obtain function contours using 'plot with table'
settings = """set contour base
              set cntrparam level incremental -3, 0.5, 3
              unset surface"""
contours = Gaston.plotwithtable(settings, x, y, f4)

# calculate meshgrid for heatmap plot
z = Gaston.meshgrid(x, y, f4)

# plot heatmap and contours
plot("""unset key
        unset colorbox
        set palette rgbformulae 33,13,10""",
        x, y, z, "with image")
plot!(contours, "w l lw 1.5 lc 'slategray'")
```

## Other examples

#### [3-D Euler spiral (Clothoid)](https://en.wikipedia.org/wiki/Euler_spiral)

```@example 2dt
using QuadGK
z = range(-5, 5, 200)
fx(z) = sin(z^2)
fy(z) = cos(z^2)
x = [quadgk(fx, 0, t)[1] for t in z]
y = [quadgk(fy, 0, t)[1] for t in z]
splot("""unset zeroaxis
         set tics border
         set xyplane at -5 
         set view 65,35
         set border 4095""",
         x, y, z, "w l lc 'black' lw 1.5")
```

#### Waterfall

Inspired by this [Julia Discourse discussion](https://discourse.julialang.org/t/how-to-produce-a-waterfall-plot-in-julia/93441).
```@example 2dt
x = -15:0.1:15
y = 0:30
u1data = [exp(-(x-0.5*(y-15))^2) for x in x, y in y]
Zf = fill(0.0, length(x))
f = Figure()
Gaston.set!(f(1), """set zrange [0:2]
               set tics out
               set ytics border
               set xyplane at 0
               set view 45,5
               set zrange [0:3]
               set xlabel 'ξ' offset -0,-2
               set ylabel 't'
               set zlabel '|u|'
               set border 21""")
for i in reverse(eachindex(y))
    Y = fill(y[i], length(x))
    Z = u1data[:,i]
    splot!(x, Y, Z, Zf, Z, "w zerrorfill lc 'black' fillstyle solid 1.0 fc 'white'")
end
f
```

## Plot recipes

There are two ways to extend Gaston to plot arbitrary types. The first is to define a new
function that takes the required type, and returns a `Gaston.Figure`. For example, we may wish to plot
complex data as two subplots, with the magnitude and phase of the data. This can be done as follows:
```@example 2dt
function myplot(data::Vector{<:Complex}; kwargs...)
                    x = 1:length(data)
                    y1 = abs2.(data)
                    y2 = angle.(data)
                    Gaston.sthemes[:myplot1] = @gpkw {grid, ylabel = Q"Magnitude"}
                    Gaston.sthemes[:myplot2] = @gpkw {grid, ylabel = Q"Angle"}
                    Gaston.pthemes[:myplot1] = @gpkw {w = "lp"}
                    Gaston.pthemes[:myplot2] = @gpkw {w = "p", lc = "'black'"}
                    f = Figure(multiplot = "layout 2,1")
                    plot(f[1], x, y1, stheme = :myplot1, ptheme = :myplot1)
                    plot(f[2], x, y2, stheme = :myplot2, ptheme = :myplot2)
                    return f
                end
t = range(0, 1, 20)
myplot(exp.(t) .* cis.(2*pi*7.3*t))
```
The use of themes allows the user to modify the default properties of the plot, by modifying the
themes (such as `Gaston.sthemes[:myplot1]`) instead of having to re-define `myplot`.

The second way to plot an arbitrary type is to define a new method of `Gaston.convert_args` for that
type (or `Gaston.convert_args3` for 3-D plots). Here's an example:

```@example 2dt
using Gaston: PlotObject, TimeSeries, TSBundle
import Gaston: convert_args

struct MyType end

function convert_args(x::MyType)
    t1 = range(0, 1, 40)
    t2 = range(-5, 5, 50)
    z = Gaston.meshgrid(t2, t2, (x,y) -> cos(x)*cos(y))
    @gpkw PlotObject(
        TSBundle(
            TimeSeries(1:10, rand(10)),
            settings = {title = Q"First Axis"}
        ),
        TSBundle(
            TimeSeries(t1, sin.(5t1), pl = {lc = Q"black"}),
            TimeSeries(t1, cos.(5t1), pl = {w = "p", pt = 16}),
            settings = {title = Q"Trig"}
        ),
        TSBundle(
            TimeSeries(t2, t2, z, pl = {w = "pm3d"}, is3d = true),
            settings = {title = Q"3D",
                        tics = false,
                        palette = (:matter, :reverse)}
        ),
        TSBundle(
            TimeSeries(1:10, 1:10, rand(10,10), pl = "w image"),
            settings = {tics, title = false}
        ),
        mp_settings = "title 'A Four-Axes Recipe' layout 2,2"
    )
end

figure().multiplot = "" # hide
plot(MyType())
```


================================================
FILE: docs/v1/extending.md
================================================
# Extending Gaston

Gaston offers multiple plotting commands that cover most cases of general data plotting. However, it is sometimes convenient to extend its capabilities to cover more specific use cases. One simple case is the generation of consistent plots of a certain type. A more complex example is plotting of new types, not just numerical data. We illustrate these two cases with examples.

## Consistent plots in a specific application

Consider this situation: we are designing and simulating a new communications algorithms and we need to plot the resulting bit error rate (BER). BER plots have certain characteristics:

* The x label defaults to `E_b/N_0 (dB)`.
* The y label defaults to `Bit Error Rate`, but could also be `Symbol Error Rate`.
* The y axis is logarithmic, and we want the tics to be negative powers of ten.
* The grid should be visible.
* The plot title defaults to `BER as a function of SNR`.
* We wish to have markers at each SNR value, defaulting to full diamonds.
* We like to use a thick line (width 2) that defaults to color blue.

Let us define a new plot command, called `berplot`, that allows us to do this.

```@example ext
using Gaston # hide
set(reset=true) # hide
set(termopts="size 550,325 font 'Consolas,11'") # hide
function berplot(snr, ber, axes::Axes = Axes() ; ser = false, args...)

    # support an optional Boolean argument to control the y label
    ylab = "'Bit Error Rate'"
    if ser
        ylab = "'Symbol Error Rate'"
    end

    # Build the default axes configuration
    a = Axes(title  = "'BER as a function of SNR'",
             xlabel = "'E_b/N_0 (dB)'",
             ylabel = ylab,  # use the label specified by ser
             axis   = "semilogy",
             grid   = "on",
             ytics  = "out format '10^{%T}'"
            )

    # Execute the plot command with the default curve configuration. Note that
    # the default axes configuration is merged with the one provided by the
    # user, giving preference to the latter.
    plot(snr, ber, Gaston.merge(a, axes) ;
         w = :lp,
         lc = :blue,
         lw = 2,
         marker = "fdmd",
         args...
        )
end
```

Let us try it out:

```@example ext
using SpecialFunctions
Q(x) = 0.5erfc(x/sqrt(2))
snr = 3:15
snr_dB = 10log10.(snr)
ber = 4Q.(sqrt.(snr))
berplot(snr_dB, ber)
```

Let us verify that we can control the y label:

```@example ext
berplot(snr_dB, ber, ser = true)
```

And verify that we can override the defaults:

```@example ext
berplot(snr_dB, ber, Axes(grid = "xtics mytics"), lc = :orange)
```

## Plotting a new type

As an example, let us extend `plot` to display the frequency and phase response of a filter designed with [DSP.jl](https://docs.juliadsp.org/stable/filters/). The idea is to plot magnitude and phase responses in two subplots, Matlab-style.

```@example ext
using DSP, FFTW

fs = 200.
df = digitalfilter(Lowpass(50, fs=fs), Chebyshev1(21, 0.5))
typeof(df)
```

We cannot run `plot(df)` directly, since neither Gaston nor gnuplot know what to do with data of this type.. We need to extend `plot` to type `ZeroPoleGain`, wee can also define a default plot configuration.

```@example ext
# We need to explicitly import plot, since we're extending it.
import Gaston.plot

function plot(x::ZeroPoleGain, axes::Axes = Axes() ; fs = π, n = 250, args...)
    # The filter's frequency response is obtained with freqz.
    f = range(0, fs/2, length = n)
    fz = freqz(x, f, fs)
    mg = abs.(fz)
    ph = angle.(fz)

    # magnitude plot
    a = Axes(title = "'Magnitude response'",
             grid = :on,
             xlabel = "'Frequency'",
             ylabel = "'Magnitude'")
    p1 = plot(f, mg, merge(a, axes) ; handle = Gaston.nexthandle(), args...)

    # phase plot
    a = Axes(title = "'Phase response'",
             grid = :on,
             xlabel = "'Frequency'",
             ylabel = "'Phase'")
    p2 = plot(f, ph, merge(a, axes) ; handle = Gaston.nexthandle(), args...)

    plot([p1 ; p2])

end
```

Note that, when creating plots for the magnitude and phase response, the function `Gaston.nexthandle()` is used to select a new, unused handle. The reason is that `plot` overwrites the last created plot. So, when defining `p1` we run the risk of overwriting the last plot the user created, and when defining `p2` we run the risk of overwriting `p1`. These are avoided by choosing handles that are not shared with any other plots.

Let us test it:

```@example ext
set(termopts = "size 550, 600 font 'Consolas,11'")  # hide
plot(df, fs=fs)
```


================================================
FILE: docs/v1/extguide.md
================================================
# Extension Guide


================================================
FILE: docs/v1/faq.md
================================================
# Usage notes and FAQ

## How to set the terminal

Gnuplot supports a huge amount of terminals. Most modern gnuplot installations should support the `qt` terminal. A different terminal can be selected with

    set(term = t::String)

where `newterm` is the desired terminal. Most terminals accept a configuration string, which can be set with

    set(termopts = opt::String)

For example, to set the font on the qt terminal to Consolas size 11, one could do

    set(term = "qt")  # not needed in most installations
    set(termopts = "font 'Consolas,11')

!!! info "Choosing a terminal on Windows"
    On Windows, Gaston selects the `windows` terminal by default. Changing the terminal is not recommended, since they tend to be very slow and have other issues (for example, see [here](https://github.com/mbaz/Gaston.jl/issues/136) and [here](https://sourceforge.net/p/gnuplot/bugs/2279/)).

## What settings are available in Gaston?

The `set` command can be used to configure Gaston's behavior. The following settings are available:

| Setting | Purpose |
|:--------|:--------|
| term | Sets gnuplot's terminal. |
| termopts | Sets the terminal's options. |
| mode    | If set to "null", plots are not shown. |
| preamble | A string that is sent to gnuplot for every plot. |
| debug | If set to `true`, all data sent to gnuplot is printed on the screen. |
| saveopts | A string that specifies options when saving a plot. |
| showable | For IJulia, Documenter.jl, Juno and similar uses. Defaults to `"png"`; all plots are generated in PNG format only. Set to `"svg"` to enable SVG plots, or `"png+svg"` to enable both.
| timeout | How long Gaston waits for gnuplot to complete a plot. Defaults to 10 seconds (20 on Windows and Mac); you may need to set it higher if your computer is slow or you're plotting lots of data.

## How to plot text or sixels?

Plots can be rendered using text on the console by setting the terminal to `dumb`:

```julia
using Gaston  # hide
set(reset=true)  # hide
set(term = "dumb", termopts = "size 80,25 ansirgb")
t = -5:0.1:5
plot(t, sin);
plot!(t, cos)
```

![](assets/dumb.png)

To plot with sixels, use

    set(term = "sixelgd")

A terminal that supports sixels is required (for example, xterm in mode vt340 (invoked as `xterm -ti vt340`).

![](assets/sixels.png)

# How to configure plot size in Documenter.jl, IJulia, etc?

In these environments, the front-end chooses among all supported MIME types. Gaston supports PNG and SVG images. Some of these front-ends, though, ask Gaston to produce plots in both formats, and then choose SVG. This is a waste of resources, and combined with the fact that plots in SVG format can grow very large, it is recommeded to configure Gaston to produce only PNG files. This is achieved with

    set(ijulia = "png")

The `png` terminal can be configured with

    set(termopts=...)

For example, the plots in this document are created with these settings:

    set(termopts="size 550,325 font 'Consolas,11'")

## I run `plot` inside a `for` loop and no plots are produced! (or: Julia's display system)

Julia separates the calculation of a result from the display of the result (see [custom pretty-printing](https://docs.julialang.org/en/v1/manual/types/#man-custom-pretty-printing-1) and [multimedia I/O](https://docs.julialang.org/en/v1/base/io-network/#Multimedia-I/O-1) in Julia's documentation). This mechanism is very powerful; in Gaston, it enables plotting to the REPL, Jupyter, Juno, or in Documenter.jl with just a few lines of code. In other words, plotting is not a side effect of running `plot`, the way it is in, say, Matlab; rather, a plot is produced when a result of type `Gaston.Figure` is returned by some code.

While elegant and powerful, this mechanism can also be surprising if you're used to side-effect plotting. None of the following code samples display any plots:

```julia
y = rand(20)
plot(y);  # note the final ; suppreses displaying the result
```

```julia
# nothing is returned by the for loop
for k = 1:5
    plot(k*y)
end
```

```julia
# function that does not return a figure
function f(y)
    plot(sin.(y))
    println("Sum = $(sum(y))")
end
```

The common problem in the code samples above is that a figure is never returned; in consequence, no figure is displayed. This can be fixed by making sure your code returns a figure; or alternatively, save the figure in a variable and display it when it is convenient. For example:

```julia
p = Gaston.Figure[]
for k = 1:5
    push!(p, plot(k*y))
end
```

Now, `p[3]` returns the third plot (for example). Another way to force the figure to be rendered is to call `display()`:

```julia
# all five figures are displayed
closeall()
for k = 1:5
    figure()
    display(plot(k*y))
end
```
## How does gnuplot report errors?

Gnuplot's main drawback, from a usability standpoint, is that it is not a library; it is designed to be used interactively. Gaston simulates a user typing interactive commands in a gnuplot session. Gaston tries to catch any errors reported back by gnuplot.

An example of an error returned by gnuplot and caught by Gaston:

```julia
using Gaston # hide
y = rand(20)
plot(y, plotstyle="linepoints")  # missing an 's'
```

results in an error message like:

```julia
┌ Warning: Gnuplot returned an error message:
│
│ gnuplot> plot '/tmp/jl_d8yIs9' i 0  with linepoints
│                                                     ^
│          line 0: unrecognized plot type
│
└ @ Gaston ~/.julia/dev/Gaston/src/gaston_llplot.jl:172
```

Gaston does its best effort to read and display any warnings or errors produced by gnuplot, and to recover gracefully. In some corner cases, it might happen that the communication link enters an unforeseen state and a restart is required. Please file a Gaston issue if you experience this.

## Support

Please post support questions to [Julia's discuss forum](https://discourse.julialang.org/tag/plotting).

## Contributing

Bug reports, suggestions and pull requests are welcome at [Gaston's github page](https://github.com/mbaz/Gaston.jl)


================================================
FILE: docs/v1/figures.md
================================================
# Managing multiple figures

When using a graphical terminal such as `qt` or `wxt`, it is possible to have multiple figures on the screen at one time. Gaston provides a few commands to help manage them.

Each figure is identified by its handle, which must be an integer larger than zero. Handles don't have to be consecutive. Plotting commands accept an optional handle argument, which directs the plot to the specified figure. For example, in this code:

```julia
t = -5:0.01:5
plot(t, sin)
figure()  # creates a new figure
plot(t, cos)
plot!(t, sin.(t).^2, handle = 1)
```
the cosine will be plotted in a second figure, while the squared sine will be appended to the first figure.

```@docs
figure
closefigure
closeall
```


================================================
FILE: docs/v1/index.md
================================================
```@meta
Author = "Miguel Bazdresch"
```

# Gaston.jl

Gaston (source code [here](https://github.com/mbaz/Gaston.jl)) is a Julia package for plotting. It provides an interface to [gnuplot](http://www.gnuplot.info), a mature, powerful, and actively developed plotting package available on all major platforms.

Gaston emphasizes easy and fast plotting on the screen, notebook or IDE. Knowledge of gnuplot is not required, but some familiarity is beneficial. Gaston also exposes the full power of gnuplot, for more expert users.

```@example t2
using Gaston, SpecialFunctions
set(reset=true) # hide
set(termopts="size 550,325 font 'Consolas,11'") # hide
x = y = 0:0.075:10
surf(x, y, (x,y) -> besselj0(y)*x^2, with = "pm3d",
     Axes(view = (45, 45),
          pm3d = "lighting primary 0.5 specular 0.4",
          key = :off)
     )
```

(Image inspired by [What's new in gnuplot 5.2?](https://lwn.net/Articles/723818/))

## Gaston features

* Plot using graphical windows, and keeping multiple plots active at a time, with mouse interaction. A browser is not required to show plots.
* Plot also directly to the REPL, using text (ASCII) or [sixels](https://en.wikipedia.org/wiki/Sixel).
* Plot in Jupyter, Juno or VS Code.
* "Recipes" to generate common 2-D and 3-D plots, such as stem plots, histograms, images, surfaces, contour and heatmaps.
* Easy definition of custom plotting commands for specific types, or with specific defaults.
* Save plots to multiple formats, including pdf, png and svg.
* Color palettes from [ColorSchemes.jl](https://github.com/JuliaGraphics/ColorSchemes.jl).
* Export plots for integration into Latex documents.
* A simple interface to almost the full power of gnuplot, for users who have more experience with it.
* Fast first plot: load package, plot, and save to pdf in less than six seconds. Subsequent plots take a few hundreds of milliseconds.
* A simple interface to manage multiple plots, using commands such as `figure()`, `closeall()`, etc.

### Gaston and Gnuplot.jl: two philosophies

[Gnuplot.jl](https://github.com/gcalderone/Gnuplot.jl) is another front-end for gnuplot, with comparable capabilities to Gaston. An example serves to illustrate the differences in how the two packages approach the interface problem. Consider [this example plot](https://gcalderone.github.io/Gnuplot.jl/v1.3.0/basic/#Multiple-datasets,-logarithmic-axis,-labels-and-colors,-etc.-1):

```julia
x = 1:0.1:10
@gp    "set grid" "set key left" "set logscale y"
@gp :- "set title 'Plot title'" "set label 'X label'" "set xrange [0:*]"
@gp :- x x.^0.5 "w l tit 'Pow 0.5' dt 2 lw 2 lc rgb 'red'"
@gp :- x x      "w l tit 'Pow 1'   dt 1 lw 3 lc rgb 'blue'"
@gp :- x x.^2   "w l tit 'Pow 2'   dt 3 lw 2 lc rgb 'purple'"
```

This shows that Gnuplot.jl essentially allows one to write gnuplot commands directly in Julia. The same plot in Gaston would be:

```@example t2
x = 1:0.1:10
plot(x, x.^0.5,
     w = "l",
     legend = "'Pow 0.5'",
     dt = 2,
     lw = 2,
     lc = :red,
     Axes(grid = :on,
          key = "left",
          axis = "semilogy"))
plot!(x, x,
      w = :l,
      leg = :Pow_1,
      dt = 1,
      lw = 3,
      lc = :blue)
plot!(x, x.^2,
      curveconf = "w l tit 'Pow 2' dt 3 lw 2 lc 'purple'")
```

In summary, Gaston offers a function-based interface, and gnuplot commands can be specified in a few different ways, with convenient notation, such as the optional use of "legend" instead of gnuplot's "title", symbols to avoid typing quote marks (") all the time, and others that are described later in this document.

## Installation

Gaston requires Julia version 1.3.0 or above, and requires Gnuplot version 5.0 or above (version 5.2.8 is recommended). You should install gnuplot on your system prior to using Gaston. On Linux, it is highly recommended that you select a version with support for Qt: on Debian and Ubuntu, you will need `gnuplot-qt`.

To install Gaston from the Julia REPL, run

```julia
julia> ]add Gaston
```

Typing `]` switches the Julia REPL to the package manager, and the `add` command installs the package. To exit the package manager, hit the backspace key.

## Gnuplot configuration

Gaston respects user configuration settings in gnuplot's startup file. Left un-configured, gnuplot's plots are less than attractive. The following minimum configuration is suggested (and was used to generate the plots in this document):

    set linetype 1 lc rgb "blue" pt 3
    set linetype 2 lc rgb "red" pt 4
    set linetype 3 lc rgb "green" pt 6
    set linetype 4 lc rgb "black" pt 12
    set linetype 5 lc rgb "blue" pt 5
    set linetype 6 lc rgb "red" pt 1
    set linetype 7 lc rgb "green" pt 2
    set linetype 8 lc rgb "black" pt 7
    set linetype cycle 8
    set style data lines
    set key noautotitle
    set auto fix
    set offsets graph .05, graph .05, graph .05, graph .05

The configuration file is `~/.gnuplot` in Unix-like systems, and `%APPDATA%\GNUPLOT.INI` in Windows.

## Next steps

Load Gaston into your Julia session with

```julia
using Gaston
```

The [Introduction to plotting](@ref) has more information about basic use and configuration.

There is a [2-D plotting tutorial](@ref twodeetut) and a [3-D plotting tutorial](@ref threedeetut).

The [Extending Gaston](@ref) section explains how to extend Gaston by creating your own "recipes", both for specific kinds of plots, and for plotting data of specific types.

There is a section on  [Managing multiple figures](@ref) and all related commands.

The [2-D Gallery](@ref twodeegal) and [3-D Gallery](@ref threedeegal) show many plotting examples.

The [Usage notes and FAQ](@ref) section includes additional usage examples and answers frequent questions.

## Gnuplot resources

These websites have more information on gnuplot and how to use it:

* [Official website](http://www.gnuplot.info/)
* [Official demo gallery](http://gnuplot.sourceforge.net/demo_5.2/)
* [PDF documentation for 5.2](http://www.gnuplot.info/docs_5.2/Gnuplot_5.2.pdf)
* [A good blog on gnuplot](http://www.gnuplotting.org/)

## Running tests

Gaston includes an extensive test suite, which can executed with:

```julia
julia> ]test Gaston
```

All tests should pass (but a few may be skipped).

## Support

Please post support questions to [Julia's discuss forum](https://discourse.julialang.org/tag/plotting).

## Contributing

Bug reports, suggestions and pull requests are welcome at [Gaston's github page](https://github.com/mbaz/Gaston.jl)


================================================
FILE: docs/v1/introduction.md
================================================
```@meta
Author = "Miguel Bazdresch"
```

# Introduction to plotting

Gaston supports essentially all 2-D plots styles that gnuplot is capable of, including regular function plots, plots with logarithmic axes, scatter, stem and step plots, bar plots and histograms, images, etcetera.

It can also create 3-D plots, including wireframe, surface, scatter and contour plots.

This section presents the basic usage of `plot` and `plot!`. Examples of specific plot types, such as cloud points, stem plots, and images, are presented in [2-D plotting tutorial](@ref twodeetut). For 3-D plots, see [3-D plotting tutorial](@ref threedeetut).

## `plot` and `plot!` commands

The main 2-D plotting commands are `plot` and `plot!`. To plot a vector `y` against a vector `x`, use `plot(x,y)`:

```@example intro
using Gaston # hide
set(reset=true) # hide
set(termopts="size 550,325 font 'Consolas,11'") # hide
t = 0:0.01:1
plot(t, sin.(2π*5*t),
     linecolor  = :coral,
     Axes(title = :First_Plot)
    )
```

To add a second curve, use `plot!`:

```@example intro
plot!(t, cos.(2π*5*t),
      plotstyle = "linespoints",
      pointtype = "ecircle",
      linecolor = "'blue'"
     )
```

Curves are added to a figure one by one; the first curve is plotted with `plot`, and the rest with succesive `plot!` commands.

The commands `plot` and `plot!` take three kinds of arguments:
* Data, in the form of vectors `x`, `y`, etcetera.
* Configuration related to the data's appearance: line color, line width, markers, line style, etcetera. These are passed to `plot` as regular arguments (for example, `linecolor = :coral` above).
* Configuration related to the entire figure: title, tics, ranges, grid, etcetera. These must be wrapped in `Axes()`; for example, `Axes(title = :First_Plot)`. Only `plot` accepts these arguments.

## Figure and curve configuration

An example can be worth a thousand words. The following commands are all exactly equivalent:

```julia
plot(t, sin.(2π*5*t),
     with       = "linespoints",
     linecolor  = :coral,
     Axes(title = :First_Plot,
          xtics = "(0.25, 0.5, 0.75)")
    )
```

```julia
plot(t, sin.(2π*5*t),
     curveconf = "with linespoints linecolor 'coral'",
     Axes(title = :First_Plot,
          xtics = "(0.25, 0.5, 0.75)")
    )
```

```julia
A = Axes(title = :First_Plot, xtics = "(0.25, 0.5, 0.75)")
plot(t, sin.(2π*5*t), A,
     plotstyle = :linespoints,
     lc  = "'coral'"
    )
```

```julia
plot(t, sin.(2π*5*t),
     curveconf = "w lp lc 'coral'",
     Axes(axesconf = """set title 'First Plot'
                        set xtics (0.25, 0.5, 0.75)""")
    )
```

```julia
plot(t, sin.(2π*5*t),
     curveconf = "w lp lc 'coral'",
     Axes(axesconf = "set title 'First Plot'",
          xtics = "(0.25, 0.5, 0.75)")
    )
```

## How arguments are handled

Gaston has a few rules to handle arguments, and supports special syntax to make passing commands to gnuplot more convenient. All configuration commands are given as key-value arguments.

* Values can be given in quotes (`"'red'"`) or as symbols (`:red`).
* Values in quotes are passed directly to gnuplot.
* Symbol values are passed to gnuplot wrapped in single quotes. For example, `linecolor = :blue` in the example above is translated as `linecolor 'blue'`.
* In symbols, underscores are converted to spaces. For example, `title = :First_Plot` is translated as `set title 'First Plot'`.
* When an argument is a vector, each element is handled as a separate argument. For example, `xtics = [1:2:5, "reverse"]` is translated to two separate gnuplot commands, `set xtics 1, 2, 5` and `set xtics reverse`.
* To send a `set` command without options, like `set grid`, use (for example) `grid = :on` (or `"on"`, or `true`).
* To send an `unset` command, use (for example) `tics = :off` (or `"off"`, or `false`).

!!! info "Interaction with gnuplot"
    Keyword arguments wrapped in `Axes()` are converted to gnuplot `set` commands. For example,

        Axes(pm3d = "lighting primary 0.5")

    is sent to gnuplot as

        set pm3d lighting primary 0.5

    Other keyword arguments are used as plot elements; for example,

        w = :lp, u = "1:3"

    is sent to gnuplot as

        plot 'filename' w lp u 1:3

## Configuring a figure's appearance

As explained above, a figure's configuration is given as key-value pairs wrapped in `Axes()`. Some arguments have special syntax for convenience:

* The `axis` argument sets the axis type:
    * `axis = "semilogx"` →  `set logscale x`
    * `axis = "semilogy"` →  `set logscale y`
    * `axis = "semilogz"` →  `set logscale z`
    * `axis = "loglog"` →  `set logscale xyz`

* Tics are set with `xtics`, `ytics`, `ztics` or `tics`:
    * `tics = a:b:c` →  `set tics a, b, c`
    * `tics = (a:b:c, ["l1" "l2" ... "lN"])`  →  `set tics ("l1", a, ..., "lN", c)`
    * `tics = ([t1 t2 ... tN], ["l1" "l2" ... "lN"])`  →  `set tics ("l1", t1, ..., "lN", tN)`

In the last two cases, the first element in the tuple represents the numerical tics, and the second element is the set of labels.

Example:
```@example intro
plot(t, sin.(2π*5*t),
     linecolor  = :coral,
     Axes(title = "'Tics Example'",
          xtics = [(0.25:0.5:1, ["1/4" "3/4"]), "rotate"])
    )
```

* Ranges are specified with `xrange`, `yrange`, `zrange` or `cbrange`:
    * `{x,y,z,cb}range = (low, high)` → `set {x,y,z,cb}range [low|high]`
    * `{x,y,z,cb}range = (-Inf, high)` → `set {x,y,z,cb}range [*|high]`
    * `{x,y,z,cb}range = (low, Inf)` → `set {x,y,z,cb}range [low|*]`

Example:
```@example intro
plot(t, sin.(2π*5*t),
     linecolor  = :coral,
     Axes(title = :Range_Example,
          yrange = (-Inf, 2))
    )
```

* A set of linetypes with the colors specified by a palette from [ColorSchemes.jl](https://github.com/JuliaGraphics/ColorSchemes.jl). The palette name must be specified as a symbol. For example,

```@example intro
t = range(-2, 2, length = 100)
f(t, σ) = exp.(-σ*abs.(t))
A = Axes(title = :Linetypes_Example, linetype = :sunset)
plot(t, f(t,0.5), lw = 3, A)
plot!(t, f(t, 1), lw = 3)
plot!(t, f(t, 1.5), lw = 3)
plot!(t, f(t, 2), lw = 3)
plot!(t, f(t, 2.5), lw = 3)
```

* A string containing gnuplot commands may be passed as argument `axesconf`. This string is sent to gnuplot without modification.

* In addition, a string of gnuplot commands may be specified using Gaston's configuration setting `preamble`. This string will be used in all subsequent plots, before the commands specified in `Axes()`. This may be useful to configure gnuplot in environments where it is not feasible to have a permanent gnuplot configuration file. For example,

```julia
set(preamble = "set offsets graph .05, graph .05, graph .05, graph .05")
```

## Configuring a curve's appearance

All key-value arguments provided to `plot` and not wrapped in `Axes()` are interpreted as a curve configuration. Some of them have offer some convenient syntax:

* The plot style can be specified with the `with` key. The keys `with`, `w` and `plotstyle` are synonyms.

* The point type is specified with the key `pointtype`. This key is synonym with `pt` and `marker`. Gnuplot accepts markers specified as numbers. In addition, Gaston accepts the following descriptive strings:
| Value | Meaning |
|-------|---------|
| `"dot"` | Single pixel |
| `"+"` | A plus sign|
| `"x"` | A cross |
| `"*"` | An asterisk|
| `"ecircle"` | Empty circle |
| `"fcircle"` | Full circle |
| `"esquare"` | Empty square |
| `"fsquare"` | Full square |
| `"etrianup"` | Empty up triangle |
| `"ftrianup"` | Full up triangle |
| `"etriandn"` | Empty down triangle |
| `"ftriandn"` | Full down triangle |
| `"edmd"` | Empty diamond |
| `"fdmd"` | Full diamond |
Other strings are passed to gnuplot wrapped in single quotes; for example, `pt = "λ"` is translated as `pointtype 'λ'`.

* A legend can be specified with the keys `legend`, `leg`, `title` or `t`.

* A full plot specification can be provided with the key `curveconf`. This overrides all other provided arguments. For example, this plot

```julia
t = 0:0.05:10pi
plot(t, cos, w=:lp, leg = :A_sine_wave, marker = "fdmd", pi = -20)
```

can equivalently be specified as:
```julia
cc = "w lp t 'A sine wave' pt 13 pi -20"
plot(t, cos, curveconf = cc)
```

## Data arguments

Most plotting commands accept data in a few different formats:

* `plot(y, args...)` assumes that `x = 1:length(y)`
* `plot(x, f::Function, args...)` applies function `f` to `x`.
* `plot(c, args...)` where `c` is complex, plots `real(c)` vs `imag(c)`.

In addition, gnuplot may use additional data to, for example, set a marker's size or color. These are called "supplementary data" by Gaston, and are provided to `plot` using the `supp` keyword argument. For example,

```@example intro
c = rand(30) .+ im*rand(30)
plot(c, supp = 3abs.(c), w = :p, marker = "ecircle", markersize = "variable")
```

## 3-D plotting

Gaston and gnuplot are fully capable of plotting surfaces and other kinds of 3-D plots such as contours and heatmaps. See the [3-D plotting tutorial](@ref threedeetut).

## Multiplot

Multiple plots can be included in the same figure. This is accomplished by calling `plot` with a matrix made up of other figures. If a matrix elements is `nothing`, then the corresponding subplot is left empty. An example:

```@example intro
t = 0.01:0.01:10pi
p1 = plot(t, cos, Axes(title = :Plot_1), handle = 1)
p2 = plot(t, t.^2, Axes(title = :Plot_2), handle = 2)
p4 = plot(t, exp.(-t), Axes(title = :Plot_4), handle = 4)
plot([p1 p2 ; nothing p4])
```

The `handle` argument is necessary because a `plot` command, by default, overwrites the previous plot. See the section on [Managing multiple figures](@ref) for more details on how handles work.

## Saving plots

To save a plot (or "print" it, in gnuplot's parlance), use the `save` command, which requires `term` and `output` arguments. Optionally, arguments specifying the `font`, `size`, `linewidth`, and `background` color may be given. These may be specified in a gnuplot command string with `saveopts`, which may also be specified in advance using `set(saveopts = "...")`. The following two examples are equivalent:

```julia
save(term = "png",
     output= "myfigure.png",
     font = "Consolas,10",
     size = "1280,900",
     linewidth = 1,
     background = "blue")
```

```julia
save(term = "png", output = "myfigure.png",
     saveopts = "font 'Consolas,10' size 1280,900 lw 1 background 'blue'")
```


================================================
FILE: docs/v1/plotguide.md
================================================
# Manual

This manual covers all aspects of using Gaston.

## Gaston Settings

### The terminal

By default, gnuplot chooses an appropriate terminal: `qt` or `wxt` on Linux, `windows` on Windows,
and `aqua` on MacOS.
The terminal can be set by changing the value of `Gaston.config.term`; for example:
```julia
Gaston.config.term = "pngcairo font ',10' size 700,400"
```
The terminals supported by gnuplot can be listed by running:
```julia
Gaston.terminals()
```

### Other settings

* `Gaston.config.output`: controls how plots are displayed. Possible values are:
    * `:external`: plots are displayed in GUI windows. This is the default value.
    * `:echo`: sends text-based plots (like `png` and `sixelgd`) back to the terminal. Useful for notebooks and IDEs, and for plotting on the terminal.
    * `:null`: execute all plot commands but do not actually produce a plot.

    If Gaston detects it is running in a notebook environment, it automatically sets the terminal
    to `pngcairo` and `config.output` to `:echo`.
* `Gaston.config.embedhtml`: `Bool`, defaults to `false`. Enables embedding plots in HTML; useful to enable interactivity in Pluto and Jupyter notebooks. See examples in the included Pluto notebooks.

## Plotting

A `plot` command takes three different kinds of arguments: settings, data, and plotline, in that
order.
```julia
plot([settings...], data..., [plotline...])
```
Further curves may be added using `plot!`. (For 3-D plots, use `splot` instead.)

More specifically, a `plot` command takes:
* Zero or more **settings** arguments, which get converted to gnuplot `set` commands.
* One or more **data** arguments, which are written to a file in the format gnuplot expects.
* Zero or more **plotline** arguments, which are appended to gnuplot's `plot` or `splot` commands.

Gaston provides several alternative ways to specify these.

### Settings and Plotlines

All the following are equivalent.

* One single string
```julia
plot("set grid
      unset key
      set title 'A Sinusoid'",
     x, y,
     "with linespoints lc 'green'")
```
* One string per setting
```julia
plot("set grid", "unset key", "set title 'A Sinusoid'",
     x, y,
     "with linespoints", "lc 'green'")
```
* Keywords with `@plot`
```julia
@plot({grid = true, key = false, title = "'A Sinusoid'"},
      x, y,
      {with = "linespoints", lc = "'green'"})
```

Keyword options are enclosed in curly brackets `{}`. To set an option without arguments,
such as `set grid`, use either a lone `grid`, or `grid = true`. To unset an option, such as in
`unset grid`, use ` grid = false`.  Options can be repeated; each one will be converted to a
separate `set` line.

`@plot` also accepts strings, and in fact strings and keywords may be combined:
```julia
@plot({grid, key = false}, "set title 'A Sinusoid'",
      x, y,
      "with linespoints", {lc = "'green'"})
```
It is possible to omit the parenthesis, but in this case the command must fit in a single line.
```julia
@plot {grid, key = false, title = "'A Sinusoid'"} x y {with = "lp", lc = "'green'"}
```
For 3-D plots, use the macro `@splot`.

#### Quoted strings

All strings passed to gnuplot must be enclosed in single quotes, such as in `lc = "'green'"` in the
example above. The `Q` string macro can help reduce the number of quotes needed:
```julia
@plot {grid = true, key = false, title = sqs"A Sinusoid"} x y {with = "lp", lc = Q"green"}
```
This macro turns `"abc"` into `"'abc'"`.

### Data

Data to be plotted can be provided as vectors and/or matrices. Gaston converts the data to a
format compatible with gnuplot. Three cases are supported:
* All data arguments are vectors.
* The first two arguments are vectors of length `n` and `m`, and the third argument is a matrix
of size `n x m`; further arguments are optional.
* All provided arguments are matrices of size `n x m`.

#### Functions

Functions can be plotted directly, with a given range and number of samples, which
can be specified in the following alternative ways:
```julia
# g is a function
plot(g)            # plots `g` evaluated at 100 samples, from -10 to 9.99
plot((a, b), g)    # plots `g` evaluated at 100 samples, from a to b
plot((a, b, c), g) # plots `g` evaluated at c samples, from a to b
plot(x, g)         # plots g.(x)
```

#### Plot with table

In some cases, it is useful to have gnuplot produce plot data in a "table" format, which can then
be plotted. See an example in [Contour lines on heatmap](@ref). The function `Gaston.plotwithtable`
returns a `Gaston.DataTable` storing the table. All plot commands accept this type.

### Simple themes

Frequently-used settings or plotlines may be stored in a theme; the `@gpkw` macro processes
keyword arguments wrapped in curly brackets.
```julia
theme = @gpkw {grid, key = false}
plot(theme, x, y)
```
Themes may be combined with other themes and/or with strings:
```julia
theme2 = @gpkw {xlabel = Q"X"}
plot(theme, "set title 'A Sinusoid'", theme2, x, y)
```
Themes can also be used for plotlines, and these may also be combined with other themes and/or
strings.
```julia
pltheme = @gpkw {w = "lp", pt = "'o'", ps = 3}
plot(theme, "set title 'A Sinusoid'", theme2, x, y, pltheme)
```
Gaston includes a few generic themes:

|Axis themes | Description |
|-----------:|:------------|
| :notics | Removes all tics |
| :labels | Generic axis labels (`x`, `y`, `z`) |
| :nocb   | Removes colorbox |
| :unitranges | Set all ranges to `[-1:1]` |

For example, the following command plots a sine wave with no tics and generic `x` and `y` axis
labels:
```julia
plot(:notics, :labels, "set title 'Example'", (-1, 1), sin)
```
Themes are also used to provide common plot types (illustrated in the [Themes](@ref) section). These
specialized plot commands and the themes they use are:

| Commands | Settings theme | Plotline theme |
|----------|----------------|----------------|
| `scatter`, `scatter!` | `:scatter`, `:scatter3` | `:scatter` |
| `stem`, `stem!` | None | `:stem`, `:impulses` |
| `bar`, `bar!` | `:boxplot` | `:box` |
| `barerror`, `barerror!` | `:boxerror` | `:box` |
| `histogram` | `:histplot` | `:box`, `:horhist` (1-D); `:image`  (2-D) |
| `imagesc` | `:imagesc` | `:image`, `:rgbimage` |
| `surf`, `surf!` |
| `contour` |
| `surfcontour` |
| `wireframe`, `wireframe!` |
| `wiresurf`, `wiresurf!` |
| `heatmap` | 

!!! note "Plotline themes"
    Plotline themes must be handled with care: gnuplot requires plotline options
    to be specified in a certain order, may not be repeated, and some combinations are invalid.
    It is very easy to create erroneous plotlines.

!!! note "Gaston lacks a parser"
    Gaston does not validate that the settings and plotline given to gnuplot are valid. When
    gnuplot returns an error or warning, it is echoed to the terminal.

## Multiplot

## Managing multiple figures

Gaston has the ability to create and manage multiple GUI plot windows simultaneously. Each window
is backed up by its own gnuplot process. The following commands can be used to create and control
multiple windows.

#### Creating and selecting figures

```
Figure()
```
Creates a new, empty figure. All figures are of type `Gaston.Figure`. Gaston keeps an internal
pointer to the figure, so that its not removed by the garbage collector.

When creating a figure intended for multiplot, a setting string can be included, with the
`multiplot` keyword.
```
Figure(multiplot = "title 'A Multiplot'")
```

When a figure is created, it becomes active, meaning that subsequent plot
commands will go to this figure. Of course, it is possible to keep figures in different variables:
```
fig1 = Figure()
fig2 = Figure()
```
and then redirect plot commands to the desired figure:
```
plot(fig1, ...)  # plot goes to fig1
plot!(fig2, ...) # new plot added to fig2
```
It is also possible to select figures using _handles_:
```
Figure("density") # figure with handle "density"
Figure(:volume)   # figure with handle :volume
Figure(33)        # figure with handle 33
```
Handles can be of any type. If not specified, handles are integers assigned in increasing order
starting from 1.

To plot in a specific figure, specify its handle using the keyword
argument `handle`:
```
plot(..., handle = :volume)
plot!(..., handle = 33)
scatter(..., handle = "density")
```

To activate a figure given its handle, use:
```
figure(handle)
```
or, given its index number `i`, use:
```
figure(index = i)
```
With no arguments, `figure()` returns the current figure.

To obtain the list of all current figures and their handles, and to identify the active figure,
use the unexported function `Gaston.listfigures()`.

#### Closing figures

To close the active figure, run
```
closefigure()
```
The figure with handle `h` can be closed with `closefigure(h)`. Likewise, to close figure `f` use `closefigure(f)`. Closing a figure quits the underlying gnuplot process. 

To close all figures, use `closeall()`.

## Saving plots

A plot can be saved to a file in any format supported by gnuplot, with the function
```
save(f ; output, term)
```
where the arguments are:
* `f`, which can be either a `Figure`, or an arbitrary value that is taken to be the handle of the figure to save. Defaults to the active figure.
* `output`, a string that specifies the filename. If empty, it defaults to `figure-` followed by the figure's handle; the filename extension is set to the first three characters of the gnuplot terminal (see next argument).
* `term`, specifies the gnuplot terminal used to save the plot; defaults to `"pngcairo font ',7'"`.

## Interacting with gnuplot




================================================
FILE: docs/v2/.gitignore
================================================
/.quarto/


================================================
FILE: docs/v2/Project.toml
================================================
[deps]
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
Gaston = "4b11ee91-296f-5714-9832-002c20994614"
GastonRecipes = "39356fd2-1f9e-4efe-8abf-5745c7d9f608"
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
QuartoNotebookRunner = "4c0109c6-14e9-4c88-93f0-2b974d3468f4"
QuartoTools = "5fded309-f5a0-485a-9129-b3749510da85"
TestImages = "5e47fb64-e119-507b-a336-dd2b206d9990"


================================================
FILE: docs/v2/_extensions/jjallaire/code-visibility/_extension.yml
================================================
title: Code Visibility
author: fast.ai
version: 1.0.0
contributes:
  filters:
    - code-visibility.lua


================================================
FILE: docs/v2/_extensions/jjallaire/code-visibility/code-visibility.lua
================================================



-- remove any lines with the hide_line directive.
function CodeBlock(el)
  if el.classes:includes('cell-code') then
    el.text = filter_lines(el.text, function(line)
      return not line:match("#| ?hide_line%s*$")
    end)
    return el
  end
end

-- apply filter_stream directive to cells
function Div(el)
  if el.classes:includes("cell") then
    local filters = el.attributes["filter_stream"]
    if filters then
      -- process cell-code
      return pandoc.walk_block(el, {
        CodeBlock = function(el)
          -- CodeBlock that isn't `cell-code` is output
          if not el.classes:includes("cell-code") then
            for filter in filters:gmatch("[^%s,]+") do
              el.text = filter_lines(el.text, function(line)
                return not line:find(filter, 1, true)
              end)
            end
            return el
          end
        end
      })
      
    end

  end
  
end

function filter_lines(text, filter)
  local lines = pandoc.List()
  local code = text .. "\n"
  for line in code:gmatch("([^\r\n]*)[\r\n]") do
    if filter(line) then
      lines:insert(line)
    end
  end
  return table.concat(lines, "\n")
end




================================================
FILE: docs/v2/_quarto.yml
================================================
project:
  type: website

website:
  title: "Gaston.jl"
  navbar:
    left:
      - href: index.qmd
        text: Introduction
      - href: tutorial.qmd
        text: Tutorial
      - href: examples.qmd
        text: Examples
      - href: recipes.qmd
        text: Recipes
      - href: manual.qmd
        text: Manual
      - href: migrate.qmd
        text: Migration Guide
      - href: reference.qmd
        text: API Reference
    tools:
      - icon: github
        href: https://github.com/mbaz/Gaston.jl
    search: true
    pinned: true
    reader-mode: true
    back-to-top-navigation: true

format:
  html:
    theme:
      - minty
    css: styles.css
    toc: true
    embed-resources: true

engines: ['julia']

execute:
  daemon: 600

filters:
  - code-visibility




================================================
FILE: docs/v2/assets/cairolatex.tex
================================================
\documentclass{article}
\usepackage{amsmath}
\usepackage{graphicx}
\usepackage{color}

\begin{document}
\begin{figure}
  \input{test.tex}
\end{figure}
\end{document}


================================================
FILE: docs/v2/assets/lorenz.jl
================================================
using Gaston
using ColorSchemes

Base.@kwdef mutable struct Lorenz
    dt::Float64 = 0.01
    σ::Float64 = 10
    ρ::Float64 = 28
    β::Float64 = 8/3
    x::Float64 = 1
    y::Float64 = 1
    z::Float64 = 1
end

function step!(l::Lorenz)
    dx = l.σ * (l.y - l.x)
    dy = l.x * (l.ρ - l.z) - l.y
    dz = l.x * l.y - l.β * l.z
    l.x += l.dt * dx
    l.y += l.dt * dy
    l.z += l.dt * dz
    return (l.x, l.y, l.z)
end

Nframes = 120
Npoints = 50
attractor = Lorenz()
x = Float64[];
y = Float64[];
z = Float64[];

s = @gpkw {xrange = (-30, 30),
           yrange = (-30, 30),
           zrange = (0, 60),
           xtics = "offset -1.2,0",
           xtics = "add ('' -30, '' 30)",
           ytics = "offset 1.2,0",
           ytics = "add ('' -30, '' 30)",
           origin = "-0.1, -0.1",
           size = "1.2, 1.2",
           object = "rectangle from screen 0,0 to screen 1,1 fillcolor 'black' behind",
           border = "back lc rgb '#eeeeee' lt 1 lw 1.5",
           view = "equal xyz",
           xyplane = "at 0"}

f = splot(s, 1, 1, 1)

for i = 1:Nframes
    for j = 1:Npoints
        step!(attractor)
        push!(x, attractor.x);
        push!(y, attractor.y);
        push!(z, attractor.z)
    end
    cs = resample(ColorSchemes.inferno, length(x))
    splot(f[i],
          s, "set view 70, $(45 + 17 * sin(2pi * i / Nframes))",
          x, y, z, Gaston.cs2dec(cs),
          "w l notitle lc rgb variable")
end
save(f, filename = "lorenz.webp", term = "webp animate loop 0 size 640,480")


================================================
FILE: docs/v2/assets/test.tex
================================================
% GNUPLOT: LaTeX picture with Postscript
\begingroup
  \makeatletter
  \providecommand\color[2][]{%
    \GenericError{(gnuplot) \space\space\space\@spaces}{%
      Package color not loaded in conjunction with
      terminal option `colourtext'%
    }{See the gnuplot documentation for explanation.%
    }{Either use 'blacktext' in gnuplot or load the package
      color.sty in LaTeX.}%
    \renewcommand\color[2][]{}%
  }%
  \providecommand\includegraphics[2][]{%
    \GenericError{(gnuplot) \space\space\space\@spaces}{%
      Package graphicx or graphics not loaded%
    }{See the gnuplot documentation for explanation.%
    }{The gnuplot epslatex terminal needs graphicx.sty or graphics.sty.}%
    \renewcommand\includegraphics[2][]{}%
  }%
  \providecommand\rotatebox[2]{#2}%
  \@ifundefined{ifGPcolor}{%
    \newif\ifGPcolor
    \GPcolortrue
  }{}%
  \@ifundefined{ifGPblacktext}{%
    \newif\ifGPblacktext
    \GPblacktexttrue
  }{}%
  % define a \g@addto@macro without @ in the name:
  \let\gplgaddtomacro\g@addto@macro
  % define empty templates for all commands taking text:
  \gdef\gplbacktext{}%
  \gdef\gplfronttext{}%
  \makeatother
  \ifGPblacktext
    % no textcolor at all
    \def\colorrgb#1{}%
    \def\colorgray#1{}%
  \else
    % gray or color?
    \ifGPcolor
      \def\colorrgb#1{\color[rgb]{#1}}%
      \def\colorgray#1{\color[gray]{#1}}%
      \expandafter\def\csname LTw\endcsname{\color{white}}%
      \expandafter\def\csname LTb\endcsname{\color{black}}%
      \expandafter\def\csname LTa\endcsname{\color{black}}%
      \expandafter\def\csname LT0\endcsname{\color[rgb]{1,0,0}}%
      \expandafter\def\csname LT1\endcsname{\color[rgb]{0,1,0}}%
      \expandafter\def\csname LT2\endcsname{\color[rgb]{0,0,1}}%
      \expandafter\def\csname LT3\endcsname{\color[rgb]{1,0,1}}%
      \expandafter\def\csname LT4\endcsname{\color[rgb]{0,1,1}}%
      \expandafter\def\csname LT5\endcsname{\color[rgb]{1,1,0}}%
      \expandafter\def\csname LT6\endcsname{\color[rgb]{0,0,0}}%
      \expandafter\def\csname LT7\endcsname{\color[rgb]{1,0.3,0}}%
      \expandafter\def\csname LT8\endcsname{\color[rgb]{0.5,0.5,0.5}}%
    \else
      % gray
      \def\colorrgb#1{\color{black}}%
      \def\colorgray#1{\color[gray]{#1}}%
      \expandafter\def\csname LTw\endcsname{\color{white}}%
      \expandafter\def\csname LTb\endcsname{\color{black}}%
      \expandafter\def\csname LTa\endcsname{\color{black}}%
      \expandafter\def\csname LT0\endcsname{\color{black}}%
      \expandafter\def\csname LT1\endcsname{\color{black}}%
      \expandafter\def\csname LT2\endcsname{\color{black}}%
      \expandafter\def\csname LT3\endcsname{\color{black}}%
      \expandafter\def\csname LT4\endcsname{\color{black}}%
      \expandafter\def\csname LT5\endcsname{\color{black}}%
      \expandafter\def\csname LT6\endcsname{\color{black}}%
      \expandafter\def\csname LT7\endcsname{\color{black}}%
      \expandafter\def\csname LT8\endcsname{\color{black}}%
    \fi
  \fi
    \setlength{\unitlength}{0.0500bp}%
    \ifx\gptboxheight\undefined%
      \newlength{\gptboxheight}%
      \newlength{\gptboxwidth}%
      \newsavebox{\gptboxtext}%
    \fi%
    \setlength{\fboxrule}{0.5pt}%
    \setlength{\fboxsep}{1pt}%
    \definecolor{tbcol}{rgb}{1,1,1}%
\begin{picture}(7200.00,4740.00)%
    \gplgaddtomacro\gplbacktext{%
    }%
    \gplgaddtomacro\gplfronttext{%
      \csname LTb\endcsname%%
      \put(1512,3921){\makebox(0,0)[r]{\strut{}n=0}}%
      \csname LTb\endcsname%%
      \put(1512,3716){\makebox(0,0)[r]{\strut{}n=1}}%
      \csname LTb\endcsname%%
      \put(2937,3921){\makebox(0,0)[r]{\strut{}n=2}}%
      \csname LTb\endcsname%%
      \put(2937,3716){\makebox(0,0)[r]{\strut{}n=3}}%
      \csname LTb\endcsname%%
      \put(4363,3921){\makebox(0,0)[r]{\strut{}sin(x)}}%
      \csname LTb\endcsname%%
      \put(616,409){\makebox(0,0)[r]{\strut{}$-1.5$}}%
      \csname LTb\endcsname%%
      \put(616,1025){\makebox(0,0)[r]{\strut{}$-1$}}%
      \csname LTb\endcsname%%
      \put(616,1641){\makebox(0,0)[r]{\strut{}$-0.5$}}%
      \csname LTb\endcsname%%
      \put(616,2257){\makebox(0,0)[r]{\strut{}$0$}}%
      \csname LTb\endcsname%%
      \put(616,2873){\makebox(0,0)[r]{\strut{}$0.5$}}%
      \csname LTb\endcsname%%
      \put(616,3489){\makebox(0,0)[r]{\strut{}$1$}}%
      \csname LTb\endcsname%%
      \put(616,4105){\makebox(0,0)[r]{\strut{}$1.5$}}%
      \csname LTb\endcsname%%
      \put(1257,204){\makebox(0,0){\strut{}$-\pi$}}%
      \csname LTb\endcsname%%
      \put(2521,204){\makebox(0,0){\strut{}$-\pi/2$}}%
      \csname LTb\endcsname%%
      \put(3786,204){\makebox(0,0){\strut{}0}}%
      \csname LTb\endcsname%%
      \put(5050,204){\makebox(0,0){\strut{}$\pi/2$}}%
      \csname LTb\endcsname%%
      \put(6314,204){\makebox(0,0){\strut{}$\pi$}}%
      \csname LTb\endcsname%%
      \put(4519,1148){\makebox(0,0){\strut{}\begin{minipage}[c]{\textwidth}\begin{equation*}\sin(x) = \sum_0^{+\infty} \frac{(-1)^n}{(2n + 1)!} x^{2n+1}\end{equation*} \end{minipage}}}%
      \csname LTb\endcsname%%
      \put(3785,4412){\makebox(0,0){\strut{}Polynomial approximation of sin(x)}}%
    }%
    \gplbacktext
    \put(0,0){\includegraphics[width={360.00bp},height={237.00bp}]{test}}%
    \gplfronttext
  \end{picture}%
\endgroup


================================================
FILE: docs/v2/examples.qmd
================================================
---
title: "Examples"
---

```{julia}
#| echo: false
#| output: false
using Gaston
Gaston.config.term = "pngcairo font ',10' size 640,480"
Gaston.config.output = :echo
```

### 3-D Euler spiral [(Clothoid)](https://en.wikipedia.org/wiki/Euler_spiral)

```{julia}
using QuadGK
z = range(-5, 5, 200)
fx(z) = sin(z^2)
fy(z) = cos(z^2)
x = [quadgk(fx, 0, t)[1] for t in z]
y = [quadgk(fy, 0, t)[1] for t in z]
splot("""unset zeroaxis
         set tics border
         set xyplane at -5 
         set view 65,35
         set border 4095
         set xtics offset 0, -0.5""",
         x, y, z, "w l lc 'black' lw 1.5")
```

### Waterfall

Inspired by this [Julia Discourse discussion](https://discourse.julialang.org/t/how-to-produce-a-waterfall-plot-in-julia/93441).
```{julia}
x = -15:0.1:15
y = 0:30
u1data = [exp(-(x-0.5*(y-15))^2) for x in x, y in y]
Zf = fill(0.0, length(x))
f = Figure()
Gaston.set!(f(1), """set zrange [0:1.5]
               set tics out
               set ytics border
               set xyplane at 0
               set view 45,17
               set xlabel 'ξ'
               set ylabel 't' offset -2.5
               set zlabel '|u|' offset -0.85
               set border 21
               set size 1, 1.3""")
for i in reverse(eachindex(y))
    Y = fill(y[i], length(x))
    Z = u1data[:,i]
    splot!(x, Y, Z, Zf, Z, "w zerrorfill lc 'black' fillstyle solid 1.0 fc 'white'")
end
f
```

### Vector field

Inspired by this [post in gnuplotting.org](https://gnuplotting.org/vector-field-from-function/index.html).

```{julia}
xr = 15  # samples in x direction
yr = 15  # samples in y direction

# parameters
x01 = 1
y01 = 0
q1  = 1
x02 = -1
y02 = 0
q2  = -1
scaling = 0.22

# equations
r(x,y)     = sqrt(x*x+y*y)
v1(x,y)    = q1/(r(x-x01,y-y01))
v2(x,y)    = q2/(r(x-x02,y-y02))
v(x,y)     = v1(x,y)+v2(x,y)
e1x(x,y)   = q1*x/r(x,y)^3
e1y(x,y)   = q1*y/r(x,y)^3
e2x(x,y)   = q2*x/r(x,y)^3
e2y(x,y)   = q2*y/r(x,y)^3
ex(x,y)    = e1x(x-x01,y-y01)+e2x(x-x02,y-y02)
ey(x,y)    = e1y(x-x01,y-y01)+e2y(x-x02,y-y02)
enorm(x,y) = sqrt(ex(x,y)^2 + ey(x,y)^2)
dx(x,y)    = scaling*ex(x,y)/enorm(x,y)
dy(x,y)    = scaling*ey(x,y)/enorm(x,y)

# initialize data vectors
d1 = zeros(xr*yr)
d2 = zeros(xr*yr)
d3 = zeros(xr*yr)
d4 = zeros(xr*yr)
d5 = zeros(xr*yr)

# calculations
for X in range(-2, 2, length=xr)
    for Y in range(-1.8, 1.8, length=yr)
         push!(d1, X-dx(X,Y)/2)
         push!(d2, Y-dy(X,Y)/2)
         push!(d3, dx(X,Y))
         push!(d4, dy(X,Y))
         push!(d5, v(X,Y))
    end
end

@plot({palette = :linear_kry_5_95_c72_n256}, :nocb,
      d1, d2, d3, d4, d5,
      "with vectors head size 0.08,20,60 filled lc palette")
```

### Line color from palette

```{julia}
x = -2π:0.05:2π
@plot {palette = :ice} x sin.(3x) x "w l notitle lw 3 lc palette"
```

### Variable marker size and color

```{julia}
x = 0:0.1:6π
splot("unset colorbox",
      x, cos.(x), sin.(x), x./10,
      "w p", "ps variable", "pt 7", "lc palette")
```

### Filled curves

#### Filled transparent curves in 2-D

```{julia}
pois(λ, k) = (λ^k)*exp(-λ)/factorial(k)
s = "set style fill transparent solid 0.4 noborder \nset title 'Poisson PMF'"
plot(s, 0:15, k -> pois(4, k), "w filledcu x1 lc 'cyan' t 'λ = 4'")
plot!(0:15, k -> pois(6, k), "w filledcu x1 lc 'blue' t 'λ = 6'")
plot!(0:15, k -> pois(8, k), "w filledcu x1 lc 'pink' t 'λ = 8'")
```

#### Fill between two curves

```{julia}
x = range(-10, 10, 100)
y1 = sin.(x) .- 0.5
y2 = sin.(x) .+ 0.5
plot(x, y1, y2, "w filledcu lc 'turquoise'")
```

#### Filled curve in 3-D

```{julia}
x = 0.:0.05:3;
y = 0.:0.05:3;
z = @. sin(x) * exp(-(x+y))
@gpkw splot(:labels, {style = "fill transparent solid 0.3", xyplane = "at 0", grid, lt = :Set1_5},
            x, y, z, z.*0, z,
            "w zerror t 'Data'")
splot!(x.*0, y, z, "w l lw 3")
splot!(x, y.*0, z, "w l lw 3")
```

Here, `Set1_5` is a color scheme from [ColorSchemes.jl](https://github.com/JuliaGraphics/ColorSchemes.jl).

### Spheres

#### Wireframe

```{julia}
Θ = range(0, 2π, length = 100)
Φ = range(0, π, length = 20)
rd = 0.8
x = [rd*cos(θ)*sin(ϕ) for θ in Θ, ϕ in Φ]
y = [rd*sin(θ)*sin(ϕ) for θ in Θ, ϕ in Φ]
z = [rd*cos(ϕ)        for θ in Θ, ϕ in Φ]
@gpkw splot({view = "equal xyz", pm3d = "depthorder", hidden3d},
            x, y, z,
            {w = "l", lc = Q"turquoise"})
```

#### Surface

```{julia}
Θ = range(0, 2π, length = 100)
Φ = range(0, π, length = 100)
rd = 0.8
x = [rd*cos(θ)*sin(ϕ) for θ in Θ, ϕ in Φ]
y = [rd*sin(θ)*sin(ϕ) for θ in Θ, ϕ in Φ]
z = [rd*cos(ϕ)        for θ in Θ, ϕ in Φ]
@splot({style = "fill transparent solid 1",
        palette = :summer,
        view = "equal xyz",
        pm3d = "depthorder"},
       x, y, z,
       "w pm3d")
```

### Torus

```{julia}
U = range(-π, π, length = 50)
V = range(-π, π, length = 100)
rd = 0.5
x = [1+cos(u)+rd*cos(u)*cos(v) for u in U, v in V]
y = [rd*sin(v)                 for u in U, v in V]
z = [sin(u)+rd*sin(u)*cos(v)   for u in U, v in V]
settings = """set object rectangle from screen 0,0 to screen 1,1 behind fillcolor 'black' fillstyle solid noborder
              set pm3d depthorder
              set style fill transparent solid 0.5
              set pm3d lighting primary 0.05 specular 0.2
              set view 108,2
              unset border
              set xyplane 0
              unset tics
              unset colorbox"""
@splot(settings, {palette = :cool}, x, y, z, "w pm3d")
```

#### Interlocking torii

```{julia}
U = LinRange(-π, pi, 100)
V = LinRange(-π, pi, 20)
x = [cos(u) + .5 * cos(u) * cos(v) for u in U, v in V]
y = [sin(u) + .5 * sin(u) * cos(v) for u in U, v in V]
z = [.5 * sin(v)                   for u in U, v in V]
@gpkw surf({palette = :dense,
        pm3d = "depthorder",
        colorbox = false,
        key = :false,
        tics = :false,
        border = 0,
        view = "60, 30, 1.5, 0.9",
        style = "fill transparent solid 0.7"},
       x', y', z')
x = [1 + cos(u) + .5 * cos(u) * cos(v) for u in U, v in V]
y = [.5 * sin(v)                       for u in U, v in V]
z = [sin(u) + .5 * sin(u) * cos(v)     for u in U, v in V]
surf!(x', y', z')
```

See more torus examples in the included Pluto notebook.

### Contours

#### Surface with contours

```{julia}
x = y = -10:0.5:10
f1(x, y) = cos.(x./2).*sin.(y./2)
surf("""set hidden3d
        set contour base
        set cntrparam levels 10
        unset key""",
     x, y, f1,
     "lc 'turquoise'")
```

#### Egg-shaped contours

```{julia}
x = -1:0.05:1
y = -1.5:0.05:2
egg(x,y) = x^2 + y^2/(1.4 + y/5)^2
segg = [egg(x,y) for x in x, y in y]
@gpkw contour({palette = :cool,
               cntrparam = "levels incremental 0,0.01,1",
               auto = "fix",
               xrange = (-1.2, 1.2),
               yrange = (-1.5, 2),
               cbrange = (0, 1),
               xlabel = "'x'",
               ylabel = "'y'",
               size = "ratio -1"},
              x, y, segg',
              "w l lc palette",
              labels = false)
```

### 3D Tubes

#### Wireframe

```{julia}
U = range(0, 10π, length = 80)
V = range(0, 2π, length = 10)
x = [(1-0.1*cos(v))*cos(u)     for u in U, v in V]
y = [(1-0.1*cos(v))*sin(u)     for u in U, v in V]
z = [0.2*(sin(v) + u/1.7 - 10) for u in U, v in V]
settings = @gpkw {pm3d = "depthorder",
                  style = "fill transparent solid 1",
                  view = "equal xyz",
                  xyplane = -0.05,
                  palette = :ice,
                  xrange = (-1.2, 1.2),
                  yrange = (-1.2, 1.2),
                  colorbox = false,
                  hidden3d,
                  view = (70, 79)}
@splot(settings, x, y, z, "w l lc 'turquoise'")
```

#### Surface

```{julia}
@splot(settings, x, y, z, "w pm3d")
```

### Animations

#### Lorenz attractor

This example is adapted from [https://docs.makie.org/stable/#example](Makie's documentation).
A few notes on the adaptation to Gaston:

* The camera animation is achieved by changing the `view` setting every frame.
* Each frame, `Npoints` coordinates are added to the plot. The animation consists of `Nframes`
  frames.
* The coloring of the attractor is different than in most 3-D plots. Normally, the color of
  a point depends on its `z` coordinate. In this case, the `z` coordinate is not an amplitude,
  since the curve lives in a state space. Therefore, the color palette will be applied along
  the length of the curve, with points nearer the start given colors at the start of the palette.
  To achieve this, we use `ColorSchemes.resample` to create a new palette with the same number
  of colors as there are points in the curve. Then, `Gaston.hex` is used to convert these
  colors to decimal numbers. Finally, the colors are used as a fourth column of data and the
  line color is set to `lc rgb variable`.

```{.julia}
using ColorSchemes

Base.@kwdef mutable struct Lorenz
    dt::Float64 = 0.01
    σ::Float64 = 10
    ρ::Float64 = 28
    β::Float64 = 8/3
    x::Float64 = 1
    y::Float64 = 1
    z::Float64 = 1
end

function step!(l::Lorenz)
    dx = l.σ * (l.y - l.x)
    dy = l.x * (l.ρ - l.z) - l.y
    dz = l.x * l.y - l.β * l.z
    l.x += l.dt * dx
    l.y += l.dt * dy
    l.z += l.dt * dz
    return (l.x, l.y, l.z)
end

Nframes = 120
Npoints = 50
attractor = Lorenz()
x = Float64[];
y = Float64[];
z = Float64[];

s = @gpkw {xrange = (-30, 30),
           yrange = (-30, 30),
           zrange = (0, 60),
           xtics = "offset -1.2,0",
           xtics = "add ('' -30, '' 30)",
           ytics = "offset 1.2,0",
           ytics = "add ('' -30, '' 30)",
           origin = "-0.1, -0.1",
           size = "1.2, 1.2",
           object = "rectangle from screen 0,0 to screen 1,1 fillcolor 'black' behind",
           border = "back lc rgb '#eeeeee' lt 1 lw 1.5",
           view = "equal xyz",
           xyplane = "at 0"}

f = splot(s, 1, 1, 1)

for i = 1:Nframes
    for j = 1:Npoints
        step!(attractor)
        push!(x, attractor.x);
        push!(y, attractor.y);
        push!(z, attractor.z)
    end
    cs = resample(ColorSchemes.inferno, length(x))
    splot(f[i],
          s, "set view 70, $(45 + 17 * sin(2pi * i / Nframes))",
          x, y, z, Gaston.hex(cs),
          "w l notitle lc rgb variable")
end
save(f, filename = "lorenz.webp", term = "webp animate loop 0 size 640,480")
```

![](assets/lorenz.webp)


#### 3-D spiral

```{.julia}
z = 0:0.1:10pi
step = 5
cc = "lc 'turquoise' lw 3 notitle"
ac = @gpkw {zrange = (0,30), xrange = (-1.2, 1.2), yrange = (-1.2, 1.2)}
F = scatter3(ac, :notics, :labels, cos.(z[1:step]), sin.(z[1:step]), z[1:step], cc)
frame = Figure()
for i = 2:60
    frame = scatter3(ac, :notics, :labels, cos.(z[1:i*step]), sin.(z[1:i*step]), z[1:i*step], cc)
    push!(F, frame)
end
for i = 60:-1:1
    frame = scatter3(ac, :notics, :labels, cos.(z[1:i*step]), sin.(z[1:i*step]), z[1:i*step], cc)
    push!(F, frame)
end
save(F, filename = "3dspiral.webp", term = "webp animate loop 0 size 640,480")
```
![](assets/3dspiral.webp)

#### Splash

```{.julia}
x = y = -15:0.4:15
ac = @gpkw {title = Q"Splash",
            palette  = :cool,
            cbrange  = (-0.2, 1),
            zrange   = (-0.3, 1),
            hidden3d = true}
F = splot(ac, x, y, (x, y) -> sin(sqrt(x*x+y*y))/sqrt(x*x+y*y), "w pm3d")
frame = Figure()
for i = 1:-0.1:-1
    frame = splot(ac, x, y, (x,y) -> i*sin(sqrt(x*x+y*y))/sqrt(x*x+y*y), "w pm3d");
    push!(F, frame)
end
for i = -0.9:0.1:1
    frame = splot(ac, x, y, (x,y) -> i*sin(sqrt(x*x+y*y))/sqrt(x*x+y*y), "w pm3d");
    push!(F, frame)
end
save(F, filename = "3dsplash.webp", term = "webp animate loop 0 size 640,480")
```
![](assets/3dsplash.webp)



================================================
FILE: docs/v2/index.qmd
================================================
---
title: "Introduction"
---

[Gnuplot](http://www.gnuplot.info/) is a venerable (but actively
developed), very powerful and fast program for plotting.
[Julia](https://julialang.org) is a very powerful language for numerical
computing.  [Gaston](https://github.com/mbaz/Gaston.jl) is a package for
plotting Julia data and functions using gnuplot.

The following diagram illustrates how Gaston works. On the left there is a
gnuplot script; the equivalent Gaston function call is on the right.

![](assets/comparison.png)

The data to plot is in green color. In gnuplot, the data can be provided
inline as a _data block_ (as in this example), or it can be provided in a
separate file. Gaston can plot data stored in arrays (`x` and `y` in this
example). Gaston also supports recipes to plot arbitrary Julia types.

The lines in red specify the _axes settings_, affecting things like the
presence of a grid, the title, the legend box, tics positions/labels, etc.
Finally, in blue color, the _plot settings_ or _plotline_ specify the
properties of one specific curve within the axes (for example, the line
color, thickness and style, which marker to use, etc.)

There is a close correspondence between gnuplot and Gaston commands; in
fact, the main purpose of Gaston is to translate the Julia code on the
right to the gnuplot commands on the left. Gaston has two main features:

* It provides convenient, flexible syntax for plotting, along with common
  2-D and 3-D plot styles.
* It provides a simple mechanism to add user-defined recipes for plotting
  arbitrary Julia types.

Other features are:

* Support for plotting in separate GUI windows, in the terminal (with text
  or [sixels](https://en.wikipedia.org/wiki/Sixel)), in VS Code, or in
  notebooks (such as Jupyter and Pluto).
* Handling multiple co-existing interactive GUI plot windows.
* Support for (user-defined) themes.
* Convenient commands for common types of plots (like histograms, contour
  plots, surface plots, heatmaps, etcetera).
* Convenient syntax for creating multiplots and animations.
* Saving plots to multiple formats, including pdf, png and svg.
* Integrated color palettes from
  [ColorSchemes.jl](https://github.com/JuliaGraphics/ColorSchemes.jl).

::: {.callout-note}

This manual is for Gaston version 2. The manual for Gaston v1 (no longer
maintained) is [here](https://mbaz.github.io/Gaston.jl/v1/index.html).

:::

## Learning gnuplot

This documentation assumes at least a basic understanding of gnuplot. Some
pointers to get started with gnuplot are:

* The [official documentation](http://www.gnuplot.info/documentation.html).
* The [official list of tutorials](http://www.gnuplot.info/help.html).
* [Plotting data](http://www.gnuplotting.org/plotting-data/) article on
  [gnuplotting.org](http://www.gnuplotting.org/).
* [A blog post about Gaston by Julia
  Frank](https://juliaifrank.com/gnuplot-with-julia-for-beautiful-graphics/).
* Stackoverflow has a [gnuplot
  tag](https://stackoverflow.com/questions/tagged/gnuplot) with answers to
  more than 6,500 questions.

The following are interesting plot galleries:

* [Official gnuplot demo
  gallery](http://www.gnuplot.info/screenshots/index.html#demos).
* [Wikimedia commons
  gallery](https://commons.wikimedia.org/wiki/Category:Gnuplot_diagrams).
* [Nice collection of volumetric
  plots](https://ayapin-film.sakura.ne.jp/Gnuplot/pm3d.html).

## Installation

Gaston v2.x requires Julia version 1.8.0 or above (Gaston v1.x supports
Julia 1.6 and above), and has been tested with gnuplot versions 5 and 6.
You should manually install gnuplot on your system prior to using Gaston.
On Linux, it is highly recommended that you select a version with Qt
support: on Debian and Ubuntu, you will need `gnuplot-qt`. On Arch and its
derivatives, a simple `pacman -S gnuplot` suffices.

Gnuplot also supports Windows and Mac. This author does not use these systems
much, but it is said that gnuplot Windows executables are available at
[Sourceforge's gnuplot repository](https://sourceforge.net/projects/gnuplot/files/gnuplot/).
On Mac, gnuplot is supposed to be available using Homebrew.

To install Gaston from the Julia REPL, run
```julia
julia> ]add Gaston
```
Typing `]` switches the Julia REPL to the package manager, and the `add`
command installs the package. To exit the package manager, hit the backspace
key.
Load Gaston into your Julia session with
```julia
using Gaston
```

::: {.callout-note}
## Specifying the location of gnuplot

    The location of the gnuplot executable can be specified with the environmental variable
    `JULIA_GNUPLOT_EXE`. If gnuplot is in the system's path, setting this variable is not
    necessary.

:::

## Support

Here are some ideas on what to do if you need help with Gaston:

* Post a question in [Julia's discuss forum](https://discourse.julialang.org/tag/plotting)
  in the "plotting" category.
* Chat with the author (@mbaz) on [Julia's Zulip chat forum](https://julialang.zulipchat.com/),
  in the "plotting" or "helpdesk" channels.
* Bug reports, suggestions and pull requests are welcome at
  [Gaston's github page](https://github.com/mbaz/Gaston.jl).

## Contributing

Contributions are welcome! Examples of things you can do are bug reports,
improvements to the documentation, new examples and tutorials, and new features or
suggestions.

## Gnuplot startup file

Gnuplot reads and executes a startup file, if it exists, before every plot.
Since an un-configured gnuplot produces plots that are less than attractive,
the following minimum configuration is suggested (and was used to generate the
plots in this document):

    set linetype 1 lc rgb "blue" pt 3 ps 1.2
    set linetype 2 lc rgb "red" pt 4 ps 1.2
    set linetype 3 lc rgb "dark-green" pt 6 ps 1.2
    set linetype 4 lc rgb "orange-red" pt 12 ps 1.2
    set linetype 5 lc rgb "gold" pt 5 ps 1.2
    set linetype 6 lc rgb "dark-violet" pt 1 ps 1.2
    set linetype 7 lc rgb "gray50" pt 2 ps 1.2
    set linetype 8 lc rgb "black" pt 7 ps 1.2
    set linetype cycle 8
    set style data lines
    set key noautotitle
    set auto fix
    set offsets graph .05, graph .05, graph .05, graph .05

The configuration file is `~/.gnuplot` on Unix-like systems, and
`%APPDATA%\GNUPLOT.INI` on Windows.

## Next steps

* Read the [Tutorial](tutorial.qmd).
* See plot examples in the [Examples](examples.qmd) section.
* Learn how to extend Gaston to plot arbitrary Julia types in the [Recipes](recipes.qmd) section.
* Learn all the details about how to plot with Gaston in the [Manual](manual.qmd).
* For specific information about migrating from Gaston v1 to v2, see the
  [Migration Guide](migrate.qmd).
* Consult the full [API Reference](reference.qmd).

Gaston's documentation includes three [Pluto](https://plutojl.org/)
notebooks:

* An overview of the [essential plotting concepts](https://github.com/mbaz/Gaston.jl/tree/master/docs/v2/tutorial-essentials.jl).
* An overview of [3-D plotting](https://github.com/mbaz/Gaston.jl/tree/master/docs/v2/tutorial-3d.jl).
* A tutorial on how to [plot a torus](https://github.com/mbaz/Gaston.jl/tree/master/docs/how-to-plot-a-torus.jl) (which aims to showcase Gaston in interactive notebooks).

## Acknowledgments

When developing Gaston, I've been inspired by the excellent features and ideas
behind other Julia plotting packages, including
[Plots.jl](https://github.com/JuliaPlots/Plots.jl),
[Gnuplot.jl](https://github.com/gcalderone/Gnuplot.jl),
[PGFPlotsX.jl](https://github.com/KristofferC/PGFPlotsX.jl),
and [Makie.jl](https://github.com/MakieOrg/Makie.jl).
Many thanks to their multiple authors for freely sharing their code and their APIs!


================================================
FILE: docs/v2/manual.qmd
================================================
---
title: "Manual"
---

This manual covers all aspects of using Gaston.

## Configuration

### The terminal

By default, gnuplot chooses an appropriate terminal: `qt` or `wxt` on Linux,
`windows` on Windows, and `aqua` on MacOS.  The terminal can be set by changing
the value of `Gaston.config.term`; for example:

```julia
Gaston.config.term = "pngcairo font ',10' size 700,400";
```

To show the terminals supported by gnuplot, run:

```julia
Gaston.terminals()
```

### Other settings

* `Gaston.config.output`: controls how plots are displayed. Possible values are:
    * `:external`: plots are displayed in GUI windows. This is the default value.
    * `:echo`: sends text-based plots (like `png` and `sixelgd`) back to the terminal. Useful for notebooks and IDEs, and for plotting on the terminal.
    * `:null`: execute all plot commands but do not actually produce a plot.

    If Gaston detects it is running in a notebook environment, it automatically sets the terminal
    to `pngcairo` and `config.output` to `:echo`. When the automatic detection does
    not work, these setting have to be set manually.
* `Gaston.config.embedhtml`: `Bool`, defaults to `false`. Enables embedding plots in HTML; useful to enable interactivity in Pluto and Jupyter notebooks.

### Location of gnuplot executable

If gnuplot is not in the system's path, its location can be set using the environmental
variable `JULIA_GNUPLOT_EXE`. This variable must be set before Gaston is loaded.

## Plotting

The `plot` function is used to plot one curve, while `plot!` is used to add a
curve to the same plot. 3-D plots are created with `splot` and `splot!`. `plot`
returns a value of type `Figure`, which contains a vector of `Axis` (each
containing one or more `Plot`s, or curves.

A `plot` command takes four different kinds of arguments: a figure (possibly
indexed), settings, data, and plotline, in that order.

```julia
plot([figure,] [settings...,] data..., [plotline...])
```

Further curves may be added using `plot!`. (For 3-D plots, use `splot` and `splot!` instead.)

More specifically, a `plot` command takes:

* Optionally, a figure where the plot is to be produced.
  * If the figure is indexed, then the plot will be produced in the specified axis (if it
    doesn't exist, it will be created).
* Zero or more **settings** arguments, which get converted to gnuplot `set` commands.
* One or more **data** arguments, which are written to a file in the format gnuplot expects.
* Zero or more **plotline** arguments, which are appended to gnuplot's `plot` or `splot` commands.

Gaston provides several alternative ways to specify settings and plotlines.

### Settings and Plotlines

All the following are equivalent.

* One single string

```julia
plot("set grid
      unset key
      set title 'A Sinusoid'",
     x, y,
     "with linespoints lc 'green'")
```

* Multiple strings

```julia
plot("set grid", "unset key \n set title 'A Sinusoid'",
     x, y,
     "with linespoints", "lc 'green'")
```

* Keywords with `@plot`

```julia
@plot({grid = true, key = false, title = "'A Sinusoid'"},
      x, y,
      {with = "linespoints", lc = "'green'"})
```

* Keywords with `@gpkw`:

```julia
@gpkw plot({grid = true, key = false, title = "'A Sinusoid'"},
      x, y,
      {with = "linespoints", lc = "'green'"})
```

Keyword options are enclosed in curly brackets `{}`. To set an option without arguments,
such as `set grid`, use either a lone `grid`, or `grid = true`. To unset an option, such as in
`unset grid`, use ` grid = false`.  Options can be repeated; each one will be converted to a
separate `set` line.

`@plot` also accepts strings, and in fact strings and keywords may be combined:

```julia
@plot({grid, key = false}, "set title 'A Sinusoid'",
      x, y,
      "with linespoints", {lc = "'green'"})
```

It is possible to omit the parenthesis, but in this case the command must fit in a single line.

```julia
@plot {grid, key = false, title = "'A Sinusoid'"} x y {with = "lp", lc = "'green'"}
```

For 3-D plots, use the macro `@splot`.

#### Quoted strings

All strings passed to gnuplot must be enclosed in single quotes, such as in `lc = "'green'"` in the
example above. The `@Q_str` string macro can help reduce the number of quotes needed:

```julia
@plot {grid = true, key = false, title = Q"A Sinusoid"} x y {with = "lp", lc = Q"green"}
```

This macro turns `"abc"` into `"'abc'"`.

#### Keyword parsing

Some `@plot` (or `@gpkw`) keyword arguments are parsed by Gaston, providing syntax that may be more
convenient than gnuplot's. The following list is for keywords that specify axis settings:

* For any keyword argument, `{arg}` or `{arg = true}` is parsed to `set arg`, while `{arg = false}` is parsed to `unset arg`.
* For `xtics`, `ytics`, `ztics` or `tics`:
  * `{tics = R}` where `R` is an `AbstractRange` is parsed as `set tics $(first(R)), $(step(R)), $(last(R))`.
  * `{tics = T}` where `T` is a `Tuple` is parsed as `set tics $T`.
  * `{tics = NT}` where `NT` is a `NamedTuple` is parsed as in this example:
    `{tics = (labels = ("one", "two"), positions = (0, 2))}` is equivalent to `set tics ('one' 0, 'two' 2, )`
* For `xrange`, `yrange`, `zrange`, `cbrange`:
  * `{xrange = R}` where `R` is a vector or tuple is parsed as `set xrange [$R[1]:$R[2]]`
  * If `R` contains an `Inf`, then it is replaced with `*`.
* If the keyword is `ranges`, then all four ranges listed above are set.
* For `palette`, if the value is a symbol, then the corresponding color scheme from `ColorSchemes.jl` is converted to gnuplot's format. If a tuple of two symbols is provided and the second one is `:reverse`, then the order of the palette is reversed.
* For `{view = V}`, if `V` is a `Tuple`, then it is parsed as `set view $V[1], $V[2]`.
* For `{linetype = S}` where `S` is a `Symbol`, then the corresponding color scheme is converted to a set of line types, one per color in the scheme.
* For `{margins = T}` where `T` is a `Tuple` is parsed as in this example:
  `{margins = (1, 2, 3, 4)}` is equivalent to `set lmargin at screen 1`, `set rmargin at screen 2`, `set bmargin at screen 3`, `set tmargin at screen 4`.

The following list is for keywords that specify plotline elements:

* `plotstyle` is equivalent to `with`.
* `markersize` and `ms` are equivalent to `pointsize`.
* `legend` is equivalent to `title`.
* `marker` is equivalent `pointtype`.

In addition, `marker`, `pointtype` and `pt` accept symbolic names for the
marker types, according to the following table:

| name | gnuplot pointtype |
|------|-------------------|
| :dot      | 0 |
| :⋅        | 0 |
| :+        | 1 |
| :plus     | 1 |
| :x        | 2 |
| :*        | 3 |
| :star     | 3 |
| :esquare  | 4 |
| :fsquare  | 5 |
| :ecircle  | 6 |
| :fcircle  | 7 |
| :etrianup | 8 |
| :ftrianup | 9 |
| :etriandn | 10 |
| :ftriandn | 11 |
| :edmd     | 12 |
| :fdmd     | 13 |

### Data

Data to be plotted can be provided as vectors and/or matrices. Gaston converts the data to a
format compatible with gnuplot. Three cases are supported:
* All data arguments are vectors.
* The first two arguments are vectors of length `n` and `m`, and the third argument is a matrix
  of size `n x m`; further arguments are optional.
* All provided arguments are matrices of size `n x m`.

#### Recipes

[Recipes](manual.qmd#defining-new-plot-types-and-recipes) can be provided to
convert arbitrary types to data that gnuplot understands.

#### Functions

Functions can be plotted directly, with a given range and number of samples, which
can be specified in the following alternative ways:

```julia
# g is a function
plot(g)            # plots `g` evaluated at 100 samples, from -10 to 9.99
plot((a, b), g)    # plots `g` evaluated at 100 samples, from a to b
plot((a, b, c), g) # plots `g` evaluated at c samples, from a to b
plot(x, g)         # plots g.(x)
```

#### Plot with table

In some cases, it is useful to have gnuplot produce plot data in a "table"
format, which can then be plotted. See an example in [contour lines on
heatmap](tutorial.qmd#gnuplot-datasets-and-tables). The (non-exported) function
`Gaston.plotwithtable` returns a `Gaston.DataTable` storing the table. All plot
commands accept this type.

The following `DataTable` constructors are provided:

* `DataTable(vs::Vector{<:AbstractString}...)`
* `DataTable(ts::T) where T <: Tuple`; the tuple is assumed to contain strings.
* `DataTable(args::Matrix...)`; each matrix is a datablock.

### Simple themes

Frequently-used settings or plotlines may be stored in a "theme"; the `@gpkw` macro processes
keyword arguments wrapped in curly brackets.

```julia
theme = @gpkw {grid, key = false}
plot(theme, x, y)
```

Themes may be combined with other themes and/or with strings:

```julia
theme2 = @gpkw {xlabel = Q"X"}
plot(theme, "set title 'A Sinusoid'", theme2, x, y)
```

Themes can also be used for plotlines, and these may also be combined with other themes and/or
strings.

```julia
pltheme = @gpkw {w = "lp", pt = "'o'", ps = 3}
plot(theme, "set title 'A Sinusoid'", theme2, x, y, pltheme)
```

Gaston includes a few generic themes:

|Axis themes | Description |
|-----------:|:------------|
| :notics | Removes all tics |
| :labels | Generic axis labels (`x`, `y`, `z`) |
| :nocb   | Removes colorbox |
| :unitranges | Set all ranges to `[-1:1]` |

For example, the following command plots a sine wave with no tics and generic `x` and `y` axis
labels:

```julia
plot(:notics, :labels, "set title 'Example'", (-1, 1), sin)
```

Themes are also used to provide common plot types (illustrated in
[Themes](examples.qmd#themes)). The following are the provided specialized plot
commands and the themes they use:

| Command | Settings theme | Plotline theme |
|----------|----------------|----------------|
| `scatter`, `scatter!` | `:scatter`, `:scatter3` | `:scatter` |
| `stem`, `stem!` | None | `:stem`, `:impulses` (optional) |
| `bar`, `bar!` | `:boxplot` | `:box` |
| `barerror`, `barerror!` | `:boxerror` | `:box` |
| `histogram` | `:histplot` | `:box`, `:horhist` (1-D); `:image`  (2-D) |
| `imagesc` | `:imagesc` | `:image`, `:rgbimage` |
| `surf`, `surf!` | `:hidden3d` | `:pm3d` |
| `contour` | `:contour` | `:labels` (optional) |
| `surfcontour` | `:contourproj` | `:labels` (optional) |
| `wireframe`, `wireframe!` | `:hidden3d` | None |
| `wiresurf`, `wiresurf!` | `:wiresurf` | None |
| `heatmap` | `:heatmap` | `:pm3d` |

::: {.callout-warning}

# Plotline themes

    Plotline themes must be handled with care: gnuplot requires plotline
    options to be specified in a certain order, which may not be repeated, and
    some combinations are invalid.  It is very easy to create erroneous
    plotlines.

:::

::: {.callout-note}

# Gaston is not a gnuplot parser

Gaston does not validate that the settings and plotline given to gnuplot are valid. When
gnuplot returns an error or warning, it is echoed to the terminal.

:::

## Multiplot

As mentioned above, a `Figure` contains a vector of `Axis`. Any figure with more than one axis is plotted using gnuplot's `multiplot` feature (except in the case where the terminal configuration contains `animate`).

There are several ways to insert axes into a figure. The first is to index into the figure:

```julia
f = Figure()
plot(f[2], sin)
plot(f[4], cos)
```

Note that:

* Indexing into a non-existing axis creates an empty axis at that index.
* It's possible to have empty axes (`f[1]` and `f[3]` above are empty).
* By default, Gaston will manage the figure's layout, trying to keep a square aspect ratio. In the
  example above, the figure will have dimensions 2x2.

The second method is to `push!` a figure into another:

```julia
f1 = plot(sin)
f2 = plot(cos)
push!(f1, f2)
```

Here, the axis at `f[2]` will be inserted into the axes vector of `f1`. It is possible to index
into a figure to obtain a specific axis:

```julia
f1 = plot(sin)
plot(f1[2], cos)  # f1 now contains two axes
f2 = Figure()
plot(tan)         # plot goes into f2 since it is the active figure
push!(f2, f1[2])  # the axis with a plot of cos is inserted into f2
```

The third and final method is to plot multiple figures together:

```julia
plot(f1, f2, multiplot = "...", autolayout = ...)
```

This will return a new figure with all axes from `f1` and `f2`. Any number of figures
may be provided as arguments.

The `Figure` constructor takes a couple of options to control how multiplot behaves:

* `multiplot`: a string that is appended to `set multiplot`, such as `"title 'A multiplot'"`.
  Defaults to `""`.
* `autolayout`: a boolean that controls whether Gaston should manage the figure's layout. Defaults
  to `true`.

## Managing multiple figures

Gaston has the ability to create and manage multiple GUI plot windows simultaneously. Each window
is backed up by its own gnuplot process. The following commands can be used to create and control
multiple windows.

#### Creating and selecting figures

```julia
Figure()
```

Creates a new, empty figure. All figures are of type `Gaston.Figure`. Gaston keeps internal
references to all figures, to prevent them from being garbage collected. As described
above, `Figure` takes two optional arguments, `multiplot` and `autolayout`.

When a figure is created, it becomes the active figure, meaning that subsequent
plot commands will go to this figure by default. It is possible to keep figures
in different variables:

```julia
fig1 = Figure()
fig2 = Figure()
```

and then redirect plot commands to the desired figure:

```julia
plot(fig1, ...)  # plot goes to fig1
plot!(fig2, ...) # new curve added to fig2
```

By default, `plot` resets the contents of a figure.

Usually it is more convenient to keep figures in variables, but it is also
possible to manage figures using _handles_:

```julia
Figure("density") # figure with handle "density"
Figure(:volume)   # figure with handle :volume
Figure(33)        # figure with handle 33
```

Handles can be of any type. All figures have a handle. By default, handles are
integers in increasing order starting from 1.

The keyword argument `handle` allows specifying the destination of a `plot` command:

```julia
plot(..., handle = :volume)
plot!(..., handle = 33)
scatter(..., handle = "density")
```

To activate a figure given its handle, use:

```julia
figure(handle)
```

It is possible to make an existing figure `f` the active figure with:

```julia
figure(f)
```

With no arguments, `figure()` returns the current figure.

To obtain the list of all current figures and their handles, and to identify the active figure,
use the unexported function `Gaston.listfigures()`.

#### Closing figures

To close the active figure, run

```julia
closefigure()
```

The figure with handle `h` can be closed with `closefigure(h)`. Likewise, to close figure `f` use `closefigure(f)`. Closing a figure quits the underlying gnuplot process. 

To close all figures, use `closeall()`.

## Saving plots

A plot can be saved to a file in any format supported by gnuplot, with the function

```julia
save([f] ; filename, term)
```

where the arguments are:

* `f`, which can be either a `Figure`, or an arbitrary value that is taken to be the handle of the figure to save. Defaults to the active figure.
* `filename`, a string that specifies the filename. If empty, it defaults to `figure-` followed by the figure's handle; the filename extension is set to the first three characters of the gnuplot terminal (see next argument).
* `term`, specifies the gnuplot terminal used to save the plot; defaults to `"pngcairo font ',7'"`.

## Defining new plot types and recipes

There are several ways to extend Gaston to create new plot types or to plot
arbitrary types. One is to define a new function that returns a
`Gaston.Figure`. The rest involve extending `Gaston.convert_args` in various
ways.

### Functions that return a `Gaston.Figure`

The first way to extend Gaston to handle arbitrary types is to define a new
function (and optionally new themes) that returns a `Gaston.Figure`. See an
example [here](recipes.qmd#functions-that-return-a-gaston.figure).  For 3-D
plot commands such as `splot`, the function `convert_args3` should be used
instead.

The recommended way to proceed is to:

0. Define new themes if necessary, by adding key-value pairs to `Gaston.sthemes` and/or
   `Gaston.pthemes`.
2. Process the function arguments as required.
1. Create a new figure inside the function, using either `Figure` or `MultiFigure`.
3. Use `plot` to add new axes and curves to the figure, possibly using the new themes.
4. Return the figure.

### Adding new methods to `Gaston.convert_args`

When the data provided to `plot` is not of a type that gnuplot directly understands,
Gaston calls the function `convert_args`, defined in the package `GastonRecipes`.
This function returns a value of one of three different types:

* `GastonRecipes.PlotRecipe`, used to define a single curve (coordinates and a plotline). See
  and example [here](recipes.qmd#plotrecipe).
* `GastonRecipes.AxisRecipe`, used to define an axis (settings, a vector of `PlotRecipe`s,
  and a boolean to define if the axis is three dimensional). See an example
  [here](recipes.qmd#axisrecipe).
* `GastonRecipes.FigureRecipe`, used to define a full figure (a vector of `AxisRecipes`,
  plus multiplot and autolayout settings). See an example [here](recipes.qmd#figurerecipe).

The function `convert_args` is called with all data and all keyword arguments
given to the `plot` command. Keyword arguments can be used to control the recipe's
behavior.

Note that these functions and types are not exported by Gaston.

## Internals

In Gaston, the basic building block is the `Plot` type. This type has two fields: the
plotline, a string; and the name of a file where the coordinates are stored. When a `Plot`
is constructed, the data provided is immediately written to a file; a `Plot` does not
store any coordinates.

On top of `Plot` we have the `Axis` type, which contains a vector of `Plot`s, a string
with the axis settings, and a boolean that indicates whether the axis should be
rendered with `plot` (2-D) or `splot` (3-D).

Finally, on top of `Axis` we have the `Figure` type, which contains a vector of `Axis`
plus multiplot configuration. Besides, a `Figure` contains a figure handle, and
most importantly, a gnuplot process with which it communicates. Each figure is
associated with a different gnuplot process.

When a `Figure` is displayed by Julia, the `show` function builds a set of commands
that are sent to gnuplot. Gnuplot is instructed to send a sentinel string back to
the figure, which indicates that gnuplot is done displaying the figure (and also
prevents race conditions).

Each `Figure` is associated with a finalizer that makes sure its associated gnuplot
process exits gracefully.

Gaston uses the following functions to set up and communicate with gnuplot:

* `gp_start` initializes a new gnuplot process and connects to its stdin, stdout and
  stderr streams.
* `gp_quit` terminates a gnuplot process.
* `gp_send` sends a string of commands to an existing gnuplot process.
* `gp_exec` starts a new gnuplot process, sends it commands, and quits the process.

Gaston also keeps some internal state:

* `Gaston.state.figures` stores pointers to all existing figures.
* `Gaston.state.enabled` is `true` if gnuplot is runnable.
* `Gaston.state.activefig` stores the handle of the currently active figure.


================================================
FILE: docs/v2/migrate.qmd
================================================
---
title: "Migration guide"
---

```{julia}
#| echo: false
#| output: false
using Gaston
Gaston.config.term = "pngcairo font ',10' size 640,480"
Gaston.config.output = :echo
```

This guide provides hints on how to migrate from Gaston v1 to v2. In
side-by-side code comparisons, Gaston v1 is always on the left, and v2 on the
right.

### Axis settings

In v1, axes settings are wrapped in a type called `Axes`, and given as key-value pairs.
In v2, settings always come before data, and may be given as strings and/or key-value
pairs enclosed in curly brackets (which require either `@plot` or `@gpkw`).

::: {layout-ncol=2}

```julia
using SpecialFunctions
x = y = 0:0.075:10
surf(x, y, (x,y) -> besselj0(y)*x^2, with = "pm3d",
     Axes(view = (45, 45),
          pm3d = "lighting primary 0.5 specular 0.4",
          key = :off)
     )
```

```julia
using SpecialFunctions
x = y = 0:0.075:10
@gpkw surf({view = (45, 45),
            pm3d = "lighting primary 0.5 specular 0.4",
            key = :off},
           x, y, (x,y) -> besselj0(y)*x^2)
```

:::

Two other differences:

* Using `key = false` instead of `key = :off` is valid syntax to produce `unset key`.
* In v2, `surf` is a plot style that includes `with pm3d`. The generic 3-D plot
  command is `splot`, so `splot(..., x, y, z, "with pm3d")` in v2 is equivalent
  to `surf` in v1.

### Plotline (or curve appearance settings)

In v1, a curve's appearance is configured with key-value arguments that are
not data and not `Axes`. Values can be symbols or strings, which are interpreted
differently, and is some cases spaces had to be written as underscores.

In v2, all curve settings (or _plotline_) are given after the data.
Just like
Download .txt
gitextract__535gg22/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       └── tagbot.yml
├── .gitignore
├── CHANGELOG.md
├── COPYING
├── LICENSE.txt
├── Project.toml
├── README.md
├── docs/
│   ├── notebook/
│   │   ├── how-to-plot-a-torus.jl
│   │   ├── tutorial-3d.jl
│   │   └── tutorial-essentials.jl
│   ├── v1/
│   │   ├── 2d-gallery.md
│   │   ├── 2dplots.md
│   │   ├── 3d-gallery.md
│   │   ├── 3dplots.md
│   │   ├── api.md
│   │   ├── examples.md
│   │   ├── extending.md
│   │   ├── extguide.md
│   │   ├── faq.md
│   │   ├── figures.md
│   │   ├── index.md
│   │   ├── introduction.md
│   │   └── plotguide.md
│   └── v2/
│       ├── .gitignore
│       ├── Project.toml
│       ├── _extensions/
│       │   └── jjallaire/
│       │       └── code-visibility/
│       │           ├── _extension.yml
│       │           └── code-visibility.lua
│       ├── _quarto.yml
│       ├── assets/
│       │   ├── cairolatex.tex
│       │   ├── lorenz.jl
│       │   └── test.tex
│       ├── examples.qmd
│       ├── index.qmd
│       ├── manual.qmd
│       ├── migrate.qmd
│       ├── recipes.qmd
│       ├── reference.qmd
│       ├── styles.css
│       └── tutorial.qmd
├── src/
│   ├── Gaston.jl
│   ├── gaston_aux.jl
│   ├── gaston_builtinthemes.jl
│   ├── gaston_figures.jl
│   ├── gaston_llplot.jl
│   ├── gaston_options.jl
│   ├── gaston_plot.jl
│   └── gaston_recipes.jl
└── test/
    ├── Project.toml
    ├── downstream.jl
    ├── downstream_dev.jl
    ├── manualtests.txt
    ├── preferences.jl
    └── runtests.jl
Condensed preview — 55 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (367K chars).
[
  {
    "path": ".github/dependabot.yml",
    "chars": 313,
    "preview": "# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\nversion: 2\nupda"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1324,
    "preview": "name: ci\n\non:\n  pull_request:\n  workflow_dispatch:\n  push:\n    branches: [master]\n\nconcurrency: \n  group: ${{ github.wor"
  },
  {
    "path": ".github/workflows/tagbot.yml",
    "chars": 408,
    "preview": "name: tagbot\n\non:\n  issue_comment:\n    types: ['created']\n  workflow_dispatch:\n    inputs:\n      lookback:\n        defau"
  },
  {
    "path": ".gitignore",
    "chars": 106,
    "preview": "docs/build\n\nManifest-v*.toml\nManifest.toml\n\ndocs/v2/.quarto/\ndocs/v2/_site/\ndocs/v1/_site/\ndocs/v1/assets\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 5847,
    "preview": "New in version 2\n================\n\nGaston v2 is a breaking release. A\n[migration guide](https://mbaz.github.io/Gaston.jl"
  },
  {
    "path": "COPYING",
    "chars": 1060,
    "preview": "Copyright (c) 2012 Miguel Bazdresch\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthi"
  },
  {
    "path": "LICENSE.txt",
    "chars": 1060,
    "preview": "Copyright (c) 2013 Miguel Bazdresch\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthi"
  },
  {
    "path": "Project.toml",
    "chars": 711,
    "preview": "name = \"Gaston\"\nuuid = \"4b11ee91-296f-5714-9832-002c20994614\"\nversion = \"2.0.2\"\n\n[deps]\nColorSchemes = \"35d6a980-a343-54"
  },
  {
    "path": "README.md",
    "chars": 3031,
    "preview": "[![Docs stable](https://img.shields.io/badge/docs-stable-blue.svg)](\n  https://mbaz.github.io/Gaston.jl/v2/\n)\n[![License"
  },
  {
    "path": "docs/notebook/how-to-plot-a-torus.jl",
    "chars": 12602,
    "preview": "### A Pluto.jl notebook ###\n# v0.20.10\n\nusing Markdown\nusing InteractiveUtils\n\n# This Pluto notebook uses @bind for inte"
  },
  {
    "path": "docs/notebook/tutorial-3d.jl",
    "chars": 9074,
    "preview": "### A Pluto.jl notebook ###\n# v0.20.10\n\nusing Markdown\nusing InteractiveUtils\n\n# This Pluto notebook uses @bind for inte"
  },
  {
    "path": "docs/notebook/tutorial-essentials.jl",
    "chars": 23211,
    "preview": "### A Pluto.jl notebook ###\n# v0.20.10\n\nusing Markdown\nusing InteractiveUtils\n\n# This Pluto notebook uses @bind for inte"
  },
  {
    "path": "docs/v1/2d-gallery.md",
    "chars": 5866,
    "preview": "# [2-D Gallery](@id twodeegal)\n\n(Many of these examples taken from, or inspired by, [@lazarusa's amazing gallery](https:"
  },
  {
    "path": "docs/v1/2dplots.md",
    "chars": 13682,
    "preview": "# [2-D plotting tutorial](@id twodeetut)\n\nThis section provides a brief tutorial on 2-D plotting, with examples on how t"
  },
  {
    "path": "docs/v1/3d-gallery.md",
    "chars": 5706,
    "preview": "# [3-D Gallery](@id threedeegal)\n\n(Many of these examples taken from, or inspired by, [@lazarusa's amazing gallery](http"
  },
  {
    "path": "docs/v1/3dplots.md",
    "chars": 3162,
    "preview": "# [3-D plotting tutorial](@id threedeetut)\n\nThree dimensional plots can be created with the commands `surf` and `surf!`."
  },
  {
    "path": "docs/v1/api.md",
    "chars": 16,
    "preview": "# API Reference\n"
  },
  {
    "path": "docs/v1/examples.md",
    "chars": 20498,
    "preview": "# Examples\n\nThe plots below have been rendered in a png terminal with the following configuration:\n```julia\nGaston.confi"
  },
  {
    "path": "docs/v1/extending.md",
    "chars": 4547,
    "preview": "# Extending Gaston\n\nGaston offers multiple plotting commands that cover most cases of general data plotting. However, it"
  },
  {
    "path": "docs/v1/extguide.md",
    "chars": 18,
    "preview": "# Extension Guide\n"
  },
  {
    "path": "docs/v1/faq.md",
    "chars": 6051,
    "preview": "# Usage notes and FAQ\n\n## How to set the terminal\n\nGnuplot supports a huge amount of terminals. Most modern gnuplot inst"
  },
  {
    "path": "docs/v1/figures.md",
    "chars": 725,
    "preview": "# Managing multiple figures\n\nWhen using a graphical terminal such as `qt` or `wxt`, it is possible to have multiple figu"
  },
  {
    "path": "docs/v1/index.md",
    "chars": 6464,
    "preview": "```@meta\nAuthor = \"Miguel Bazdresch\"\n```\n\n# Gaston.jl\n\nGaston (source code [here](https://github.com/mbaz/Gaston.jl)) is"
  },
  {
    "path": "docs/v1/introduction.md",
    "chars": 10420,
    "preview": "```@meta\nAuthor = \"Miguel Bazdresch\"\n```\n\n# Introduction to plotting\n\nGaston supports essentially all 2-D plots styles t"
  },
  {
    "path": "docs/v1/plotguide.md",
    "chars": 9553,
    "preview": "# Manual\n\nThis manual covers all aspects of using Gaston.\n\n## Gaston Settings\n\n### The terminal\n\nBy default, gnuplot cho"
  },
  {
    "path": "docs/v2/.gitignore",
    "chars": 10,
    "preview": "/.quarto/\n"
  },
  {
    "path": "docs/v2/Project.toml",
    "chars": 427,
    "preview": "[deps]\nColorSchemes = \"35d6a980-a343-548e-a6ea-1d62b119f2f4\"\nGaston = \"4b11ee91-296f-5714-9832-002c20994614\"\nGastonRecip"
  },
  {
    "path": "docs/v2/_extensions/jjallaire/code-visibility/_extension.yml",
    "chars": 104,
    "preview": "title: Code Visibility\nauthor: fast.ai\nversion: 1.0.0\ncontributes:\n  filters:\n    - code-visibility.lua\n"
  },
  {
    "path": "docs/v2/_extensions/jjallaire/code-visibility/code-visibility.lua",
    "chars": 1169,
    "preview": "\n\n\n-- remove any lines with the hide_line directive.\nfunction CodeBlock(el)\n  if el.classes:includes('cell-code') then\n "
  },
  {
    "path": "docs/v2/_quarto.yml",
    "chars": 780,
    "preview": "project:\n  type: website\n\nwebsite:\n  title: \"Gaston.jl\"\n  navbar:\n    left:\n      - href: index.qmd\n        text: Introd"
  },
  {
    "path": "docs/v2/assets/cairolatex.tex",
    "chars": 166,
    "preview": "\\documentclass{article}\n\\usepackage{amsmath}\n\\usepackage{graphicx}\n\\usepackage{color}\n\n\\begin{document}\n\\begin{figure}\n "
  },
  {
    "path": "docs/v2/assets/lorenz.jl",
    "chars": 1515,
    "preview": "using Gaston\nusing ColorSchemes\n\nBase.@kwdef mutable struct Lorenz\n    dt::Float64 = 0.01\n    σ::Float64 = 10\n    ρ::Flo"
  },
  {
    "path": "docs/v2/assets/test.tex",
    "chars": 5261,
    "preview": "% GNUPLOT: LaTeX picture with Postscript\n\\begingroup\n  \\makeatletter\n  \\providecommand\\color[2][]{%\n    \\GenericError{(g"
  },
  {
    "path": "docs/v2/examples.qmd",
    "chars": 11618,
    "preview": "---\ntitle: \"Examples\"\n---\n\n```{julia}\n#| echo: false\n#| output: false\nusing Gaston\nGaston.config.term = \"pngcairo font '"
  },
  {
    "path": "docs/v2/index.qmd",
    "chars": 7645,
    "preview": "---\ntitle: \"Introduction\"\n---\n\n[Gnuplot](http://www.gnuplot.info/) is a venerable (but actively\ndeveloped), very powerfu"
  },
  {
    "path": "docs/v2/manual.qmd",
    "chars": 19385,
    "preview": "---\ntitle: \"Manual\"\n---\n\nThis manual covers all aspects of using Gaston.\n\n## Configuration\n\n### The terminal\n\nBy default"
  },
  {
    "path": "docs/v2/migrate.qmd",
    "chars": 4295,
    "preview": "---\ntitle: \"Migration guide\"\n---\n\n```{julia}\n#| echo: false\n#| output: false\nusing Gaston\nGaston.config.term = \"pngcairo"
  },
  {
    "path": "docs/v2/recipes.qmd",
    "chars": 9270,
    "preview": "---\ntitle: \"Recipes\"\n---\n\n```{julia}\n#| echo: false\n#| output: false\nusing Gaston\nGaston.config.term = \"pngcairo font ',"
  },
  {
    "path": "docs/v2/reference.qmd",
    "chars": 4730,
    "preview": "---\ntitle: \"API Reference\"\n---\n\n```{julia}\n#| echo: false\n#| output: false\nusing Gaston\nusing QuartoTools: Cell, Markdow"
  },
  {
    "path": "docs/v2/styles.css",
    "chars": 17,
    "preview": "/* css styles */\n"
  },
  {
    "path": "docs/v2/tutorial.qmd",
    "chars": 27824,
    "preview": "---\ntitle: \"Tutorial\"\n---\n\nIf you have not installed Gaston yet, then run the following commands in the Julia REPL:\n\n```"
  },
  {
    "path": "src/Gaston.jl",
    "chars": 4475,
    "preview": "## Copyright (c) 2013 Miguel Bazdresch\n##\n## This file is distributed under the 2-clause BSD License.\n\nmodule Gaston\n\n# "
  },
  {
    "path": "src/gaston_aux.jl",
    "chars": 20637,
    "preview": "# Copyright (c) 2013 Miguel Bazdresch\n##\n## This file is distributed under the 2-clause BSD License.\n\n# Auxiliary, non-e"
  },
  {
    "path": "src/gaston_builtinthemes.jl",
    "chars": 1992,
    "preview": "# Themes in use are stored in this dictionary.\n# Each theme is identified by a name.\n\n# settings themes\nsthemes = @gpkw "
  },
  {
    "path": "src/gaston_figures.jl",
    "chars": 13870,
    "preview": "## Copyright (c) 2013-2021 Miguel Bazdresch\n##\n## This file is distributed under the 2-clause BSD License.\n\n# Code relat"
  },
  {
    "path": "src/gaston_llplot.jl",
    "chars": 2718,
    "preview": "## Copyright (c) 2013 Miguel Bazdresch\n##\n## This file is distributed under the 2-clause BSD License.\n\n# Write plot data"
  },
  {
    "path": "src/gaston_options.jl",
    "chars": 2922,
    "preview": "# Macro and functions to handle options in brackets\n\n\"\"\"\n    @Q_str\n\nInserts single quotation marks around a string.\n\nWh"
  },
  {
    "path": "src/gaston_plot.jl",
    "chars": 11939,
    "preview": "## Copyright (c) 2013 Miguel Bazdresch\n##\n## This file is distributed under the 2-clause BSD License.\n\n\"\"\"\n    plot([f::"
  },
  {
    "path": "src/gaston_recipes.jl",
    "chars": 13753,
    "preview": "## Copyright (c) 2013 Miguel Bazdresch\n##\n## This file is distributed under the 2-clause BSD License.\n\n# Recipes: argume"
  },
  {
    "path": "test/Project.toml",
    "chars": 447,
    "preview": "[deps]\nAqua = \"4c88cf16-eb10-579e-8560-4a9242c79595\"\nDownloads = \"f43a241f-c20a-4ad4-852c-f6b1247861c6\"\nJET = \"c3a54625-"
  },
  {
    "path": "test/downstream.jl",
    "chars": 2603,
    "preview": "using Downloads, JSON, Test\n\nfunction available_channels()\n    juliaup = \"https://julialang-s3.julialang.org/juliaup\"\n  "
  },
  {
    "path": "test/downstream_dev.jl",
    "chars": 2066,
    "preview": "using Pkg\n\nLibGit2 = Pkg.GitTools.LibGit2\nTOML = Pkg.TOML\n\nfailsafe_clone_checkout(path, url, pkg = nothing; stable = tr"
  },
  {
    "path": "test/manualtests.txt",
    "chars": 995,
    "preview": "Tests to be run manually.\n\n* Produce a sixelgd plot, using `xterm -ti vt340`, `wezterm` or other\n  sixelgd-capable termi"
  },
  {
    "path": "test/preferences.jl",
    "chars": 1617,
    "preview": "using Preferences, Gaston\n\nconst PREVIOUS_DEFAULT_GNUPLOT = load_preference(Gaston, \"gnuplot_binary\")\n\ninvalidate_compil"
  },
  {
    "path": "test/runtests.jl",
    "chars": 26626,
    "preview": "## Copyright (c) 2013 Miguel Bazdresch\n##\n## This file is distributed under the 2-clause BSD License.\n\nusing Test, Gasto"
  }
]

About this extraction

This page contains the full source code of the mbaz/Gaston.jl GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 55 files (338.2 KB), approximately 110.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!