Plotting
This one's complicated. Yikes.
Essentially, build your plots with makeplots
and save them to interactive html with savehtmlplot
.
For makeplots
, you pass the dataframe (typically gss.df
or similar), a bunch of Strings or Symbols specifying columns to map to various variables, and whatever other random settings you need.
The docstring is horrendously complicated and so is the signature, but remember: if you don't need the functionality, just don't include it, and it'll (maybe (probably (surely))) be fine.
PowerSystemsExperiments.savehtmlplot
— Functionsavehtmlplot(plot, filename::String=nothing)
utility to save plot
to filename
.html. Default filename is the plot's image download filename, if it exists, or worst case just "plot.html"
PowerSystemsExperiments.makeplots
— Functionmakeplots(
df::DataFrame;
rows::Union{AbstractString, Symbol, Nothing}=nothing,
cols::Union{AbstractString, Symbol, Nothing}=nothing,
legendgroup::Union{AbstractString, Symbol, Nothing}=nothing,
markershape::Union{AbstractString, Symbol, Nothing}=nothing,
trace_names::Union{AbstractString, Symbol, Nothing}=nothing,
color::Union{AbstractString, Symbol, Nothing}=nothing,
opacity::Union{AbstractString, Symbol, Real}=1.0,
markersize::Union{AbstractString, Symbol, Real}=8,
hovertext::Union{AbstractString, Symbol, Nothing}=nothing,
scattermode::Union{AbstractString, Symbol}="markers",
scattertext::Union{AbstractString, Symbol, Nothing}=nothing,
colorbar::Bool=false,
map_to_colorbar::Bool=true,
marker_line_width::Union{Real, Nothing} = nothing,
slider_trace_id::Union{AbstractString, Symbol, Nothing}=nothing,
row_sort_func::Function = identity,
col_sort_func::Function = identity,
color_sort_func::Function = identity,
slider_sort_func::Function = identity,
slider::Union{AbstractString, Symbol, Nothing}=nothing,
slider_label_func::Function = x->round(x, sigdigits=2),
slider_current_value_prefix::Union{AbstractString, Nothing} = nothing,
x::Union{AbstractString, Symbol, NamedTuple{(:x0, :dx), <:Tuple{Real, Real}}, Vector{<:Real}}=nothing,
y::Union{AbstractString, Symbol, NamedTuple{(:y0, :dy), <:Tuple{Real, Real}}, Vector{<:Real}}=nothing,
x_title::Union{AbstractString, Nothing} = nothing,
y_title::Union{AbstractString, Nothing} = nothing,
col_title_func::Function=identity,
row_title_func::Function=identity,
legendgroup_title_func::Function=identity,
supertitle::Union{AbstractString, Nothing} = nothing,
yaxis_home_range::Union{NamedTuple{(:min, :max), <:Tuple{Real, Real}}, Nothing} = nothing,
xaxis_home_range::Union{NamedTuple{(:min, :max), <:Tuple{Real, Real}}, Nothing} = nothing,
image_export_filename::String = "saved_plot",
image_export_size::@NamedTuple{height::Int64, width::Int64}=(height=1200, width=1200),
colorlist::Union{Vector{String}, Vector{<:Colors.Colorant}} = Colors.distinguishable_colors(10),
symbollist::Vector{<:AbstractString} = ["circle", "square", "diamond", "cross", "triangle-up", "star", "circle-cross", "y-up", "circle-open", "square-open", "diamond-open", "cross-open", "triangle-up-open", "star-open"],
colorbar_args::Dict = Dict(attr(autocolorscale=true, colorbar=attr(outlinecolor=colorant"black", outlinewidth=1))),
use_webgl::Bool = false,
hide_legend_duplicates::Bool = true,
legend_location::@NamedTuple{x::Float64, y::Float64} = (x=0.9, y=0.9),
legend_visible::Bool=true,
shared_xaxes::Union{String, Bool}="all",
shared_yaxes::Union{String, Bool}="all",
fontsize::Real=18,
offsets::NamedTuple{(:xtitle, :ytitle, :coltitle, :rowtitle), <:Tuple{Real, Real, Real, Real}} = (xtitle = -0.03, ytitle=-0.05, coltitle=0.01, rowtitle=0.01),
subplotgaps::NamedTuple{(:horizontal_spacing, :vertical_spacing), <:Tuple{Real, Real}}=(horizontal_spacing=0.1, vertical_spacing=0.06),
)
Plot data from a dataframe. allows high dimensional data through a grid of subplots, trace colors, and a slider.
- 2 variables for (x, y) on plot
- 2 variables for row and column in subplot grid
- 1 variable for color
- 1 variable for marker symbol
- 1 variable on a slider
- 1 variable on hovertext
- 1 variable on marker text
- 1 variable on opacity
- 1 variable on trace name
- 1 variable for trace or datapoint size/thickness
- 0 variables for legend group (typically can't work independently; pair with color or marker symbol)
= 12 max variables
In reality, you should use less. For example, it's impossible to read the opacity correctly, so you should make hovertext and opacity the same. Also, if you don't need that many variables, you can just leave them out. If you don't specify what to separate along subplot rows and columns, makeplots
will just give you a single subplot.
Notes
- colorbar doesn't work very well with line plots. If you want to vary color by trace, that's ok, just set the
colorlist
to make the legend effectively a discrete colorbar. - for slider:
- make sure that each slider value has the exact same number of traces
- either provide the
slider_trace_id
or sort the dataframe such that subsetting to each slider value gives the remaining traces in the same order every time
Arguments
Mandatory Arguments
df
: the DataFrame to get data from.
DATA TO PLOT
x
and y
can be:
- AbstractString, Symbol: get from column of df
- NamedTuple of
(x0, dx)
or(y0, dy)
: evenly spaced values with given parameters - Vector{<:Real}: this specific array every time
Use the data_sigdigits
(default: 6) argument to specify how much to round this input data. This significantly helps reduce the size of the exported HTML files.
If you choose to get the series from the dataframe, each element of the column will be one series/trace, so it better be a vector! If you have scalar or categorical values, try the default PlotlyJS.plot(df, ...)
- it's pretty good for that.
Specifying which columns to use for what
rows
: the column of the dataframe specifying which row of subplots this data should be oncols
: the column of the dataframe specifying which column of subplots this data should be onlegendgroup
: the column of the dataframe specifying which legendgroup this trace should be. Value of this column is the legendgroup name.color
: the column of the dataframe specifying the color of this trace (or the color of each datapoint in this trace). Mapped tocolorlist
after being sorted bycolor_sort_func
ifcolorbar==false
, otherwise used raw for colorbar.opacity
(default: 1.0): the opacity of all datapoints OR the column of the dataframe specifying the opacity of each datapointmarkershape
: the column of the dataframe to map to marker shape. Uses shapes provided insymbollist
.markersize
(default: 8): the size of all markers OR the column of the dataframe specifying the size of each trace or datapoint.trace_names
: the column of the dataframe specifying the text name of this trace. Visible in legend and on hover. Ifhide_legend_duplicates==true
, duplicates oftrace_names
will not be seen in each legend group.hovertext
: the column of the dataframe specifying any additional text that appears for this trace on hoverslider
: the column of the dataframe specifying which slider value this trace corresponds to. See Slider Configscattertext
: the column of the dataframe specifying the text to appear next to datapoints. Only has effect ifscattermode
contains thetext
flag.
Titles
x_title
: x axis title for every plot.y_title
: y axis title for every plot.col_title_func
: function to get column title from value in column of df passed incols
. Default: identityrow_title_func
: function to get row title from value in column of df passed inrow
. Default: identitylegendgroup_title_func
: function to get the legendgroup title text from the legendgroup name. Default: identitysupertitle
: Biggest title on the graph.
Legend & Axes
colorbar
(default: false): whether to display the colorbar. Can be finnicky, only really works for non-line plots.colorbar_args
: Dictionary of parameters for the colorbar. See Julia PlotlyJS docs for Layout.coloraxis.shared_xaxes
,shared_yaxes
: how to share axes. seeSubplots
.hide_legend_duplicates
(default: true): hide duplicate trace names for each legend group.legend_visible
(default: true): show the legend
Markers & Colors
scattermode
(default: "markers"): mode for scatterplot. Some combination of "markers", "lines", and "text", joined with "+". ie, "markers+text".colorlist
(default: 10 ok colors): list of colors to use. If you have more than 10 different values you want represented by color, or you want a specific set of colors, set this array.color_sort_func
(default: identity): function by which to sort values ofcolor
before associating withcolorlist
(if no colorbar)symbollist
(default: 14 different symbols): list of symbols to use for the different values ofmarkershape
. If you have more than 14 different values, set this array.use_webgl
(default:true
): Whether to use scattergl or plain scatter.map_to_colorbar
(default:true
): whether to associate markers with colorbar and show the scale. Generally keep this set totrue
. You may have to set it to false when you have"lines"
in yourscattermode
. The PlotlyJS documentation is not entirely clear on the effect of these options.
Sizes
fontsize
(default 18): font size for most/main textmargin
(default: 200): Int, just the margin size (px)offsets
(default:(xtitle = -0.03, ytitle=-0.05, coltitle=0.01, rowtitle=0.01)
): where to put the titles, as a fraction of the plotyaxis_home_range
andxaxis_home_range
can beNamedTuple{(:min, :max), <:Tuple{Real, Real}}
legend_location
(default: (x=0.9, y=0.9)): NamedTuple with Float64x
andy
defining the legend location relative to the paper.image_export_size
(default: (height=1200, width=1200)): NamedTuple with Integersheight
andwidth
specifying the size in pixels of the SVG plots saved with the "download plot" button.image_export_filename
(default:"saved_plot"
): default filename when image is exported using button on plot.
Slider Config
slider_sort_func
(default:identity
): a function to get keys for the sort of the slider labels. For example,(x -> -x)
would reverse the slider.slider_trace_id
: the column in the dataframe corresponding to a trace identifier. There must be exactly one row for each unique combination of this column and the slider column. If not passed, will use the order of the dataframe.slider_label_func
(default:x->round(x, sigdigits=2)
): gets slider tick label from value.slider_current_value_prefix
: prefix to put before the value on the slider's label. For example, "val: " would make the label "val: 0.5" or something
Things to be aware of
Also known as Questionable Things I'm Not Willing To Fix Right Now
- if
colorbar==false
,color
is assumed to be categorical and each unique color is mapped to an element ofcolorlist
after being sorted bycolor_sort_func
- colorbar doesn't really work with lines because you can't have lines of variable color. To get it to work, you need to pass
colorlist
and ensure that it matches the right values on the colorscale you give incolorbar_args
colorbar_args
are kinda complicated. Here's an example:
Dict(attr(
autocolorscale=false,
cmax= 1.0,
# cmid=0.5,
cmin= -1.2,
title="",
colorbar=attr(
outlinecolor=colorant"black",
outlinewidth=1,
tickmode="array",
ticktext=(["Z=1.0", "P=1.0", "P=0.8", "P=0.6", "P=0.4", "P=0.2", "P=E=0", "E=0.2", "E=0.4", "E=0.6", "E=0.8", "E=1.0"]),
tickvals=(collect(range(-1.2, 1, 13)).+(2.2/(2*12)))[1:end - 1],
xref="paper",
yref="paper",
x=1.02,
thickness=40
),
colorscale=[[0.0, RGB(colorant"yellow")],
[1.0, RGB(colorant"purple")]]
))
Note that colorscale
's numerical scale is in $[0, 1]$, which is different from cmax
and cmin
.
- You can have a legend and a colorbar at the same time, but it is recommended to just use
hide_legend_duplicates=true
(which is defaulttrue
) and use the legend to represent a different variable. Since color cannot be used, you'll have to pair it with another method of conveying information, like opacity or marker shape. symbollist
andcolorlist
provide some initial values, but if you have more unique values represented by symbol or color respectively, you'll need to provide new lists with more new values.scattertext
andhovertext
can make plot files MASSIVE. Take care to include as little information as possible in them. Round numbers to the appropriate length.- similarly, high values of
data_sigdigits
can increase plot file size. Do not set it to a high number unless you absolutely need to. slider_trace_id
is funny. You don't actually have to make some fancy id - often using the default, the order of the rows in the dataframe, is best. Just make sure to sort the dataframe beforehand by as many things as possible so that you have a very predictable and consistent order of traces across slider values.