Plots

Biblioteka Plots, chyba najbardziej popularna w Julii do tworzenia wykresów, w gruncie rzeczy nie jest biblioteką tworzącą wykresy, a jedynie metapakietem. Jego zadaniem jest stworzenie wspólnego interfejsu dla innych bibliotek. "Prawdziwe" biblioteki stojące za wykresami to

  • GR

  • InspectDR (szybkie interaktywne wykresy)

  • PyPlot (wrapper do matplotliba - Python)

  • Gaston (wrapper do Gnuplota)

  • Plotly (wrapper do plotly - JavaScript)

  • UnicodePlots (wykresy ASCII)

Backend można oczywiście zmieniać według możliwości i upodobań, domyślny to GR.

Plots podobnie jak Gadfly używa tzw. gramatyki grafiki. Wymaga to przyzwyczajenia się do innej koncepcji wykresu, który jest odpowiednikiem zdania w językach naturalnych, złożonego z danych, estetyki i geometrii (tak jak rzeczowniki, czasowniki i przymiotniki). Plots jest mniej restrykcyjny jeżeli chodzi o implementację tej filozofii i można z nim pracować bez ścisłego stosownia się do jej zasad.

Najprostszy wykres

using Plots

x = 0:0.1:pi
y = cos.(x)
plot(x, y)

Jeżeli jako y podamy tabelę z kolumnami, to każda z nich zostanie interpretowana jako wykres

y = [cos.(x) sin.(x)]
println(typeof(y))
plot(x, y)

Istniejące wykresy można modyfikować poleceniami z wykrzyknikiem, np plot! doda wykres do poprzedniego

z = tan.(x)
plot!(x, z)

Cechy wykresu

Wszelkie cechy wykresu jakie chcemy modyfikować będą zawsze przekazywane jako nazwane atrybuty (np. title="Wykres 1"). Natomiast zmienne pozycyjne (takie jak x, y, ...) są traktowane zawsze jako dane.

plot(x, y, seriestype=[:stepmid :scatter], label=["cos" "sin"], lw=2)
unicodeplots()
plot(x, y, title="Wykres 1", label=["cos" "sin"], lw=2)
Wykres 1                     
                +----------------------------------------+    
        1.05997 | r--._.        ._------._               | cos
                | |    '*..  _-"`         "*..           | sin
                | |       ]-=                '*.         |    
                | |     .-' "\,                 \.       |    
                | |   .r`     "\.                 \.     |    
                | | .r'          \.                "\_   |    
                | |./             "\.                 \. |    
                |-@------------------v-------------------|    
                | |                   \.                 |    
                | |                     \.               |    
                | |                      "*.             |    
                | |                        "\.           |    
                | |                          "*..        |    
                | |                             '-..     |    
       -1.05911 | |                                '"--* |    
                +----------------------------------------+    
                 -0.093                             3.193

Listę atrybutów z danej kategorii można sprawdzić poleceniem plotattr (:Series, :Plot, :Axis, :Subplot). Dozwolone wartości danego atrybutu dostajemy podając jego nazwę.

plotattr(:Series)
plotattr("seriestype")
plotattr(:Plot)
plotattr(:Axis)
gr()
plot(x, tan.(x), framestyle=:origin, legend=:none, ylims=[-5, 5], xlabel="α", ylabel="tan(α)", linewidth=2)

Dużo typów wykresów (np. :scatter) oraz atrybutów (np. ylims) ma swoje wersje w postaci funkcji modyfikujących istniejacy wykres bądź sprawdzających stan (np. ylims() lub ylims(-10, 10)) co wprowadza alternatywną składnię zbliżoną do filozofii maszyny stanu.

println(ylims())
ylims!(-10, 10)
scatter!(x, cot.(x), marker=:rect, markersize=2)

Przykłady wykresów 2D

x = range(-1, 1, 100)
y = range(-2, 2, 100)
z = randn(length(x), length(y))
plot(x, y, z, seriestype=:heatmap, c=:blues)
function n2(x1, x2, μ1, μ2, σ1, σ2, r)
    N = 1 / (2 * pi * σ1 * σ2 * sqrt(1 - r^2))
    @. N * exp(-1 / (1 - r^2) * ((x1 - μ1)^2 / σ1^2 - 2 * r * (x1 - μ1) * (x2 - μ2) / (σ1 * σ2) + (x2 - μ2)^2 / σ2^2))
end
plot(x, y, n2(x', y, 0.0, 0.5, 0.2, 0.5, -0.5), seriestype=:contour, framestyle=:box, xlabel="x", ylabel="y")

Podwykresy

Kilka wykresów można objąć jednym poleceniem plot z atrybutem layout, wtedy będą tworzyły podwykresy większego wykresu. Atrybuty mogą teraz dotyczyć albo konkretnego podwykresu, albo

x = -2pi:0.05:2pi
println(x)
plot(plot(x, sin.(x)), 
     plot(x, cos.(x), color="black"), 
     plot(x, tan.(x), linestyle=:dashdot, linewidth=2), 
     plot(x, cot.(x), color="red", seriestype=:scatter, markershape=:cross, markersize=2), 
     layout=(2, 2), legend=:false, ylims=(-3, 3))

Makro @layout pozwala tworzyć bardziej skomplikowane układy. Moduł Plots.PlotMeasures wprowadza jednostki względne (w/h - szerokość/wysokość) oraz bezwzględne (cm, px, itd.). LIterki a, b, c nie mają znaczenia i są tylko wewnętrznymi identyfikatorami kolejnych podwykresów w makrze @layout, a podkreślenie omija dane pole

using Plots.PlotMeasures
l = @layout[ a{0.25w} b{0.8h}
             _       c        ]
x = range(-2, 2, 100)
y = range(-1.5, 1.5, 100)
plot( plot(sum(n2(x', y, 0.0, 0.5, 1.0, 0.5, -0.5), dims=2), y, legend=:none, xlims=(0, 15)),
      plot(x, y, n2(x', y, 0.0, 0.5, 1.0, 0.5, -0.5), seriestype=:heatmap, framestyle=:box, colorbar=:none),
      plot(x, sum(n2(x', y, 0.0, 0.5, 1.0, 0.5, -0.5), dims=1)', legend=:none, ylims=(0, 15)),
      layout=l
    )

Zadanie

Odtworzyć poniższy wykres przedstawiający w dwuwymiarowym rzucie fukcję falową stanu 1s i 2p (0 i ±\pm1) atomu wodoru w dwóch górnych panelach. Dwa dolne prezentują przekrój przez gęstość prawdopodobieństwa (czyli ψ2\left|\psi\right|^2) wzdłuż osi x lub y dla funkcji falowych. Wzory na funkcje falowe można znaleźć tutaj. Skala jest w Angstromach (101110^{-11} m), wartość promieniu Bohra można wpisać jako stałą.|

hydrogen.png

CC BY-SA 4.0 Krzysztof Miernik. Last modified: December 04, 2023. Website built with Franklin.jl and the Julia programming language.