arviz-devs / ArviZ.jl
1
@doc doc"""
2
    with_interactive_backend(f; backend::Symbol = nothing)
3

4
Execute the thunk `f` in a temporary interactive context with the chosen `backend`, or
5
provide no arguments to use a default.
6

7
# Examples
8

9
```julia
10
idata = load_arviz_data("centered_eight")
11
plot_posterior(idata) # inline
12
with_interactive_backend() do
13
    plot_density(idata) # interactive
14
end
15
plot_trace(idata) # inline
16
```
17
"""
18
with_interactive_backend
19

20 0
function with_interactive_backend(f; backend=nothing)
21 0
    oldisint = PyPlot.isinteractive()
22 0
    oldgui = pygui()
23 0
    backend === nothing || pygui(Symbol(backend))
24 0
    pygui(true)
25 0
    ret = f()
26 0
    pygui(oldisint)
27 0
    pygui(oldgui)
28 0
    return ret
29
end
30

31
"""
32
    use_style(style::String)
33
    use_style(style::Vector{String})
34

35
Use matplotlib style settings from a style specification `style`.
36

37
The style name of "default" is reserved for reverting back to the default style settings.
38

39
ArviZ-specific styles are
40
`["arviz-whitegrid", "arviz-darkgrid", "arviz-colors", "arviz-white"]`.
41
To see all available style specifications, use [`styles()`](@ref).
42

43
If a `Vector` of styles is provided, they are applied from first to last.
44
"""
45 20
use_style(style) = plt.style.use(style)
46

47
"""
48
    styles() -> Vector{String}
49

50
Get all available matplotlib styles for use with [`use_style`](@ref)
51
"""
52 20
styles() = plt.style.available
53

54
"""
55
    convert_arguments(f, args...; kwargs...) -> NTuple{2}
56

57
Convert arguments to the function `f` before calling.
58

59
This function is used primarily for pre-processing arguments within macros before sending
60
to arviz.
61
"""
62 20
convert_arguments(::Any, args...; kwargs...) = args, kwargs
63

64
"""
65
    convert_result(f, result, args...)
66

67
Convert result of the function `f` before returning.
68

69
This function is used primarily for post-processing outputs of arviz before returning.
70
The `args` are primarily used for dispatch.
71
"""
72 20
convert_result(f, result, args...) = result
73

74 20
load_backend(backend) = nothing
75

76 0
function forwarddoc(f::Symbol)
77 0
    return "See documentation for [`arviz.$(f)`](https://arviz-devs.github.io/arviz/api/generated/arviz.$(f).html)."
78
end
79

80 0
forwardgetdoc(f::Symbol) = Docs.getdoc(getproperty(arviz, f))
81

82
"""
83
    @forwardfun f
84
    @forwardfun(f)
85

86
Wrap a function `arviz.f` in `f`, forwarding its docstrings.
87

88
Use [`convert_arguments`](@ref) and [`convert_result`](@ref) to customize what is passed to
89
and returned from `f`.
90
"""
91
macro forwardfun(f)
92
    fdoc = forwarddoc(f)
93
    return esc(
94
        quote
95
            @doc $fdoc $f
96

97
            function $(f)(args...; kwargs...)
98 20
                args, kwargs = convert_arguments($(f), args...; kwargs...)
99 20
                result = arviz.$(f)(args...; kwargs...)
100 20
                return convert_result($(f), result)
101
            end
102

103 0
            Docs.getdoc(::typeof($(f))) = forwardgetdoc(Symbol($(f)))
104
        end,
105
    )
106
end
107

108
"""
109
    @forwardplotfun f
110
    @forwardplotfun(f)
111

112
Wrap a plotting function `arviz.f` in `f`, forwarding its docstrings.
113

114
This macro also ensures that outputs for the different backends are correctly handled.
115
Use [`convert_arguments`](@ref) and [`convert_result`](@ref) to customize what is passed to
116
and returned from `f`.
117
"""
118
macro forwardplotfun(f)
119
    fdoc = forwarddoc(f)
120
    return esc(
121
        quote
122
            @doc $fdoc $f
123

124
            function $(f)(args...; backend=nothing, kwargs...)
125 20
                if backend === nothing
126 20
                    backend = get(rcParams, "plot.backend", nothing)
127
                end
128 20
                backend = Symbol(backend)
129 20
                backend_val = Val(backend)
130 20
                load_backend(backend_val)
131 20
                args, kwargs = convert_arguments($(f), args...; kwargs...)
132 20
                result = arviz.$(f)(args...; kwargs..., backend=backend)
133 20
                return convert_result($(f), result, backend_val)
134
            end
135

136 0
            Docs.getdoc(::typeof($(f))) = forwardgetdoc(Symbol($(f)))
137
        end,
138
    )
139
end
140

141
# Replace `missing` values with `NaN` and do type inference on the result
142 20
replacemissing(x) = map(identity, replace(x, missing => NaN))
143 20
replacemissing(x::AbstractArray{<:AbstractArray}) = map(replacemissing, x)
144 20
@inline replacemissing(x::AbstractArray{<:Real}) = x
145 20
@inline replacemissing(x::Missing) = NaN
146 20
@inline replacemissing(x::Number) = x
147

