CDF reader benchmarks

Abstract
Although not a full-featured CDF library (writing is not supported yet) like CDFpp or CDFlib, CommonDataFormat.jl offers a fast and user-friendly interface for reading CDF files, implemented entirely in Julia. It supports partial loading and multi-threaded access, enabling efficient reading of selected variables or time intervals—particularly beneficial when working with large CDF datasets.

Reading Common Data Format (CDF) files is a common task in space physics. Here we compare the performance of different implementations of CDF reader (Julia, C++, Python, etc.)

See benchmarks.ipynb - CDFpp for a relative comparison of CDFpp and other CDF readers.

Feature Comparison

Feature CommonDataFormat.jl CDFpp CDFlib
Language Julia C++ (Python wrappers) Python
Lazy loading ✅ Yes ✅ Yes ❌ No
Partial Loading ✅ Yes ❌ No ❌ No
Parallel loading ✅ Yes Thread-safe ❌ No
CDF writing ❌ No ✅ Yes ✅ Yes

Setup

Code
dir = "tutorials/cdf"
if isdir(dir)
    cd(dir)
end

Pkg.activate(".")
Pkg.resolve()
Pkg.instantiate()

using CommonDataFormat
using Downloads
using PythonCall
using Chairmarks
using CairoMakie
using DataFrames
using AlgebraOfGraphics
  Activating project at `~/src/juliaspacephysics.github.io/tutorials/cdf`
     Project No packages added to or removed from `~/src/juliaspacephysics.github.io/tutorials/cdf/Project.toml`
    Manifest No packages added to or removed from `~/src/juliaspacephysics.github.io/tutorials/cdf/Manifest.toml`
Code
urls = [
    "https://hephaistos.lpp.polytechnique.fr/data/mirrors/CDF/test_files/mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf",
    "https://lasp.colorado.edu/mms/sdc/public/about/browse/mms1/edp/fast/l2/dce/2022/11/mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf",
    "https://lasp.colorado.edu/mms/sdc/public/about/browse/mms1/fpi/fast/l2/des-dist/2022/11/mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf",
    "https://cdaweb.gsfc.nasa.gov/pub/data/solar-orbiter/rpw/science/l3/bia-efield/2022/solo_l3_rpw-bia-efield_20220220_v03.cdf"
]
4-element Vector{String}:
 "https://hephaistos.lpp.polytech" ⋯ 50 bytes ⋯ "_l2_scsrvy_20190301_v2.2.0.cdf"
 "https://lasp.colorado.edu/mms/s" ⋯ 62 bytes ⋯ "ast_l2_dce_20221110_v3.1.0.cdf"
 "https://lasp.colorado.edu/mms/s" ⋯ 78 bytes ⋯ "dist_20221103060000_v3.4.0.cdf"
 "https://cdaweb.gsfc.nasa.gov/pu" ⋯ 61 bytes ⋯ "pw-bia-efield_20220220_v03.cdf"

Set the environment variable CDF_BENCH_DOWNLOAD=true before rendering if you want the tutorial to download the test files listed above automatically.

Code
data_dir = joinpath(pwd(), "data")
mkpath(data_dir)

function ensure_local_copy(urls; download::Bool=false)
    local_files = String[]
    for url in urls
        local_path = joinpath(data_dir, basename(url))
        if !isfile(local_path) && download
            try
                Downloads.download(url, local_path)
            catch err
                @warn "Failed to download" url exception = err
            end
        end
        isfile(local_path) && push!(local_files, local_path)
    end
    return local_files
end

download_remote = get(ENV, "CDF_BENCH_DOWNLOAD", "false") in ("true", "1", "yes")
files = ensure_local_copy(urls; download=download_remote)

if isempty(files) && !download_remote
    @info "No CDF files found in $(data_dir). Set ENV[\"CDF_BENCH_DOWNLOAD\"] = \"true\" before rendering to download the test files automatically."
end

files
4-element Vector{String}:
 "/Users/zijin/src/juliaspacephys" ⋯ 46 bytes ⋯ "_l2_scsrvy_20190301_v2.2.0.cdf"
 "/Users/zijin/src/juliaspacephys" ⋯ 43 bytes ⋯ "ast_l2_dce_20221110_v3.1.0.cdf"
 "/Users/zijin/src/juliaspacephys" ⋯ 54 bytes ⋯ "dist_20221103060000_v3.4.0.cdf"
 "/Users/zijin/src/juliaspacephys" ⋯ 42 bytes ⋯ "pw-bia-efield_20220220_v03.cdf"

