Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,26 @@ using ASDF

af = load("jwst.asdf"; extensions = true)
jwst.asdf
├─ asdf_library::String
├─ asdf_library::TaggedMapping
│ ├─ author::String | The ASDF Developers
│ ├─ homepage::String | http://github.com/asdf-format/asdf
│ ├─ name::String | asdf
│ └─ version::String | 3.2.0
├─ history::String
│ └─ extensions::Vector{OrderedCollections.OrderedDict{Any, Any}} | shape = (6,)
├─ history::OrderedDict
│ └─ extensions::Vector{TaggedMapping} | shape = (6,)
├─ _fits_hash::String | 93cf4256596bd7a6d20913c3d0f6e1ab9d3a8647c02771c5c752b2311efd9456
├─ data::ASDF.NDArray | shape = [4159, 6353]
└─ meta::String
├─ aperture::String
├─ data::NDArray | shape = [4159, 6353], datatype = Float32
└─ meta::OrderedDict
├─ aperture::OrderedDict
│ ├─ name::String | NRCA5_FULL
│ ├─ position_angle::Float64 | 251.53592358473648
│ └─ pps_name::String | NRCALL_FULL
├─ asn::String
├─ asn::OrderedDict
│ ├─ exptype::String | science
│ ├─ pool_name::String | jw01611_20240910t150659_pool.csv
│ └─ table_name::String | jw01611-o002_20240910t150659_image3_00001_asn.json
├─ background::String
⋮ (320) more rows
├─ background::OrderedDict
⋮ (325) more rows
```

```julia
Expand Down
1 change: 1 addition & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ AWS = "fbe9abb3-538b-5e4e-ba9e-bc94f4f92ebc"
AWSS3 = "1c724243-ef5b-51ab-93f4-b0a88ac62a95"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656"
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"

Expand Down
8 changes: 7 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using ASDF
using Documenter
using Documenter, DocumenterInterLinks
using Documenter.Remotes: GitHub

links = InterLinks(
"PythonCall" => "https://juliapy.github.io/PythonCall.jl/stable/",
)

makedocs(;
modules = [ASDF],
authors = "Erik Schnetter",
Expand All @@ -17,9 +21,11 @@ makedocs(;
"JWST" => "examples/jwst.md",
"Roman" => "examples/roman.md",
],
"Interoperability" => "interop.md",
"API" => "api.md",
],
doctest = false,
plugins = [links],
)

