@@ -9,6 +9,7 @@ const irf_active_plot_container = Dict[]
99const model_estimates_active_plot_container = Dict[]
1010
1111import StatsPlots
12+ import DataStructures: OrderedSet
1213import SparseArrays: SparseMatrixCSC
1314import NLopt
1415using DispatchDoctor
@@ -839,7 +840,7 @@ function plot_irf(𝓂::ℳ;
839840 :sylvester_algorithm => sylvester_algorithm,
840841 :lyapunov_algorithm => lyapunov_algorithm,
841842 :plot_data => Y,
842- :reference_steady_state => reference_steady_state,
843+ :reference_steady_state => reference_steady_state[var_idx] ,
843844 :variable_names => variable_names,
844845 :shock_names => shock_names,
845846 :shock_idx => shock_idx,
@@ -965,35 +966,42 @@ function plot_irf_subplot(irf_data::AbstractVector{S}, steady_state::S, variable
965966 return p
966967end
967968
968- function plot_irf_subplot (irf_data:: Vector{<:AbstractVector{S}} , steady_state:: Vector{S} , variable_name:: String , can_dual_axis:: Bool ) where S <: AbstractFloat
969- same_ss = maximum (steady_state) - minimum (steady_state) < 1e-12
970-
969+ function plot_irf_subplot (irf_data:: Vector{<:AbstractVector{S}} , steady_state:: Vector{S} , variable_name:: String , can_dual_axis:: Bool , same_ss:: Bool ; pal:: StatsPlots.ColorPalette = StatsPlots. palette (:auto )) where S <: AbstractFloat
971970 plot_dat = []
972971 plot_dat_dual = []
973972
974- for i in 1 : length (irf_data)
975- if can_dual_axis && same_ss
976- push! (plot_dat, irf_data[i] .+ steady_state[i])
977- push! (plot_dat_dual, 100 * ((irf_data[i] .+ steady_state[i]) ./ steady_state[i] .- 1 ))
978- else
979- push! (plot_dat, irf_data[i])
973+ pal_val = Int[]
974+
975+ stst = 1.0
976+
977+ for (i,(y, ss)) in enumerate (zip (irf_data, steady_state))
978+ if ! isnan (ss)
979+ if can_dual_axis && same_ss
980+ stst = ss
981+ push! (plot_dat, y .+ ss)
982+ push! (plot_dat_dual, 100 * ((y .+ ss) ./ ss .- 1 ))
983+ else
984+ push! (plot_dat, y)
985+ end
986+ push! (pal_val, i)
980987 end
981988 end
982989
983-
984990 p = StatsPlots. plot (plot_dat,
985991 title = variable_name,
986992 ylabel = same_ss ? " Level" : " abs. " * LaTeXStrings. L "\D elta" ,
993+ color = pal[pal_val]' ,
987994 label = " " )
988995
989996 if can_dual_axis && same_ss
990997 StatsPlots. plot! (StatsPlots. twinx (),
991998 plot_dat_dual,
992999 ylabel = LaTeXStrings. L "\% \D elta" ,
1000+ color = pal[pal_val]' ,
9931001 label = " " )
9941002 end
9951003
996- StatsPlots. hline! (can_dual_axis && same_ss ? [steady_state[ 1 ] 0 ] : [same_ss ? steady_state[ 1 ] : 0 ],
1004+ StatsPlots. hline! (can_dual_axis && same_ss ? [stst 0 ] : [same_ss ? stst : 0 ],
9971005 color = :black ,
9981006 label = " " )
9991007
@@ -1010,7 +1018,7 @@ function plot_irf!(𝓂::ℳ;
10101018 save_plots:: Bool = false ,
10111019 save_plots_format:: Symbol = :pdf ,
10121020 save_plots_path:: String = " ." ,
1013- plots_per_page:: Int = 9 ,
1021+ plots_per_page:: Int = 6 ,
10141022 algorithm:: Symbol = :first_order ,
10151023 shock_size:: Real = 1 ,
10161024 negative_shock:: Bool = false ,
@@ -1311,7 +1319,7 @@ function plot_irf!(𝓂::ℳ;
13111319 :sylvester_algorithm => sylvester_algorithm,
13121320 :lyapunov_algorithm => lyapunov_algorithm,
13131321 :plot_data => Y,
1314- :reference_steady_state => reference_steady_state,
1322+ :reference_steady_state => reference_steady_state[var_idx] ,
13151323 :variable_names => variable_names,
13161324 :shock_names => shock_names,
13171325 :shock_idx => shock_idx,
@@ -1320,10 +1328,10 @@ function plot_irf!(𝓂::ℳ;
13201328 push! (irf_active_plot_container, args_and_kwargs)
13211329
13221330 diffdict = compare_args_and_kwargs (irf_active_plot_container)
1323-
1331+
13241332 @assert haskey (diffdict, :parameters ) " New plot must be different from previous plot. Use the version without ! to plot."
13251333
1326- param_nms = diffdict[:parameters ]|> keys|> collect|> sort
1334+ param_nms = diffdict[:parameters ] |> keys |> collect |> sort
13271335
13281336 annotate_ss = Vector{Pair{String, Any}}[]
13291337
@@ -1340,118 +1348,168 @@ function plot_irf!(𝓂::ℳ;
13401348 annotate_params_plot = plot_df (annotate_params)
13411349
13421350 legend_plot = StatsPlots. plot (framestyle = :none , legend_columns = length (irf_active_plot_container))
1351+
1352+ joint_shocks = OrderedSet {String} ()
1353+ joint_variables = OrderedSet {String} ()
13431354
13441355 for (i,k) in enumerate (irf_active_plot_container)
13451356 StatsPlots. plot! (legend_plot,
1346- fill (0 ,1 ,1 ),
1347- framestyle = :none ,
1348- legend = :inside ,
1349- label = i)
1357+ fill (0 ,1 ,1 ),
1358+ framestyle = :none ,
1359+ legend = :inside ,
1360+ label = i)
1361+
1362+ push! (joint_shocks, k[:shock_names ]. .. )
1363+ push! (joint_variables, k[:variable_names ]. .. )
13501364 end
13511365
1366+ sort! (joint_shocks)
1367+ sort! (joint_variables)
1368+
13521369 return_plots = []
13531370
1354- for shock in 1 : length (shock_idx)
1355- n_subplots = length (var_idx )
1371+ for shock in joint_shocks
1372+ n_subplots = length (joint_variables )
13561373 pp = []
13571374 pane = 1
13581375 plot_count = 1
1359- for i in 1 : length (var_idx)
1360- if all (isapprox .(Y[i,:,shock], 0 , atol = eps (Float32)))
1376+ joint_non_zero_variables = []
1377+ can_dual_axiss = Bool[]
1378+
1379+ for var in joint_variables
1380+ not_zero_in_any_irf = false
1381+ can_dual_axis = gr_back
1382+
1383+ for k in irf_active_plot_container
1384+ var_idx = findfirst (== (var), k[:variable_names ])
1385+ shock_idx = findfirst (== (shock), k[:shock_names ])
1386+
1387+
1388+ if isnothing (var_idx) || isnothing (shock_idx)
1389+ # If the variable or shock is not present in the current irf_active_plot_container,
1390+ # we skip this iteration.
1391+ continue
1392+ else
1393+ if any (.! isapprox .(k[:plot_data ][var_idx,:,shock_idx], 0 , atol = eps (Float32)))
1394+ not_zero_in_any_irf = not_zero_in_any_irf || true
1395+ # break # If any irf data is not approximately zero, we set the flag to true.
1396+ end
1397+
1398+ SS = k[:reference_steady_state ][var_idx]
1399+
1400+ if all ((k[:plot_data ][var_idx,:,shock_idx] .+ SS) .> eps (Float32)) && (SS > eps (Float32))
1401+ can_dual_axis = can_dual_axis && true
1402+ end
1403+ end
1404+ end
1405+
1406+ if not_zero_in_any_irf
1407+ push! (joint_non_zero_variables, var)
1408+ push! (can_dual_axiss, can_dual_axis)
1409+ else
1410+ # If all irf data for this variable and shock is approximately zero, we skip this subplot.
13611411 n_subplots -= 1
13621412 end
13631413 end
13641414
1365- for i in 1 : length (var_idx)
1366- SS = reference_steady_state[var_idx[i]]
1415+ for (var, can_dual_axis) in zip (joint_non_zero_variables, can_dual_axiss)
1416+ SSs = eltype (irf_active_plot_container[1 ][:reference_steady_state ])[]
1417+ Ys = AbstractVector{eltype (irf_active_plot_container[1 ][:plot_data ])}[]
13671418
1368- can_dual_axis = gr_back && all ((Y[i,:,shock] .+ SS) .> eps (Float32)) && (SS > eps (Float32))
1419+ for k in irf_active_plot_container
1420+ var_idx = findfirst (== (var), k[:variable_names ])
1421+ shock_idx = findfirst (== (shock), k[:shock_names ])
13691422
1370- if ! ( all ( isapprox .(Y[i,:,shock], 0 ,atol = eps (Float32))) )
1371- variable_name = replace_indices_in_symbol (𝓂 . timings . var[var_idx[i]])
1372-
1373- # push!(pp, plot_irf_subplot(Y[i,:,shock], SS, variable_name, can_dual_axis) )
1374- SSs = [k[ :reference_steady_state ][var_idx[i]] for k in irf_active_plot_container]
1375-
1376- if maximum (SSs) - minimum (SSs) > 1e-10
1377- push! (annotate_ss_page, String (variable_name) => minimal_sigfig_strings (SSs) )
1423+ if isnothing (var_idx) || isnothing (shock_idx )
1424+ # If the variable or shock is not present in the current irf_active_plot_container,
1425+ # we skip this iteration.
1426+ push! (SSs, NaN )
1427+ push! (Ys, zeros ( 0 ))
1428+ else
1429+ push! (SSs, k[ :reference_steady_state ][var_idx])
1430+ push! (Ys, k[ :plot_data ][var_idx,:,shock_idx] )
13781431 end
1432+ end
1433+
1434+ same_ss = true
13791435
1380- push! (pp, plot_irf_subplot ( [k[:plot_data ][i,:,shock] for k in irf_active_plot_container],
1381- SSs,
1382- variable_name,
1383- can_dual_axis))
1384-
1385- if ! (plot_count % plots_per_page == 0 )
1386- plot_count += 1
1436+ if maximum (filter (! isnan, SSs)) - minimum (filter (! isnan, SSs)) > 1e-10
1437+ push! (annotate_ss_page, var => minimal_sigfig_strings (SSs))
1438+ same_ss = false
1439+ end
1440+
1441+ push! (pp, plot_irf_subplot ( Ys,
1442+ SSs,
1443+ var,
1444+ can_dual_axis,
1445+ same_ss))
1446+
1447+ if ! (plot_count % plots_per_page == 0 )
1448+ plot_count += 1
1449+ else
1450+ plot_count = 1
1451+
1452+ if shocks == :simulate
1453+ shock_string = " : simulate all"
1454+ shock_name = " simulation"
1455+ elseif shocks == :none
1456+ shock_string = " "
1457+ shock_name = " no_shock"
1458+ elseif shocks isa Union{Symbol_input,String_input}
1459+ shock_string = " : " * shock
1460+ shock_name = shock
13871461 else
1388- plot_count = 1
1462+ shock_string = " Series of shocks"
1463+ shock_name = " shock_matrix"
1464+ end
13891465
1390- if shocks == :simulate
1391- shock_string = " : simulate all"
1392- shock_name = " simulation"
1393- elseif shocks == :none
1394- shock_string = " "
1395- shock_name = " no_shock"
1396- elseif shocks isa Union{Symbol_input,String_input}
1397- shock_string = " : " * replace_indices_in_symbol (𝓂. timings. exo[shock_idx[shock]])
1398- shock_name = replace_indices_in_symbol (𝓂. timings. exo[shock_idx[shock]])
1399- else
1400- shock_string = " Series of shocks"
1401- shock_name = " shock_matrix"
1402- end
1466+ ppp = StatsPlots. plot (pp... ; attributes... )
14031467
1404- ppp = StatsPlots. plot (pp... ; attributes... )
1468+ ppp_pars = StatsPlots. plot (annotate_params_plot; attributes... )
1469+
1470+ pushfirst! (annotate_ss_page, " Plot index" => 1 : length (diffdict[:parameters ][param_nms[1 ]]))
14051471
1406- ppp_pars = StatsPlots. plot (annotate_params_plot; attributes... )
1407-
1408- pushfirst! (annotate_ss_page, " Plot index" => 1 : length (diffdict[:parameters ][param_nms[1 ]]))
1472+ push! (annotate_ss, annotate_ss_page)
14091473
1410- push! (annotate_ss, annotate_ss_page)
1474+ if length (annotate_ss[pane]) > 1
1475+ annotate_ss_plot = plot_df (annotate_ss[pane])
14111476
1412- if length (annotate_ss[pane]) > 0
1413- annotate_ss_plot = plot_df (annotate_ss[pane])
1477+ ppp_ss = StatsPlots. plot (annotate_ss_plot; attributes... )
14141478
1415- ppp_ss = StatsPlots. plot (annotate_ss_plot; attributes... )
1416-
1417- p = StatsPlots. plot (ppp,
1418- legend_plot,
1419- ppp_pars,
1420- ppp_ss,
1421- layout = StatsPlots. grid (4 , 1 , heights = [37 , 1 , 9 , 9 ] ./ 56 ),
1422- plot_title = " Model: " * 𝓂. model_name* " " * shock_dir * shock_string * " (" * string (pane)* " /" * string (Int (ceil (n_subplots/ plots_per_page)))* " )" ;
1423- attributes_redux... )
1424- else
1425- p = StatsPlots. plot (ppp,
1426- legend_plot,
1427- ppp_pars,
1428- layout = StatsPlots. grid (3 , 1 , heights = [15 , 1 , 5 ] ./ 21 ),
1429- plot_title = " Model: " * 𝓂. model_name* " " * shock_dir * shock_string * " (" * string (pane)* " /" * string (Int (ceil (n_subplots/ plots_per_page)))* " )" ;
1430- attributes_redux... )
1431- end
1479+ p = StatsPlots. plot (ppp,
1480+ legend_plot,
1481+ ppp_pars,
1482+ ppp_ss,
1483+ layout = StatsPlots. grid (4 , 1 , heights = [37 , 1 , 9 , 9 ] ./ 56 ),
1484+ plot_title = " Model: " * 𝓂. model_name* " " * shock_dir * shock_string * " (" * string (pane)* " /" * string (Int (ceil (n_subplots/ plots_per_page)))* " )" ;
1485+ attributes_redux... )
1486+ else
1487+ p = StatsPlots. plot (ppp,
1488+ legend_plot,
1489+ ppp_pars,
1490+ layout = StatsPlots. grid (3 , 1 , heights = [15 , 1 , 5 ] ./ 21 ),
1491+ plot_title = " Model: " * 𝓂. model_name* " " * shock_dir * shock_string * " (" * string (pane)* " /" * string (Int (ceil (n_subplots/ plots_per_page)))* " )" ;
1492+ attributes_redux... )
1493+ end
14321494
1433- push! (return_plots,p)
1495+ push! (return_plots,p)
14341496
1435- if show_plots
1436- display (p)
1437- end
1497+ if show_plots
1498+ display (p)
1499+ end
14381500
1439- if save_plots
1440- StatsPlots. savefig (p, save_plots_path * " /irf__" * 𝓂. model_name * " __" * shock_name * " __" * string (pane) * " ." * string (save_plots_format))
1441- end
1501+ if save_plots
1502+ StatsPlots. savefig (p, save_plots_path * " /irf__" * 𝓂. model_name * " __" * shock_name * " __" * string (pane) * " ." * string (save_plots_format))
1503+ end
14421504
1443- pane += 1
1505+ pane += 1
14441506
1445- annotate_ss_page = Pair{String,Any}[]
1507+ annotate_ss_page = Pair{String,Any}[]
14461508
1447- pp = []
1448- end
1449- end
1509+ pp = []
1510+ end
14501511 end
14511512
1452- pushfirst! (annotate_ss_page, " Plot index" => 1 : length (diffdict[:parameters ][param_nms[1 ]]))
1453-
1454- push! (annotate_ss, annotate_ss_page)
14551513
14561514 if length (pp) > 0
14571515 if shocks == :simulate
@@ -1461,8 +1519,8 @@ function plot_irf!(𝓂::ℳ;
14611519 shock_string = " "
14621520 shock_name = " no_shock"
14631521 elseif shocks isa Union{Symbol_input,String_input}
1464- shock_string = " : " * replace_indices_in_symbol (𝓂 . timings . exo[shock_idx[ shock]])
1465- shock_name = replace_indices_in_symbol (𝓂 . timings . exo[shock_idx[ shock]])
1522+ shock_string = " : " * shock
1523+ shock_name = shock
14661524 else
14671525 shock_string = " Series of shocks"
14681526 shock_name = " shock_matrix"
@@ -1476,7 +1534,7 @@ function plot_irf!(𝓂::ℳ;
14761534
14771535 push! (annotate_ss, annotate_ss_page)
14781536
1479- if length (annotate_ss[pane]) > 0
1537+ if length (annotate_ss[pane]) > 1
14801538 annotate_ss_plot = plot_df (annotate_ss[pane])
14811539
14821540 ppp_ss = StatsPlots. plot (annotate_ss_plot; attributes... )
@@ -1584,7 +1642,9 @@ function minimal_sigfig_strings(v::AbstractVector{<:Real};
15841642 out = Vector {String} (undef, length (v))
15851643 for i in eachindex (v)
15861644 x = v[i]
1587- if ! (isfinite (x)) || x == 0
1645+ if isnan (x)
1646+ out[i] = " "
1647+ elseif ! (isfinite (x)) || x == 0
15881648 # For zero or non finite just echo (rule does not change them)
15891649 out[i] = string (x)
15901650 elseif haskey (req_sig, i)
0 commit comments