Julia interface to different CDF libraries

Interface to CommonDataFormat.jl

Code
module JLCDF
import CommonDataFormat as CDF

load(fname) = CDF.CDFDataset(fname)
list_variables(fname) = load(fname) |> keys
function get_var_data(fname, varname=nothing)
    ds = load(fname)
    varname = @something varname keys(ds)[1]
    return Array(ds[varname])
end
function full_load(fname)
    ds = load(fname)
    return [Array(ds[k]) for k in keys(ds)]
end
end
Main.Notebook.JLCDF

Interface to CDFpp

Code
module Pycdfpp
using PythonCall
const pycdfpp = pyimport("pycdfpp")

load(fname) = @py pycdfpp.load(fname)

function list_variables(fname)
    cdf = load(fname)
    @py list(cdf)
end

function get_var_data(fname, varname=nothing)
    ds = load(fname)
    varname = @something varname pylist(ds)[0]
    return ds[varname].values
end

function full_load(fname)
    c = load(fname)
    [c[varname].values for varname in c]
end
end
Main.Notebook.Pycdfpp

Interface to CDFlib

Code
module CDFlib
using PythonCall
const cdflib = pyimport("cdflib")

load(fname) = @py cdflib.CDF(fname)
function list_variables(fname)
    @py begin
        cdf = cdflib.CDF(fname)
        info = cdf.cdf_info()
        info.rVariables + info.zVariables
    end
end

function get_var_data(fname, varname=nothing)
    cdf = load(fname)
    varname = @something varname cdf.cdf_info().zVariables[0]
    data = cdf.varget(varname)
end

function full_load(fname)
    c = load(fname)
    variables = @py begin
        cdf_info = c.cdf_info()
        cdf_info.rVariables + cdf_info.zVariables
    end
    map(variables) do varname
        if pyconvert(Int, c.varinq(varname).Last_Rec) != -1
            @py c.varget(varname)
        end
    end
end
end
Main.Notebook.CDFlib
Code
function run_benchmarks(files, libs, func; n=3, evals=4)
    records = map(Iterators.product(files, libs, 1:n)) do (file, lib, i)
        fname = basename(file)
        f = getfield(lib, func)
        f(file) # warmup
        GC.gc()
        sample = @b f(file) evals = evals
        (; file=fname, library=nameof(lib), task=func, time=sample.time, evals=sample.evals)
    end
    return records
end

const x = :time => log10 => "log10(Time)"
const base_plt = mapping(x, color=:library) * visual(Hist)
Layer 
  transformation: AlgebraOfGraphics.Visual(Hist, {})
  data: Nothing
  positional:
    1: :time => (log10 => "log10(Time)")
  named:
    color: library

File open

Code
libs = (JLCDF, Pycdfpp, CDFlib)
result_open = run_benchmarks(files, libs, :load) |> DataFrame
36×5 DataFrame
11 rows omitted
Row file library task time evals
String Symbol Symbol Float64 Float64
1 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF load 1.30523e-5 4.0
2 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF load 1.30105e-5 4.0
3 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF load 1.32605e-5 4.0
4 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF load 1.31665e-5 4.0
5 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp load 4.38438e-5 4.0
6 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp load 8.9375e-5 4.0
7 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp load 8.23645e-5 4.0
8 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp load 5.77603e-5 4.0
9 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib load 3.87605e-5 4.0
10 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib load 3.83125e-5 4.0
11 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib load 3.84792e-5 4.0
12 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib load 3.8677e-5 4.0
13 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF load 1.34165e-5 4.0
25 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF load 1.32188e-5 4.0
26 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF load 1.31145e-5 4.0
27 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF load 1.30938e-5 4.0
28 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF load 1.29898e-5 4.0
29 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp load 4.29895e-5 4.0
30 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp load 8.74168e-5 4.0
31 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp load 8.16875e-5 4.0
32 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp load 5.67915e-5 4.0
33 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib load 3.82292e-5 4.0
34 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib load 3.8177e-5 4.0
35 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib load 3.83645e-5 4.0
36 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib load 3.86563e-5 4.0
Code
draw(data(result_open) * base_plt)

