PowerGraphics also provides some basic specifications for plotting SimulationResults
.
This example demonstrates some simple plotting capabilities using different Plots.julia
backends.
The plotting capabilities use the Julia Plots package which can generate plots using several different graphics packages. We'll use GR.jl and PlotlyJS.jl.
using PowerSystems # to load results
using PowerSimulations # to load results
using PowerGraphics
using PowerSystemCaseBuilder
If you have already run some of the other examples, you should have generated some results (If you haven't run some of the other simulations, you can run
using Dates
using DataFrames
using HiGHS # mip solver
solver = optimizer_with_attributes(HiGHS.Optimizer, "mip_rel_gap" => 0.5)
sys_DA = build_system(SIIPExampleSystems, "5_bus_matpower_DA")
sys_RT = build_system(SIIPExampleSystems, "5_bus_matpower_RT")
template_uc = template_unit_commitment(use_slacks=true)
template_ed = template_economic_dispatch(
network=NetworkModel(CopperPlatePowerModel, duals=[CopperPlateBalanceConstraint]),
)
models = SimulationModels(
decision_models=[
DecisionModel(template_uc, sys_DA, name="UC", optimizer=solver),
DecisionModel(template_ed, sys_RT, name="ED", optimizer=solver),
],
)
feedforward = Dict(
"ED" => [
SemiContinuousFeedforward(
component_type=ThermalStandard,
source=OnVariable,
affected_values=[ActivePowerVariable],
),
],
)
DA_RT_sequence = SimulationSequence(
models=models,
ini_cond_chronology=InterProblemChronology(),
feedforwards=feedforward,
)
file_path = mktempdir(cleanup=true)
sim = Simulation(
name="5bus-test",
steps=1,
models=models,
sequence=DA_RT_sequence,
simulation_folder=file_path,
)
build!(sim)
execute!(sim, enable_progress_bar=false)
results = SimulationResults(sim);
uc_results = get_decision_problem_results(results, "UC")
ed_results = get_decision_problem_results(results, "ED");
list_dual_names(ed_results)
prices = read_dual(ed_results, "CopperPlateBalanceConstraint__System")
read_realized_dual(ed_results, "CopperPlateBalanceConstraint__System")
┌ Error: Generator voltage set-points for bus 3 are inconsistent. This can lead to unexpected results
└ @ PowerSystems ~/.julia/packages/PowerSystems/zVsmd/src/parsers/pm_io/matpower.jl:245
┌ Error: Generator voltage set-points for bus 10 are inconsistent. This can lead to unexpected results
└ @ PowerSystems ~/.julia/packages/PowerSystems/zVsmd/src/parsers/pm_io/matpower.jl:245
┌ Error: Generator voltage set-points for bus 3 are inconsistent. This can lead to unexpected results
└ @ PowerSystems ~/.julia/packages/PowerSystems/zVsmd/src/parsers/pm_io/matpower.jl:245
┌ Error: Generator voltage set-points for bus 10 are inconsistent. This can lead to unexpected results
└ @ PowerSystems ~/.julia/packages/PowerSystems/zVsmd/src/parsers/pm_io/matpower.jl:245
24 rows × 2 columns
DateTime | CopperPlateBalanceConstraint__System | |
---|---|---|
DateTime | Float64 | |
1 | 2020-01-01T00:00:00 | 1000.0 |
2 | 2020-01-01T01:00:00 | 1000.0 |
3 | 2020-01-01T02:00:00 | 1000.0 |
4 | 2020-01-01T03:00:00 | 1000.0 |
5 | 2020-01-01T04:00:00 | 1000.0 |
6 | 2020-01-01T05:00:00 | 1000.0 |
7 | 2020-01-01T06:00:00 | 1000.0 |
8 | 2020-01-01T07:00:00 | 1000.0 |
9 | 2020-01-01T08:00:00 | 1000.0 |
10 | 2020-01-01T09:00:00 | 1000.0 |
11 | 2020-01-01T10:00:00 | 1000.0 |
12 | 2020-01-01T11:00:00 | 1000.0 |
13 | 2020-01-01T12:00:00 | 1000.0 |
14 | 2020-01-01T13:00:00 | 1000.0 |
15 | 2020-01-01T14:00:00 | 1000.0 |
16 | 2020-01-01T15:00:00 | 1000.0 |
17 | 2020-01-01T16:00:00 | 1000.0 |
18 | 2020-01-01T17:00:00 | 1000.0 |
19 | 2020-01-01T18:00:00 | 1000.0 |
20 | 2020-01-01T19:00:00 | 1000.0 |
21 | 2020-01-01T20:00:00 | 1000.0 |
22 | 2020-01-01T21:00:00 | 1000.0 |
23 | 2020-01-01T22:00:00 | 1000.0 |
24 | 2020-01-01T23:00:00 | 1000.0 |
Alternatively, you can load the results into memory with:
simulation_folder = joinpath(pkgdir(SIIPExamples), "rts-test")
simulation_folder =
joinpath(simulation_folder, "$(maximum(parse.(Int64,readdir(simulation_folder))))")
results = SimulationResults(simulation_folder);
uc_results = get_decision_problem_results(results, "UC")
Since some of the plotting capabilities rely on input data as well as output data (e.g. fuel plots)
but the result deserialization doesn't load the System
, we can add the System
to the results
so that the plotting routines can find the requisite data.
set_system!(uc_results, sys_DA)
By default, PowerGraphics uses the GR graphics package as the backend for Plots.jl to
generate figures. This creates static plots and should execute without any extra steps.
For example, we can create a plot of a particular variable in the uc_results
object:
gr() # loads the GR backend
timestamps = get_realized_timestamps(uc_results)
variable = read_realized_variable(uc_results, "ActivePowerVariable__ThermalStandard")
plot_dataframe(variable, timestamps)
However, interactive plotting can generate much more insightful figures, especially when creating somewhat complex stacked figures. So, we can use the PlotlyJS backend for Plots, but it requires that PlotlyJS.jl is installed in your Project.toml (if in a notebook, WebIO.jl is required too). To startup the PlotlyJS backend, run: plotlyjs()
PowerGraphics creates an un-stacked line plot by default, but supports kwargs to
create a variety of different figure styles. For example, a stacked area figure can be
created with the stack = true
kwarg:
plot_dataframe(variable, timestamps; stack=true)
Or a bar chart can be created with bar = true
:
plot_dataframe(variable, timestamps; bar=true)
Or a stacked bar chart...
plot_dataframe(variable, timestamps; bar=true, stack=true)
PowerGraphics also supports some basic aggregation to create cleaner plots. For example, we can create a plot of the different variables:
generation = get_generation_data(uc_results)
plot_pgdata(generation, stack=true)
reserves = get_service_data(uc_results)
plot_pgdata(reserves)
GKS: Rectangle definition is invalid in routine SET_VIEWPORT
Another standard aggregation is available to plot demand values:
plot_demand(uc_results)
The plot_demand
function can also be called with the System
rather than the StageResults
to inspect the input data. This method can also display demands aggregated by a specified
<:Topology
:
# plot_demand(uc_results.system, aggregation=Area)
Another standard aggregation exists based on the fuel categories of the generators in the
System
plot_fuel(uc_results)