Skip to content

Commit 36cda5d

Browse files
committed
Add ClimaExplorer
This commit adds an interactive viewer for ClimaAnalysis [skip ci][ci skip]
1 parent c8314a7 commit 36cda5d

File tree

8 files changed

+126
-1
lines changed

8 files changed

+126
-1
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ GeoMakie = "0.6.5, 0.7"
2626
JuliaFormatter = "1"
2727
NCDatasets = "0.13.1, 0.14"
2828
OrderedCollections = "1.3"
29+
Reexport = "1"
2930
SafeTestsets = "0.1"
3031
Statistics = "1"
31-
Reexport = "1"
3232
Test = "1"
3333
julia = "1.9"
3434

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Check out the [documentation](https://CliMA.github.io/ClimaAnalysis.jl) for more
2525
- Window variables within given ranges (e.g., select times between 10 and 100 days)
2626
- Perform mathematical operations between output variables.
2727
- Extract dimensions from conventional names (e.g., `times`).
28+
- Interactively explore the content of a simulation with `ClimaExplorer`.
2829

2930
## ClimaAnalysis.jl Developer Guidelines
3031

climaexplorer/Project.toml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name = "ClimaExplorer"
2+
authors = ["Gabriele Bozzola <gbozzola@caltech.edu>"]
3+
version = "0.0.1"
4+
5+
[deps]
6+
Bonito = "824d6782-a2ef-11e9-3a09-e5662e0c26f8"
7+
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
8+
ClimaAnalysis = "29b5916a-a76c-4e73-9657-3c8fd22e65e6"
9+
GeoMakie = "db073c08-6b98-4ee5-b6a4-5efafb3259c6"
10+
11+
[compat]
12+
Bonito = "3"
13+
ClimaAnalysis = "0.5.5"
14+
GeoMakie = "0.6.5, 0.7"

climaexplorer/assets/interactive.css

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.container {
2+
display: flex;
3+
}
4+
.column {
5+
padding: 10px;
6+
}
7+
.left {
8+
flex: 0 1 20%; /* Flex-grow: 0, Flex-shrink: 1, Flex-basis: 20% */
9+
}
10+
.right {
11+
flex: 1;
12+
}

climaexplorer/explorer.jl

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
length(ARGS) == 1 || error("Usage: julia --project=climaexplorer explorer.jl <PATH>")
2+
3+
include(joinpath(@__DIR__, "libexplorer.jl"))
4+
5+
path = first(ARGS)
6+
7+
app = BonitoApp(path)
8+
9+
server = Server(app, "0.0.0.0", 8080)
10+
println(server)
11+
route!(server, "/" => app)
12+
wait(server)

climaexplorer/libexplorer.jl

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import ClimaAnalysis
2+
import Bonito: Observable, App, Slider, Dropdown, DOM, Server, route!, wait, Asset
3+
import CairoMakie
4+
import GeoMakie
5+
6+
function BonitoApp(path)
7+
app = App() do
8+
climastyle = Asset(joinpath(@__DIR__, "assets", "interactive.css"))
9+
simdir = ClimaAnalysis.SimDir(path)
10+
variables = ClimaAnalysis.available_vars(simdir) |> collect
11+
vars_menu = Dropdown(variables)
12+
short_name = vars_menu.value.val
13+
# TODO: Add Dropdown menus for reduction and period
14+
15+
# reductions = ClimaAnalysis.available_reductions(simdir; short_name) |> collect
16+
# reductions_menu = Dropdown(reductions)
17+
# reduction = reductions_menu.value.val
18+
# periods = ClimaAnalysis.available_periods(simdir; short_name, reduction) |> collect
19+
# periods_menu = Dropdown(periods)
20+
21+
# Set up initial var
22+
reduction = Observable(first(ClimaAnalysis.available_reductions(simdir; short_name)))
23+
period = Observable(first(ClimaAnalysis.available_periods(simdir; short_name, reduction = reduction.val)))
24+
var = get(simdir; short_name, reduction = reduction.val, period = period.val)
25+
time_slider = Slider(ClimaAnalysis.times(var))
26+
level_slider = Slider(ClimaAnalysis.altitudes(var))
27+
28+
var = map(vars_menu.value) do short_name
29+
reduction[] = first(ClimaAnalysis.available_reductions(simdir; short_name))
30+
period[] = first(ClimaAnalysis.available_periods(simdir; short_name, reduction = reduction.val))
31+
var = get(simdir; short_name, reduction = reduction.val, period = period.val)
32+
time_slider.values[] = ClimaAnalysis.times(var)
33+
level_slider.values[] = ClimaAnalysis.altitudes(var)
34+
setindex!(time_slider, first(ClimaAnalysis.times(var)))
35+
setindex!(level_slider, first(ClimaAnalysis.altitudes(var)))
36+
var
37+
end
38+
39+
var = map(time_slider) do time
40+
short_name = vars_menu.value.val
41+
# Trigger level_slidel
42+
setindex!(level_slider, level_slider.value.val)
43+
ClimaAnalysis.slice(get(simdir; short_name, reduction = reduction.val, period = period.val); time, z = level_slider.value.val)
44+
end
45+
46+
var = map(level_slider) do level
47+
short_name = vars_menu.value.val
48+
ClimaAnalysis.slice(get(simdir; short_name, reduction = reduction.val, period = period.val); time = time_slider.value.val, z = level)
49+
end
50+
51+
fig = map(var) do sliced_var
52+
fig = CairoMakie.Figure(size=(1200, 760), fontsize=30)
53+
ClimaAnalysis.Visualize.contour2D_on_globe!(fig, sliced_var)
54+
# ClimaAnalysis.Visualize.plot!(fig, sliced_var)
55+
fig
56+
end
57+
58+
return DOM.div(
59+
DOM.h3("Output: ", path),
60+
DOM.div(
61+
DOM.div(
62+
climastyle,
63+
DOM.h4("Short name"),
64+
vars_menu,
65+
DOM.h4("Reduction: ", reduction),
66+
DOM.h4("Period: ", period),
67+
DOM.h4("Time: ", time_slider.value),
68+
time_slider,
69+
DOM.h4("Altitude: ", level_slider.value),
70+
level_slider;
71+
class = "column left",
72+
),
73+
DOM.div(fig, class = "column right"),
74+
class = "container"
75+
))
76+
end
77+
return app
78+
end

docs/make.jl

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ makedocs(;
2929
checkdocs = :exports,
3030
pages = [
3131
"Home" => "index.md",
32+
"Explorer" => "explorer.md",
3233
"APIs" => "api.md",
3334
"How do I?" => "howdoi.md",
3435
],

docs/src/explorer.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
`ClimaExplorer`
2+
=============
3+
4+
`ClimaExplorer` is
5+
6+
7+
I wrote this page but accidentally deleted it :(

0 commit comments

Comments
 (0)