Variable listing

List variables names without requesting values.

Code
jl_res = JLCDF.list_variables(files[1])
cdfpp_res = pyconvert(Vector{String}, Pycdfpp.list_variables(files[1]))
cdflib_res = pyconvert(Vector{String}, CDFlib.list_variables(files[1]))
@assert jl_res == cdfpp_res
@assert jl_res == cdflib_res

result_list = run_benchmarks(files, libs, :list_variables; evals=4) |> DataFrame
36×5 DataFrame
11 rows omitted
Row file library task time evals
String Symbol Symbol Float64 Float64
1 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF list_variables 1.56148e-5 4.0
2 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF list_variables 3.0573e-5 4.0
3 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF list_variables 1.55728e-5 4.0
4 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF list_variables 1.43648e-5 4.0
5 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp list_variables 0.000391188 4.0
6 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp list_variables 0.000435938 4.0
7 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp list_variables 0.00044026 4.0
8 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp list_variables 0.000403771 4.0
9 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib list_variables 0.000292573 4.0
10 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib list_variables 0.000311042 4.0
11 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib list_variables 0.00040625 4.0
12 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib list_variables 0.000444688 4.0
13 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF list_variables 1.56668e-5 4.0
25 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF list_variables 1.56665e-5 4.0
26 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF list_variables 3.0552e-5 4.0
27 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF list_variables 1.53645e-5 4.0
28 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF list_variables 1.42813e-5 4.0
29 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp list_variables 0.000394115 4.0
30 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp list_variables 0.000440375 4.0
31 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp list_variables 0.000439417 4.0
32 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp list_variables 0.000407417 4.0
33 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib list_variables 0.000290969 4.0
34 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib list_variables 0.000313563 4.0
35 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib list_variables 0.000398938 4.0
36 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib list_variables 0.000452719 4.0
Code
draw(data(result_list) * base_plt)

Variable reading

We request the first variable values. Julia is column major, while CDFpp and CDFlib are row major (C++ and Python).

Code
jl_res = permutedims(JLCDF.get_var_data(files[1]), (2, 1))
cdfpp_res = PyArray(Pycdfpp.get_var_data(files[1]))
cdflib_res = PyArray(CDFlib.get_var_data(files[1]))
@assert jl_res[.!isnan.(jl_res)]  cdfpp_res[.!isnan.(cdfpp_res)]
@assert jl_res[.!isnan.(jl_res)]  cdflib_res[.!isnan.(cdflib_res)]

result_read = run_benchmarks(files, libs, :get_var_data; evals=2, n=4) |> DataFrame
48×5 DataFrame
23 rows omitted
Row file library task time evals
String Symbol Symbol Float64 Float64
1 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF get_var_data 0.00955642 2.0
2 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF get_var_data 0.00239421 2.0
3 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF get_var_data 1.85625e-5 2.0
4 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF get_var_data 0.0113477 2.0
5 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp get_var_data 0.0717563 2.0
6 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp get_var_data 0.00296454 2.0
7 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp get_var_data 0.000437375 2.0
8 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp get_var_data 0.0118374 2.0
9 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib get_var_data 0.137004 2.0
10 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib get_var_data 0.00778117 2.0
11 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib get_var_data 0.000434875 2.0
12 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib get_var_data 0.0296159 2.0
13 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF get_var_data 0.00943675 2.0
37 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF get_var_data 0.00938646 2.0
38 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF get_var_data 0.00238021 2.0
39 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF get_var_data 1.8208e-5 2.0
40 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF get_var_data 0.0111861 2.0
41 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp get_var_data 0.0715051 2.0
42 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp get_var_data 0.00295673 2.0
43 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp get_var_data 0.000433917 2.0
44 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp get_var_data 0.0115245 2.0
45 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib get_var_data 0.138544 2.0
46 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib get_var_data 0.00765619 2.0
47 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib get_var_data 0.000432104 2.0
48 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib get_var_data 0.0302381 2.0
Code
draw(data(result_read) * base_plt)

Full CDF file loading

We request all variables values.

