Skip to content

Commit 0472712

Browse files
committed
Refactor bang plots to store call data
1 parent 19dfc3e commit 0472712

File tree

1 file changed

+75
-174
lines changed

1 file changed

+75
-174
lines changed

src/plotting.jl

Lines changed: 75 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,31 @@ Renaming and reexport of Plot.jl function `plotlyjs()` to define PlotlyJS.jl as
1818
"""
1919
plotlyjs_backend = StatsPlots.plotlyjs
2020

21-
const _LAST_PLOTS = Ref{Any}(nothing)
21+
struct _IRFMemory
22+
args::Tuple
23+
kwargs::Dict{Symbol,Any}
24+
end
25+
26+
const _IRF_HISTORY = Vector{_IRFMemory}()
27+
28+
struct _SolutionMemory
29+
args::Tuple
30+
kwargs::Dict{Symbol,Any}
31+
end
2232

23-
_store_last_plots!(p) = (_LAST_PLOTS[] = p)
33+
const _SOLUTION_HISTORY = Vector{_SolutionMemory}()
34+
35+
_merge_plot_vectors_by_title(dest::Vector, src::Vector) = begin
36+
result = copy(dest)
37+
for i in 1:length(src)
38+
if i <= length(result)
39+
result[i] = _merge_plots_by_title(result[i], src[i])
40+
else
41+
push!(result, src[i])
42+
end
43+
end
44+
result
45+
end
2446

2547

2648

@@ -412,7 +434,6 @@ function plot_model_estimates(𝓂::ℳ,
412434
end
413435
end
414436

415-
_store_last_plots!(return_plots)
416437
return return_plots
417438
end
418439

@@ -890,8 +911,6 @@ function plot_irf(𝓂::ℳ;
890911
label_done = false
891912
end
892913
end
893-
_store_last_plots!(return_plots)
894-
895914
return return_plots
896915
end
897916

@@ -1132,8 +1151,6 @@ function plot_conditional_variance_decomposition(𝓂::ℳ;
11321151
StatsPlots.savefig(p, save_plots_path * "/fevd__" * 𝓂.model_name * "__" * string(pane) * "." * string(save_plots_format))
11331152
end
11341153
end
1135-
_store_last_plots!(return_plots)
1136-
11371154
return return_plots
11381155
end
11391156

@@ -1504,7 +1521,6 @@ function plot_solution(𝓂::ℳ,
15041521
end
15051522
end
15061523

1507-
_store_last_plots!(return_plots)
15081524
return return_plots
15091525
end
15101526

@@ -1877,23 +1893,18 @@ function plot_conditional_forecast(𝓂::ℳ,
18771893
StatsPlots.savefig(p, save_plots_path * "/conditional_forecast__" * 𝓂.model_name * "__" * string(pane) * "." * string(save_plots_format))
18781894
end
18791895
end
1880-
_store_last_plots!(return_plots)
1881-
18821896
return return_plots
18831897

18841898
end
18851899

18861900
"""
1887-
plot_irf!(p, args...; kwargs...)
1901+
plot_irf!(args...; kwargs...)
18881902
1889-
Add the IRFs produced by [`plot_irf`](@ref) to the existing plot or vector of
1890-
plots `p` using `StatsPlots.plot!`.
1891-
1892-
Calling `plot_irf!(args...; kwargs...)` without providing `p` attempts to add
1893-
the lines to the previous plot. Additional pages are appended if required and
1894-
legend labels are derived from the `line_label` keyword. Subplots are matched by title when
1895-
merging so the order of variables does not matter. Titles from both plots are
1896-
collected, combined into a sorted list and used to align the panels.
1903+
Overlay the IRFs produced by successive calls. Each invocation stores the
1904+
supplied arguments and reproduces all previous IRF plots from scratch,
1905+
combining them with the new results. The combined plots are returned and, if
1906+
`show_plots = true`, displayed. Saving is controlled by the usual keyword
1907+
arguments.
18971908
"""
18981909
function _merge_plots_by_title(dest::StatsPlots.Plots.Plot, src::StatsPlots.Plots.Plot)
18991910
dest_titles = [string(dest[i][:title]) for i in 1:length(dest)]
@@ -1919,187 +1930,77 @@ function _merge_plots_by_title(dest::StatsPlots.Plots.Plot, src::StatsPlots.Plot
19191930
return merged
19201931
end
19211932

1922-
function plot_irf!(p::Union{StatsPlots.Plots.Plot,AbstractVector}, args...; kwargs...)
1923-
q = plot_irf(args...; kwargs..., show_plots = false, save_plots = false)
1924-
if isa(p, AbstractVector)
1925-
for i in 1:length(q)
1926-
if i <= length(p)
1927-
p[i] = _merge_plots_by_title(p[i], q[i])
1928-
else
1929-
push!(p, q[i])
1930-
end
1931-
end
1932-
else
1933-
p = _merge_plots_by_title(p, q[1])
1934-
end
1935-
_store_last_plots!(p)
1936-
return p
1937-
end
19381933
function plot_irf!(args...; kwargs...)
1939-
p = _LAST_PLOTS[]
1940-
if p === nothing
1941-
p = try
1942-
StatsPlots.current()
1943-
catch
1944-
nothing
1934+
push!(_IRF_HISTORY, _IRFMemory(args, Dict{Symbol,Any}(kwargs)))
1935+
plots_list = [plot_irf(m.args...; m.kwargs..., show_plots = false, save_plots = false) for m in _IRF_HISTORY]
1936+
combined = reduce(_merge_plot_vectors_by_title, plots_list)
1937+
if get(kwargs, :show_plots, true)
1938+
for p in combined
1939+
display(p)
19451940
end
19461941
end
1947-
if p === nothing
1948-
return plot_irf(args...; kwargs...)
1949-
else
1950-
return plot_irf!(p, args...; kwargs...)
1942+
if get(kwargs, :save_plots, false)
1943+
fmt = get(kwargs, :save_plots_format, :pdf)
1944+
path = get(kwargs, :save_plots_path, ".")
1945+
for (i,p) in enumerate(combined)
1946+
StatsPlots.savefig(p, joinpath(path, "irf__" * string(i) * "." * string(fmt)))
1947+
end
19511948
end
1949+
return combined
19521950
end
19531951

19541952
"""
1955-
plot_model_estimates!(p, args...; kwargs...)
1953+
plot_model_estimates!(args...; kwargs...)
19561954
1957-
Add the plots produced by [`plot_model_estimates`](@ref) to `p`.
1958-
1959-
If called without an existing plot, the results are added to the current plot if
1960-
one exists.
1955+
Convenience wrapper calling [`plot_model_estimates`](@ref). The bang-version no
1956+
longer attempts to modify the previously displayed plot.
19611957
"""
1962-
function plot_model_estimates!(p::Union{StatsPlots.Plots.Plot,AbstractVector}, args...; kwargs...)
1963-
q = plot_model_estimates(args...; kwargs..., show_plots = false, save_plots = false)
1964-
if isa(p, AbstractVector)
1965-
@assert length(p) == length(q) "Number of plots must match."
1966-
for (pi, qi) in zip(p, q)
1967-
StatsPlots.plot!(pi, qi)
1968-
end
1969-
else
1970-
StatsPlots.plot!(p, q[1])
1971-
end
1972-
_store_last_plots!(p)
1973-
return p
1974-
end
1975-
1976-
function plot_model_estimates!(args...; kwargs...)
1977-
p = _LAST_PLOTS[]
1978-
if p === nothing
1979-
p = try
1980-
StatsPlots.current()
1981-
catch
1982-
nothing
1983-
end
1984-
end
1985-
if p === nothing
1986-
return plot_model_estimates(args...; kwargs...)
1987-
else
1988-
return plot_model_estimates!(p, args...; kwargs...)
1989-
end
1990-
end
1958+
plot_model_estimates!(args...; kwargs...) =
1959+
plot_model_estimates(args...; kwargs...)
19911960

19921961
"""
1993-
plot_conditional_variance_decomposition!(p, args...; kwargs...)
1994-
1995-
Add the variance decomposition produced by
1996-
[`plot_conditional_variance_decomposition`](@ref) to `p`.
1962+
plot_conditional_variance_decomposition!(args...; kwargs...)
19971963
1998-
When called without providing a plot `p`, the decomposition is added to the
1999-
current plot if available.
1964+
Wrapper around [`plot_conditional_variance_decomposition`](@ref). The bang
1965+
version simply delegates to the non-bang function.
20001966
"""
2001-
function plot_conditional_variance_decomposition!(p::Union{StatsPlots.Plots.Plot,AbstractVector}, args...; kwargs...)
2002-
q = plot_conditional_variance_decomposition(args...; kwargs..., show_plots = false, save_plots = false)
2003-
if isa(p, AbstractVector)
2004-
@assert length(p) == length(q) "Number of plots must match."
2005-
for (pi, qi) in zip(p, q)
2006-
StatsPlots.plot!(pi, qi)
2007-
end
2008-
else
2009-
StatsPlots.plot!(p, q[1])
2010-
end
2011-
_store_last_plots!(p)
2012-
return p
2013-
end
2014-
2015-
function plot_conditional_variance_decomposition!(args...; kwargs...)
2016-
p = _LAST_PLOTS[]
2017-
if p === nothing
2018-
p = try
2019-
StatsPlots.current()
2020-
catch
2021-
nothing
2022-
end
2023-
end
2024-
if p === nothing
2025-
return plot_conditional_variance_decomposition(args...; kwargs...)
2026-
else
2027-
return plot_conditional_variance_decomposition!(p, args...; kwargs...)
2028-
end
2029-
end
1967+
plot_conditional_variance_decomposition!(args...; kwargs...) =
1968+
plot_conditional_variance_decomposition(args...; kwargs...)
20301969

20311970
"""
2032-
plot_solution!(p, args...; kwargs...)
1971+
plot_solution!(args...; kwargs...)
20331972
2034-
Add the solution plots produced by [`plot_solution`](@ref) to `p`.
2035-
If `p` is omitted, the lines are added to the current plot if one exists.
1973+
Recreate the solution plot by combining data from all previous calls. The
1974+
stored arguments are reapplied and the resulting plots merged so each variable
1975+
panel contains a line for every invocation.
20361976
"""
2037-
function plot_solution!(p::Union{StatsPlots.Plots.Plot,AbstractVector}, args...; kwargs...)
2038-
q = plot_solution(args...; kwargs..., show_plots = false, save_plots = false)
2039-
if isa(p, AbstractVector)
2040-
@assert length(p) == length(q) "Number of plots must match."
2041-
for (pi, qi) in zip(p, q)
2042-
StatsPlots.plot!(pi, qi)
2043-
end
2044-
else
2045-
StatsPlots.plot!(p, q[1])
2046-
end
2047-
_store_last_plots!(p)
2048-
return p
2049-
end
2050-
20511977
function plot_solution!(args...; kwargs...)
2052-
p = _LAST_PLOTS[]
2053-
if p === nothing
2054-
p = try
2055-
StatsPlots.current()
2056-
catch
2057-
nothing
1978+
push!(_SOLUTION_HISTORY, _SolutionMemory(args, Dict{Symbol,Any}(kwargs)))
1979+
plots_list = [plot_solution(m.args...; m.kwargs..., show_plots = false, save_plots = false) for m in _SOLUTION_HISTORY]
1980+
combined = reduce(_merge_plot_vectors_by_title, plots_list)
1981+
if get(kwargs, :show_plots, true)
1982+
for p in combined
1983+
display(p)
20581984
end
20591985
end
2060-
if p === nothing
2061-
return plot_solution(args...; kwargs...)
2062-
else
2063-
return plot_solution!(p, args...; kwargs...)
1986+
if get(kwargs, :save_plots, false)
1987+
fmt = get(kwargs, :save_plots_format, :pdf)
1988+
path = get(kwargs, :save_plots_path, ".")
1989+
for (i,p) in enumerate(combined)
1990+
StatsPlots.savefig(p, joinpath(path, "solution__" * string(i) * "." * string(fmt)))
1991+
end
20641992
end
1993+
return combined
20651994
end
20661995

20671996
"""
2068-
plot_conditional_forecast!(p, args...; kwargs...)
1997+
plot_conditional_forecast!(args...; kwargs...)
20691998
2070-
Add the conditional forecast produced by [`plot_conditional_forecast`](@ref) to
2071-
`p`. When called without an existing plot, the forecast is added to the current
2072-
plot if one is available.
1999+
Convenience wrapper for [`plot_conditional_forecast`](@ref). This function no
2000+
longer modifies any existing plots.
20732001
"""
2074-
function plot_conditional_forecast!(p::Union{StatsPlots.Plots.Plot,AbstractVector}, args...; kwargs...)
2075-
q = plot_conditional_forecast(args...; kwargs..., show_plots = false, save_plots = false)
2076-
if isa(p, AbstractVector)
2077-
@assert length(p) == length(q) "Number of plots must match."
2078-
for (pi, qi) in zip(p, q)
2079-
StatsPlots.plot!(pi, qi)
2080-
end
2081-
else
2082-
StatsPlots.plot!(p, q[1])
2083-
end
2084-
_store_last_plots!(p)
2085-
return p
2086-
end
2087-
2088-
function plot_conditional_forecast!(args...; kwargs...)
2089-
p = _LAST_PLOTS[]
2090-
if p === nothing
2091-
p = try
2092-
StatsPlots.current()
2093-
catch
2094-
nothing
2095-
end
2096-
end
2097-
if p === nothing
2098-
return plot_conditional_forecast(args...; kwargs...)
2099-
else
2100-
return plot_conditional_forecast!(p, args...; kwargs...)
2101-
end
2102-
end
2002+
plot_conditional_forecast!(args...; kwargs...) =
2003+
plot_conditional_forecast(args...; kwargs...)
21032004

21042005
"""
21052006
See [`plot_model_estimates!`](@ref)

0 commit comments

Comments
 (0)