deploydocs(;
Expand Down
137 changes: 137 additions & 0 deletions docs/src/interop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Interoperability

The [PythonCall.jl](https://juliapy.github.io/PythonCall.jl/stable/) package makes writing and reading ASDF files from the Python implementation of ASDF fairly seamless. For example, here is one way we might reproduce the [Creating Files](https://www.asdf-format.org/projects/asdf/en/latest/asdf/overview.html#creating-files) section from the Python `asdf` documentation without leaving our Julia session:

## Accessing the IPython REPL from Julia

We start by creating a fresh [Julia environment](https://pkgdocs.julialang.org/v1/environments/) named `asdf` in a global location:

```shell
julia --proj=@asdf # Or --proj=<path to a custom location>
```

!!! tip
To verify that this is a blank environment and to also display its location, run the `st` command (short for `status`) from the package REPL:

```julia-repl
julia> # Press ] to enter the package mode REPL
(@asdf) pkg> st
Status `~/.julia/environments/asdf/Project.toml` (empty project)
```

We next install whichever Python packages we may need for our analysis, e.g., `asdf` and `astropy`. PythonCall.jl exports [CondaPkg.jl](https://github.com/JuliaPy/CondaPkg.jl), which has nice hooks for accomplishing this:

```julia-repl
(@asdf) pkg> add PythonCall

julia> using PythonCall

(@asdf) pkg> conda add asdf astropy

(@asdf) pkg> conda st
CondaPkg Status <path to your julia environment>/CondaPkg.toml
Environment
<path to your julia environment>/.CondaPkg/.pixi/envs/default
Packages
asdf v5.3.0
astropy v7.2.0

(@asdf) pkg> conda run ipython
```

The last command (`conda run ipython`) starts an IPython REPL provided in the `astropy` installation directly from Julia. We can then enter regular Python syntax verbatim to create a sample ASDF file called `example.asdf`:

```python
from asdf import AsdfFile
import numpy as np

# Create some data
sequence = np.arange(100)
squares = sequence**2
random = np.random.random(100)

# Store the data in an arbitrarily nested dictionary
tree = {
"foo": 42,
"name": "Monty",
"sequence": sequence,
"powers": {"squares": squares},
"random": random,
}

# Create the ASDF file object from our data tree
af = AsdfFile(tree)

# Write the data to a new file
af.write_to("example.asdf")
```

!!! note
IPython does not come with PythonCall.jl/CondaPkg.jl by default. If working with packages other than `astropy` that do not bundle `ipython`, use `conda run python` instead.

## Julia REPL

PythonCall.jl also makes it easy to run Python syntax directly from the Julia REPL. For example, the above IPython commands could also be run directly using the [`PythonCall.@pyexec`](@extref) macro:

```shell
julia --proj=@asdf # Re-use the environment created earlier
```

```julia
using PythonCall

@pyexec """
from asdf import AsdfFile
import numpy as np

# Create some data
sequence = np.arange(100)
squares = sequence**2
random = np.random.random(100)

# Store the data in an arbitrarily nested dictionary
tree = {
"foo": 42,
"name": "Monty",
"sequence": sequence,
"powers": {"squares": squares},
"random": random,
}

# Create the ASDF file object from our data tree
af = AsdfFile(tree)

# Write the data to a new file
af.write_to("example.asdf")
"""
```

The [`PythonCall.@py`](@extref) macro reduces the barrier between Python and Julia even further by allowing us to work with Python objects directly using Julia syntax:

```julia
@py begin
import asdf: AsdfFile # Julia syntax version of `from asdf import AsdfFile`
import numpy as np
end

sequence = np.arange(100)

squares = sequence^2 # Note that Julia uses `^` instead of `**`

random = np.random.random(100)

# Create a Python dict with PythonCall.pydict
tree = pydict(
"foo" => 42,
"name" => "Monty",
"sequence" => sequence,
"powers" => pydict("squares" => squares),
"random" => random,
);

af = AsdfFile(tree)

af.write_to("example.asdf")
```

See the [PythonCall.jl documentation](https://juliapy.github.io/PythonCall.jl/stable/) for more.
42 changes: 16 additions & 26 deletions docs/src/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The saved file contains the following human-readable contents:
```jldoctest intro
julia> read("intro.asdf", String) |> print
#ASDF 1.0.0
#ASDF_STANDARD 1.2.0
#ASDF_STANDARD 1.6.0
# This is an ASDF file <https://asdf-standard.readthedocs.io/>
%YAML 1.1
%TAG ! tag:stsci.edu:asdf/
Expand All @@ -60,17 +60,12 @@ The saved file contains the following human-readable contents:
- 1.0
- 2.0
- 3.0
asdf/library: !core/software-1.0.0
asdf_library: !core/software-1.0.0
name: "ASDF.jl"
author: "Erik Schnetter <schnetter@gmail.com>"
homepage: "https://github.com/JuliaAstro/ASDF.jl"
version: "2.0.0"
...
#ASDF BLOCK INDEX
%YAML 1.1
---
[]
...
```

which can be loaded back with FileIO.jl's generic [`load`](@ref) function:
Expand All @@ -80,13 +75,13 @@ julia> af = load("intro.asdf")
intro.asdf
├─ field_1::Vector{Int64} | shape = (4,)
├─ field_2::Vector{String} | shape = (4,)
├─ field_3::String
├─ field_3::OrderedDict
│ ├─ field_3a::Vector{String} | shape = (3,)
│ └─ field_3b::Vector{Float64} | shape = (3,)
└─ asdf/library::String
└─ asdf_library::TaggedMapping
├─ name::String | ASDF.jl
├─ author::String | Erik Schnetter <schnetter@gmail.com>
├─ homepage::String | https://github.com/JuliaAstro/ASDF.jl
├─ name::String | ASDF.jl
└─ version::String | 2.0.0
```

Expand All @@ -100,7 +95,7 @@ intro.asdf
⋮ (8) more rows
```

It contains a `metadata` field, which is a new dictionary that merges information about this library (stored under the `asdf/library` key) with the original user-defined `af_payload` dictionary. For convenience, `af.metadata[<key>]` can be accessed directly as `af[key]`. Since the underlying data is a dictionary, it can be modified in the standard way:
It contains a `metadata` field, which is a new dictionary that merges information about this library (stored under the `asdf_library` key) with the original user-defined `af_payload` dictionary. For convenience, `af.metadata[<key>]` can be accessed directly as `af[key]`. Since the underlying data is a dictionary, it can be modified in the standard way:

```jldoctest intro
julia> af["field_1"] = [50, 60, 70, 80];
Expand All @@ -123,7 +118,7 @@ julia> save("intro_modified.asdf", af)
```jldoctest intro
julia> read("intro_modified.asdf", String) |> print
#ASDF 1.0.0
#ASDF_STANDARD 1.2.0
#ASDF_STANDARD 1.6.0
# This is an ASDF file <https://asdf-standard.readthedocs.io/>
%YAML 1.1
%TAG ! tag:stsci.edu:asdf/
Expand All @@ -148,17 +143,12 @@ julia> save("intro_modified.asdf", af)
- 1.0
- 2.0
- 3.0
asdf/library: !core/software-1.0.0
asdf_library: !core/software-1.0.0
name: "ASDF.jl"
author: "Erik Schnetter <schnetter@gmail.com>"
homepage: "https://github.com/JuliaAstro/ASDF.jl"
version: "2.0.0"
...
#ASDF BLOCK INDEX
%YAML 1.1
---
[]
...
```

## Array storage
Expand All @@ -172,22 +162,22 @@ julia> save("intro_compressed.asdf", af_payload)

julia> af = load("intro_compressed.asdf")
intro_compressed.asdf
├─ meta::String
│ └─ my::String
├─ meta::OrderedDict
│ └─ my::OrderedDict
│ └─ nested::String | metadata
├─ data::ASDF.NDArray | shape = [4]
└─ asdf/library::String
├─ data::NDArray | shape = [4], datatype = Int64
└─ asdf_library::TaggedMapping
├─ name::String | ASDF.jl
├─ author::String | Erik Schnetter <schnetter@gmail.com>
├─ homepage::String | https://github.com/JuliaAstro/ASDF.jl
├─ name::String | ASDF.jl
└─ version::String | 2.0.0
```

!!! details "View file"
```julia-repl
julia> read("intro_compressed.asdf", String) |> print
#ASDF 1.0.0
#ASDF_STANDARD 1.2.0
#ASDF_STANDARD 1.6.0
# This is an ASDF file <https://asdf-standard.readthedocs.io/>
%YAML 1.1
%TAG ! tag:stsci.edu:asdf/
Expand All @@ -196,13 +186,13 @@ intro_compressed.asdf
meta:
my:
nested: "metadata"
data: !core/ndarray-1.0.0
data: !core/ndarray-1.1.0
source: 0
shape:
- 4
datatype: "int64"
byteorder: "little"
asdf/library: !core/software-1.0.0
asdf_library: !core/software-1.0.0
name: "ASDF.jl"
author: "Erik Schnetter <schnetter@gmail.com>"
homepage: "https://github.com/JuliaAstro/ASDF.jl"
Expand Down
Loading
Loading