11using Plots, Latexify
2- import Plots. plot, Plots. plot!; export plot, plot!, plot_phase_diagram, savefig
2+ import Plots. plot, Plots. plot!; export plot, plot!, plot_phase_diagram, savefig, plot_spaghetti
33
44const _set_Plots_default = Dict {Symbol, Any} ([
55 :fontfamily => " computer modern" ,
66 :titlefont => " computer modern" ,
77 :tickfont => " computer modern" ,
88 :linewidth => 2 ,
9- :legend => :outerright ])
9+ :legend_position => :outerright ])
1010
1111
1212
@@ -43,11 +43,15 @@ To make the 2d plot less chaotic it is required to specify the specific `branch`
4343
4444The x and y axes are taken automatically from `res`
4545"""
46- function plot (res:: Result , varargs... ; kwargs... ):: Plots.Plot
46+ function plot (res:: Result , varargs... ; cut = Pair ( missing , missing ), kwargs... ):: Plots.Plot
4747 if dim (res) == 1
4848 plot1D (res, varargs... ; _set_Plots_default... , kwargs... )
4949 elseif dim (res) == 2
50- plot2D (res, varargs... ; _set_Plots_default... , kwargs... )
50+ if ismissing (cut. first)
51+ plot2D (res, varargs... ; _set_Plots_default... , kwargs... )
52+ else
53+ plot2D_cut (res, varargs... ; cut= cut, _set_Plots_default... , kwargs... )
54+ end
5155 else
5256 error (" Data dimension " , dim (res), " not supported" )
5357 end
@@ -181,8 +185,47 @@ function plot2D(res::Result; z::String, branch::Int64, class="physical", not_cla
181185 p = add ? Plots. plot! () : Plots. plot () # start a new plot if needed
182186
183187 ylab, xlab = latexify .(string .(keys (res. swept_parameters)))
184- p = plot! (map (_realify, [Y, X, Z])... ;
185- st= :surface , color= :blue , opacity= 0.5 , xlabel= xlab, ylabel= ylab, zlabel= latexify (z), colorbar= false , kwargs... )
188+ p = plot! (map (_realify, [Y, X, Z])... ;
189+ st= :surface , color= :blue , opacity= 0.5 , xlabel= xlab, ylabel= ylab, zlabel= latexify (z), colorbar= false , kwargs... )
190+ end
191+
192+ function plot2D_cut (res:: Result ; y:: String , cut:: Pair , class= " default" , not_class= [], add= false , kwargs... )
193+
194+ if class == " default"
195+ if not_class == [] # plot stable full, unstable dashed
196+ p = plot2D_cut (res; y= y, cut= cut, class= [" physical" , " stable" ], add= add, kwargs... )
197+ plot2D_cut (res; y= y, cut= cut, class= " physical" , not_class= " stable" , add= true , style= :dash , kwargs... )
198+ return p
199+ else
200+ p = plot2D_cut (res; y= y, cut= cut, not_class= not_class, class= " physical" , add= add, kwargs... )
201+ return p
202+ end
203+ end
204+
205+ # the swept params are ranges and thus a sorted search can be performed
206+ cut_par, cut_value = cut
207+ cut_par_index = searchsortedfirst (res. swept_parameters[cut_par], cut_value)
208+
209+ # compare strings beacuse type Num cannot be compared
210+ swept_pars = res. swept_parameters. keys
211+ x_index = findfirst (sym -> string (sym)!= string (cut_par), swept_pars)
212+ isnothing (x_index) && error (" The variable $cut_par was not swept over." )
213+ x = swept_pars[x_index]
214+
215+ X = res. swept_parameters[x]
216+ Y = _apply_mask (transform_solutions (res, y), _get_mask (res, class, not_class)) # first transform, then filter
217+ branches = _realify (x_index== 1 ? Y[:, cut_par_index] : Y[cut_par_index, :])
218+
219+ # start a new plot if needed
220+ p = add ? Plots. plot! () : Plots. plot ()
221+
222+ # colouring is matched to branch index - matched across plots
223+ for k in findall (branch -> ! all (isnan .(branch)), branches[1 : end ]) # skip NaN branches but keep indices
224+ l = _is_labeled (p, k) ? nothing : k
225+ Plots. plot! (X, branches[k]; color= k, label= l, xlabel= latexify (string (x)), ylabel= latexify (y), kwargs... )
226+ end
227+
228+ return p
186229end
187230
188231
219262plot_phase_diagram (res:: Result , class:: String ; kwargs... ) = plot_phase_diagram (res; class= class, kwargs... )
220263
221264
222- function plot_phase_diagram_2D (res:: Result ; class= " physical" , not_class= [], kwargs... )
265+ function plot_phase_diagram_2D (res:: Result ; class= " physical" , not_class= [], kwargs... ):: Plots.Plot
223266 X, Y = values (res. swept_parameters)
224267 Z = sum .(_get_mask (res, class, not_class))
225268
@@ -230,12 +273,55 @@ function plot_phase_diagram_2D(res::Result; class="physical", not_class=[], kwar
230273end
231274
232275
233- function plot_phase_diagram_1D (res:: Result ; class= " physical" , not_class= [], kwargs... )
276+ function plot_phase_diagram_1D (res:: Result ; class= " physical" , not_class= [], kwargs... ):: Plots.Plot
234277 X = values (res. swept_parameters)
235278 Y = sum .(_get_mask (res, class, not_class))
236279 plot (X... , Y; xlabel= latexify (string (keys (res. swept_parameters)... )), ylabel= " #" , legend= false , yticks= 1 : maximum (Y), kwargs... )
237280end
238281
282+ # ##
283+ # Spaghetti Plot
284+ # ##
285+
286+ function plot_spaghetti (res:: Result ; x:: String , y:: String , z:: String , class= " default" , not_class= [], add= false , kwargs... ):: Plots.Plot
287+
288+ if class == " default"
289+ if not_class == [] # plot stable full, unstable dashed
290+ p = plot_spaghetti (res; x= x, y= y, z= z, class= [" physical" , " stable" ], add= add, kwargs... )
291+ plot_spaghetti (res; x= x, y= y, z= z, class= " physical" , not_class= " stable" , add= true , style= :dash , kwargs... )
292+ return p
293+ else
294+ p = plot_spaghetti (res; x= x, y= y, z= z, class= " physical" , not_class= not_class, add= add, kwargs... )
295+ return p
296+ end
297+ end
298+
299+ vars = res. problem. variables
300+ x_index = findfirst (sym -> string (sym)== x, vars)
301+ y_index = findfirst (sym -> string (sym)== y, vars)
302+ isnothing (x_index) && error (" The variable $x is not a defined variable." )
303+ isnothing (y_index) && error (" The variable $y is not a defined variable." )
304+
305+ swept_pars = res. swept_parameters. keys
306+ z_index = findfirst (sym -> string (sym)== z, swept_pars)
307+ isnothing (z_index) && error (" The variable $z was not swept over." )
308+
309+ Z = res. swept_parameters. vals[z_index]
310+ X = _apply_mask (transform_solutions (res, x), _get_mask (res, class, not_class)) |> _realify
311+ Y = _apply_mask (transform_solutions (res, y), _get_mask (res, class, not_class)) |> _realify
312+
313+ # start a new plot if needed
314+ p = add ? Plots. plot! () : Plots. plot ()
315+
316+ # colouring is matched to branch index - matched across plots
317+ for k in findall (x -> ! all (isnan .(x)), X[1 : end ]) # skip NaN branches but keep indices
318+ l = _is_labeled (p, k) ? nothing : k
319+ Plots. plot! (X[k], Y[k], Z; _set_Plots_default... ,
320+ color= k, label= l, xlabel= latexify (x), ylabel= latexify (y), zlabel= latexify (z), xlim= :symmetric , ylim= :symmetric , kwargs... )
321+ end
322+ return p
323+ end
324+
239325# ##
240326# TRANSFORMATIONS TO THE LAB frame
241327# ##
0 commit comments