148
# Convert python types to Julia types if possible
149 20
@inline frompytype(x) = x
150 20
@inline frompytype(x::PyObject) = PyAny(x)
151 20
frompytype(x::AbstractArray{PyObject}) = map(frompytype, x)
152 20
frompytype(x::AbstractArray{Any}) = map(frompytype, x)
153 20
frompytype(x::AbstractArray{<:AbstractArray}) = map(frompytype, x)
154

155
function rekey(d, keymap)
156 20
    dnew = empty(d)
157 20
    for (k, v) in d
158 20
        knew = get(keymap, k, k)
159 20
        haskey(dnew, knew) && throw(ArgumentError("$knew in `keymap` is already in `d`."))
160 20
        dnew[knew] = d[k]
161
    end
162 20
    return dnew
163
end
164

165 20
removekeys!(dict, keys) = map(k -> delete!(dict, k), keys)
166

167
function popsubdict!(dict, names)
168 20
    (dict === nothing || names === nothing) && return nothing
169 20
    subdict = empty(dict)
170 20
    for k in names
171 20
        subdict[k] = pop!(dict, k)
172
    end
173 20
    return subdict
174
end
175 0
popsubdict!(dict, key::String) = popsubdict!(dict, [key])
176

177 0
snakecase(s) = replace(lowercase(s), " " => "_")
178

179 0
@inline _asarray(x) = [x]
180 20
@inline _asarray(x::AbstractArray) = x
181

182 20
_asstringkeydict(x) = Dict(String(k) => v for (k, v) in pairs(x))
183 20
_asstringkeydict(x::Dict{String}) = x
184 20
_asstringkeydict(::Nothing) = Dict{String,Any}()
185

186
function enforce_stat_types(dict)
187 20
    return Dict(k => get(sample_stats_types, k, eltype(v)).(v) for (k, v) in dict)
188
end
189 20
enforce_stat_types(::Nothing) = nothing
190

191
"""
192
    todataframes(df; index_name = nothing) -> DataFrames.DataFrame
193

194
Convert a Python `pandas.DataFrame` or `pandas.Series` into a `DataFrames.DataFrame`.
195

196
If `index_name` is not `nothing`, the index is converted into a column with `index_name`.
197
Otherwise, it is discarded.
198
"""
199
function todataframes(::Val{:DataFrame}, df::PyObject; index_name=nothing)
200 20
    initialize_pandas()
201 20
    col_vals = map(df.columns) do name
202 20
        series = py"$(df)[$(name)]"
203 20
        vals = series.values
204 20
        return Symbol(name) => frompytype(vals)
205
    end
206 20
    if index_name !== nothing
207 20
        index_vals = frompytype(df.index.values)
208 20
        col_vals = [Symbol(index_name) => index_vals; col_vals]
209
    end
210 20
    return DataFrames.DataFrame(col_vals)
211
end
212
function todataframes(::Val{:Series}, series::PyObject; kwargs...)
213 20
    initialize_pandas()
214 20
    colnames = map(i -> Symbol(frompytype(i)), series.index)
215 20
    colvals = map(x -> [frompytype(x)], series.values)
216 20
    return DataFrames.DataFrame(colvals, colnames)
217
end
218
function todataframes(df::PyObject; kwargs...)
219 20
    initialize_pandas()
220 20
    if pyisinstance(df, pandas.Series)
221 20
        return todataframes(Val(:Series), df; kwargs...)
222
    end
223 20
    return todataframes(Val(:DataFrame), df; kwargs...)
224
end
225

226
"""
227
    topandas(::Type{:DataFrame}, df; index_name = nothing) -> PyObject
228
    topandas(::Type{:Series}, df) -> PyObject
229
    topandas(::Val{:ELPDData}, df) -> PyObject
230

231
Convert a `DataFrames.DataFrame` to the specified pandas type.
232

233
If `index_name` is not `nothing`, the corresponding column is made the index of the
234
returned dataframe.
235
"""
236
function topandas(::Val{:DataFrame}, df; index_name=nothing)
237 20
    initialize_pandas()
238 20
    df = DataFrames.DataFrame(df)
239 20
    colnames = names(df)
240 20
    rowvals = map(Array, eachrow(df))
241 20
    pdf = pandas.DataFrame(rowvals; columns=colnames)
242 20
    index_name !== nothing && pdf.set_index(index_name; inplace=true)
243 20
    return pdf
244
end
245
function topandas(::Val{:Series}, df)
246 20
    initialize_pandas()
247 20
    df = DataFrames.DataFrame(df)
248 20
    rownames = names(df)
249 20
    colvals = Array(first(eachrow(df)))
250 20
    return pandas.Series(colvals, rownames)
251
end
252
function topandas(::Val{:ELPDData}, df)
253 20
    initialize_pandas()
254 20
    df = DataFrames.DataFrame(df)
255 20
    rownames = names(df)
256 20
    colvals = Array(first(eachrow(df)))
257 20
    return ArviZ.arviz.stats.ELPDData(colvals, rownames)
258
end

Read our documentation on viewing source code .

Loading