Code
result_full = run_benchmarks(files, libs, :full_load; evals=2, n=2) |> DataFrame
24×5 DataFrame
Row file library task time evals
String Symbol Symbol Float64 Float64
1 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF full_load 0.0125854 2.0
2 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF full_load 0.121065 2.0
3 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF full_load 0.0643002 2.0
4 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF full_load 0.0866738 2.0
5 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp full_load 0.0807833 2.0
6 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp full_load 0.622828 2.0
7 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp full_load 0.448834 2.0
8 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp full_load 0.326105 2.0
9 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib full_load 0.984941 2.0
10 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib full_load 1.22249 2.0
11 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib full_load 0.795301 2.0
12 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib full_load 0.703445 2.0
13 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF full_load 0.0126343 2.0
14 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF full_load 0.12459 2.0
15 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF full_load 0.0614843 2.0
16 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF full_load 0.0767648 2.0
17 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp full_load 0.0800061 2.0
18 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp full_load 0.62036 2.0
19 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp full_load 0.443924 2.0
20 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp full_load 0.327757 2.0
21 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib full_load 0.958206 2.0
22 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib full_load 1.25364 2.0
23 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib full_load 0.823466 2.0
24 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib full_load 0.717578 2.0
Code
draw(data(result_full) * base_plt)

Summary

Code
result = vcat(result_open, result_list, result_read, result_full)
144×5 DataFrame
119 rows omitted
Row file library task time evals
String Symbol Symbol Float64 Float64
1 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF load 1.30523e-5 4.0
2 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF load 1.30105e-5 4.0
3 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF load 1.32605e-5 4.0
4 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF load 1.31665e-5 4.0
5 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp load 4.38438e-5 4.0
6 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp load 8.9375e-5 4.0
7 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp load 8.23645e-5 4.0
8 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp load 5.77603e-5 4.0
9 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib load 3.87605e-5 4.0
10 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib load 3.83125e-5 4.0
11 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib load 3.84792e-5 4.0
12 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib load 3.8677e-5 4.0
13 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF load 1.34165e-5 4.0
133 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf JLCDF full_load 0.0126343 2.0
134 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf JLCDF full_load 0.12459 2.0
135 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf JLCDF full_load 0.0614843 2.0
136 solo_l3_rpw-bia-efield_20220220_v03.cdf JLCDF full_load 0.0767648 2.0
137 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf Pycdfpp full_load 0.0800061 2.0
138 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf Pycdfpp full_load 0.62036 2.0
139 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf Pycdfpp full_load 0.443924 2.0
140 solo_l3_rpw-bia-efield_20220220_v03.cdf Pycdfpp full_load 0.327757 2.0
141 mms1_scm_srvy_l2_scsrvy_20190301_v2.2.0.cdf CDFlib full_load 0.958206 2.0
142 mms1_edp_fast_l2_dce_20221110_v3.1.0.cdf CDFlib full_load 1.25364 2.0
143 mms1_fpi_fast_l2_des-dist_20221103060000_v3.4.0.cdf CDFlib full_load 0.823466 2.0
144 solo_l3_rpw-bia-efield_20220220_v03.cdf CDFlib full_load 0.717578 2.0
Code
plt = data(result) * mapping(layout=:task) * base_plt
draw(plt; facet=(; linkxaxes=:none, linkyaxes=:none))

Reproducibility

Code
using Pkg
Pkg.status()
Status `~/src/juliaspacephysics.github.io/tutorials/cdf/Project.toml`
  [cbdf2221] AlgebraOfGraphics v0.11.8
  [13f3f980] CairoMakie v0.15.6
  [0ca39b1e] Chairmarks v1.3.1
  [a9737db6] CommonDataFormat v0.1.6 `~/.julia/dev/CommonDataFormat`
  [a93c6f00] DataFrames v1.8.1
  [6099a3de] PythonCall v0.9.28
Code
using InteractiveUtils # hide
versioninfo()
Julia Version 1.12.1
Commit ba1e628ee49 (2025-10-17 13:02 UTC)
Build Info:
  Official https://julialang.org release
Platform Info:
  OS: macOS (arm64-apple-darwin24.0.0)
  CPU: 12 × Apple M2 Max
  WORD_SIZE: 64
  LLVM: libLLVM-18.1.7 (ORCJIT, apple-m2)
  GC: Built with stock GC
Threads: 8 default, 1 interactive, 8 GC (on 8 virtual cores)
Environment:
  JULIA_PROJECT = @.
  JULIA_LOAD_PATH = @:@stdlib
Back to top