Skip to content

Commit 4c7afc9

Browse files
committed
add DataFrames extension
1 parent 6f8f9ee commit 4c7afc9

6 files changed

+126
-3
lines changed

Project.toml

+2
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
3737
[weakdeps]
3838
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
3939
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
40+
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
4041
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
4142
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
4243
SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
4344
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
4445

4546
[extensions]
4647
NetworkDynamicsCUDAExt = ["CUDA", "Adapt"]
48+
NetworkDynamicsDataFramesExt = ["DataFrames"]
4749
NetworkDynamicsMTKExt = ["ModelingToolkit", "SymbolicUtils", "Symbolics"]
4850
NetworkDynamicsSymbolicsExt = ["Symbolics", "MacroTools"]
4951

ext/NetworkDynamicsDataFramesExt.jl

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
module NetworkDynamicsDataFramesExt
2+
3+
using NetworkDynamics: NetworkDynamics, Network
4+
using DataFrames: DataFrames, DataFrame
5+
using OrderedCollections: OrderedDict
6+
7+
function _df_from_list(list, f)
8+
df = DataFrame()
9+
for (i, v) in list
10+
row = OrderedDict{Symbol,Any}()
11+
row[:idx] = i
12+
for sym in f(v)
13+
if NetworkDynamics.has_default_or_init(v, sym)
14+
row[sym] = NetworkDynamics.get_default_or_init(v, sym)
15+
else
16+
row[sym] = missing
17+
end
18+
end
19+
push!(df, NamedTuple(row); cols=:union)
20+
end
21+
df
22+
end
23+
function _df_from_pair(list, pair)
24+
key, f = pair
25+
df = DataFrame()
26+
for (i, v) in list
27+
row = OrderedDict{Symbol,Any}(:idx => i, key => f(v))
28+
push!(df, NamedTuple(row); cols=:union)
29+
end
30+
df
31+
end
32+
33+
function NetworkDynamics.describe_vertices(nw::Network, extras...; parameters=true, states=true, batch=nothing)
34+
pairs = enumerate(nw.im.vertexm);
35+
batches = map(idx -> findfirst(batch -> idx batch.indices, nw.vertexbatches), first.(pairs))
36+
37+
if !isnothing(batch)
38+
idxs = findall(b -> b batch, batches)
39+
pairs = collect(pairs)[idxs]
40+
batch = collect(batches)[idxs]
41+
end
42+
isempty(pairs) && return DataFrame()
43+
44+
basedf = DataFrame(
45+
idx = first.(pairs),
46+
name = map(v->last(v).name, pairs),
47+
batch = map(idx -> findfirst(batch -> idx batch.indices, nw.vertexbatches), first.(pairs)),
48+
)
49+
50+
dfs = [basedf,]
51+
if parameters
52+
push!(dfs, _df_from_list(pairs, NetworkDynamics.psym))
53+
end
54+
if states
55+
push!(dfs, _df_from_list(pairs, NetworkDynamics.sym))
56+
end
57+
for p in extras
58+
push!(dfs, _df_from_pair(pairs, p))
59+
end
60+
61+
foldl((a,b) -> DataFrames.leftjoin(a,b; on=:idx), dfs)
62+
end
63+
64+
function NetworkDynamics.describe_edges(nw::Network, extras...; parameters=true, states=true, batch=nothing)
65+
pairs = enumerate(nw.im.edgem);
66+
batches = map(idx -> findfirst(batch -> idx batch.indices, nw.layer.edgebatches), first.(pairs))
67+
68+
if !isnothing(batch)
69+
idxs = findall(b -> b batch, batches)
70+
pairs = collect(pairs)[idxs]
71+
batch = collect(batches)[idxs]
72+
end
73+
isempty(pairs) && return DataFrame()
74+
75+
basedf = DataFrame(
76+
idx = first.(pairs),
77+
srcdst = map(idx -> nw.im.edgevec[idx].src => nw.im.edgevec[idx].dst, first.(pairs)),
78+
name = map(v->last(v).name, pairs),
79+
batch = map(idx -> findfirst(batch -> idx batch.indices, nw.vertexbatches), first.(pairs)),
80+
)
81+
82+
dfs = [basedf,]
83+
if parameters
84+
push!(dfs, _df_from_list(pairs, NetworkDynamics.psym))
85+
end
86+
if states
87+
push!(dfs, _df_from_list(pairs, NetworkDynamics.sym))
88+
end
89+
for p in extras
90+
push!(dfs, _df_from_pair(pairs, p))
91+
end
92+
93+
foldl((a,b) -> DataFrames.leftjoin(a,b; on=:idx), dfs)
94+
end
95+
96+
end

ext/NetworkDynamicsMTKExt.jl

+6-2
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,12 @@ function _get_metadata(sys, name)
238238
if def isa Symbolic
239239
def = fixpoint_sub(def, alldefaults)
240240
end
241-
def isa Symbolic && error("Could not resolve default $(ModelingToolkit.getdefault(sym)) for $name")
242-
nt = (; nt..., default=def)
241+
242+
if def isa Symbolic
243+
@warn "Could not resolve default term $(ModelingToolkit.getdefault(sym)) for $name, leave free."
244+
else
245+
nt = (; nt..., default=def)
246+
end
243247
end
244248

245249
# check for guess both in symbol metadata and in guesses of system

src/NetworkDynamics.jl

+17-1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ include("doctor.jl")
101101
export load_network
102102
include("importexport.jl")
103103

104+
export describe_vertices, describe_edges
105+
function describe_vertices end
106+
function describe_edges end
104107
#=
105108
using StyledStrings
106109
s1 = styled"{bright_red:brred} {bright_green:brgreen} {bright_yellow:bryellow} {bright_blue:brblue} {bright_magenta:brmagenta} {bright_cyan:brcyan} {bright_black:brblack} {bright_white:brwhite}";
@@ -119,7 +122,20 @@ const ND_FACES = [
119122
:NetworkDynamics_fftype => StyledStrings.Face(foreground=:bright_blue),
120123
]
121124

122-
__init__() = foreach(StyledStrings.addface!, ND_FACES)
125+
function __init__()
126+
if isdefined(Base.Experimental, :register_error_hint)
127+
Base.Experimental.register_error_hint(MethodError) do io, exc, argtypes, kwargs
128+
if exc.f (describe_vertices, describe_edges)
129+
ext = Base.get_extension(NetworkDynamics, :NetworkDynamicsDataFramesExt)
130+
if isnothing(ext)
131+
printstyled(io, "\nLoad `DataFrames` in order to use `describe_vertices` and `describe_edges`."; bold=true)
132+
end
133+
end
134+
end
135+
end
136+
137+
foreach(StyledStrings.addface!, ND_FACES)
138+
end
123139

124140
function reloadfaces!()
125141
StyledStrings.resetfaces!()

src/metadata.jl

+4
Original file line numberDiff line numberDiff line change
@@ -551,3 +551,7 @@ function _has_changed_hash(aliased_cfs)
551551
end
552552
changed
553553
end
554+
555+
556+
function describe_vertices end
557+
function describe_edges end

test/Project.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Bonito = "824d6782-a2ef-11e9-3a09-e5662e0c26f8"
77
CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba"
88
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
99
Chairmarks = "0ca39b1e-fe0b-4e98-acfc-b1656634c4de"
10+
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
1011
DataInterpolations = "82cc6244-b520-54b8-b5a6-8a565e85f1d0"
1112
DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab"
1213
DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def"

0 commit comments

Comments
 (0)