Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support alternate color palette #106

Merged
merged 8 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: '1.6'
version: '1'
- name: Install dependencies
run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
- name: Build and deploy
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ DataFrames = "1"
DataStructures = "0.18"
InfrastructureSystems = "1"
Plots = "1"
PowerAnalytics = "0.3"
PowerAnalytics = "^0.3.3"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump to 0.4 once it is registered check JuliaRegistries/General#89039

PowerSystems = "2"
Reexport = "1"
Requires = "1"
Expand Down
1 change: 1 addition & 0 deletions src/PowerGraphics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ isdefined(Base, :__precompile__) && __precompile__()
@info "PowerGraphics.jl loads Plots.jl. Precompile might take a while"
module PowerGraphics

export load_palette
export plot_demand
export plot_dataframe
export plot_powerdata
Expand Down
28 changes: 12 additions & 16 deletions src/call_plots.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,6 @@ function _make_ylabel(
return ylabel
end

function get_default_seriescolor()
backend = Plots.backend()
return get_default_seriescolor(backend)
end

function get_default_seriescolor(backend)
return GR_DEFAULT
end

function get_default_seriescolor(backend::Plots.PlotlyJSBackend)
return PLOTLY_DEFAULT
end
################################### DEMAND #################################

"""
Expand Down Expand Up @@ -104,6 +92,7 @@ This function makes a plot of the demand in the system.
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
- `filter_func::Function = PowerSystems.get_available` : filter components included in plot
- `palette` : color palette from `load_palette`
"""
function plot_demand!(p, result::Union{IS.Results, PSY.System}; kwargs...)
backend = Plots.backend()
Expand All @@ -114,6 +103,7 @@ function plot_demand!(p, result::Union{IS.Results, PSY.System}; kwargs...)

title = get(kwargs, :title, "Demand")
y_label = get(kwargs, :y_label, bar ? "MWh" : "MW")
palette = get(kwargs, :palette, PALETTE)

load = PA.get_load_data(result; kwargs...)
kwargs = popkwargs(kwargs, :filter_func)
Expand All @@ -127,7 +117,7 @@ function plot_demand!(p, result::Union{IS.Results, PSY.System}; kwargs...)
p,
load_agg,
load.time;
seriescolor = get(kwargs, :seriescolor, get_default_seriescolor()),
seriescolor = get(kwargs, :seriescolor, get_palette_seriescolor(palette)),
linestyle = Symbol(linestyle),
line_dash = string(linestyle),
linewidth = get(kwargs, :linewidth, 1),
Expand Down Expand Up @@ -446,6 +436,7 @@ and assigns each fuel type a specific color.
- `nofill::Bool` : force empty area fill
- `stair::Bool`: Make a stair plot instead of a stack plot
- `filter_func::Function = PowerSystems.get_available` : filter components included in plot
- `palette` : Color palette as from `load_palette`.
"""
function plot_fuel!(p, result::IS.Results; kwargs...)
backend = Plots.backend()
Expand All @@ -457,14 +448,15 @@ function plot_fuel!(p, result::IS.Results; kwargs...)
title = get(kwargs, :title, "Fuel")
stack = get(kwargs, :stack, true)
bar = get(kwargs, :bar, false)
palette = get(kwargs, :palette, PALETTE)
kwargs =
Dict{Symbol, Any}((k, v) for (k, v) in kwargs if k ∉ [:title, :save, :set_display])

# Generation stack
gen = PA.get_generation_data(result; kwargs...)
sys = PA.PSI.get_system(result)
if sys === nothing
Throw(error("No System data present: please run `set_system!(results, sys)`"))
throw(error("No System data present: please run `set_system!(results, sys)`"))
end
cat = PA.make_fuel_dictionary(sys; kwargs...)
fuel = PA.categorize_data(gen.data, cat; curtailment = curtailment, slacks = slacks)
Expand All @@ -474,10 +466,14 @@ function plot_fuel!(p, result::IS.Results; kwargs...)

# passing names here enforces order
# TODO: enable custom sort with kwarg
fuel_agg = PA.combine_categories(fuel; names = intersect(CATEGORY_DEFAULT, keys(fuel)))
fuel_agg = PA.combine_categories(
fuel;
names = intersect(get_palette_category(palette), keys(fuel)),
)
y_label = get(kwargs, :y_label, bar ? "MWh" : "MW")

seriescolor = get(kwargs, :seriescolor, match_fuel_colors(fuel_agg, backend))
seriescolor =
get(kwargs, :seriescolor, match_fuel_colors(fuel_agg, backend; palette = palette))
p = plot_dataframe!(
p,
fuel_agg,
Expand Down
80 changes: 64 additions & 16 deletions src/definitions.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

# Color Definitions
PALETTE_FILE = joinpath(
const DEFAULT_PALETTE_FILE = joinpath(
dirname(dirname(pathof(PowerGraphics))),
"report_templates",
"color-palette.yaml",
Expand All @@ -20,8 +20,26 @@ function PaletteColor(category::String, RGB::String, order::Int64)
return PaletteColor(category, RGB, color, order)
end

function get_palette(file = nothing)
file = isnothing(file) ? PALETTE_FILE : file
"""
load_palette()
load_palette(file)

Loads color palette yaml from environment, the `DEFAULT_PALETTE_FILE`,
or a given file. See `DEFAULT_PALETTE_FILE` for an example.

# Arguments

- `file` : path to YAML color palette
"""
function load_palette()
if haskey(ENV, "PG_PALETTE")
load_palette(ENV["PG_PALETTE"])
else
load_palette(DEFAULT_PALETTE_FILE)
end
end

function load_palette(file)
palette_config = YAML.load_file(file)
palette_colors = []
for (k, v) in palette_config
Expand All @@ -30,9 +48,11 @@ function get_palette(file = nothing)
sort!(palette_colors, by = x -> x.order)
return palette_colors
end
function get_default_palette()

const PALETTE = load_palette()

function get_default_palette(palette)
default_palette = []
palette = get_palette()
default_order = [6, 52, 14, 1, 32, 7, 18, 20, 27, 53, 17] # the default order from the color palette #
for i in default_order
for p in palette
Expand All @@ -53,23 +73,51 @@ function all_subtypes(t::Type)
return [split(string(s), ".")[end] for s in st]
end

GR_DEFAULT = permutedims(getfield.(get_default_palette(), :color))
FUEL_DEFAULT = getfield.(get_palette(), :color)
PLOTLY_DEFAULT = getfield.(get_default_palette(), :RGB)
PLOTLY_FUEL_DEFAULT = getfield.(get_palette(), :RGB)
CATEGORY_DEFAULT = getfield.(get_palette(), :category)
function get_palette_gr(palette)
permutedims(getfield.(palette, :color))
end

function get_palette_fuel(palette)
getfield.(palette, :color)
end

function get_palette_plotly(palette)
getfield.(get_default_palette(palette), :RGB)
end

function get_palette_plotly_fuel(palette)
getfield.(palette, :RGB)
end

function get_palette_category(palette)
getfield.(palette, :category)
end

function get_palette_seriescolor(palette)
backend = Plots.backend()
return get_palette_seriescolor(backend, palette)
end

function get_palette_seriescolor(backend, palette)
return get_palette_gr(palette)
end

function get_palette_seriescolor(backend::Plots.PlotlyJSBackend, palette)
return get_palette_plotly(palette)
end

SUPPORTED_EXTRA_PLOT_KWARGS = [:linestyle, :linewidth]
SUPPORTED_PLOTLY_SAVE_KWARGS =
const SUPPORTED_EXTRA_PLOT_KWARGS = [:linestyle, :linewidth]
const SUPPORTED_PLOTLY_SAVE_KWARGS =
[:autoplay, :post_script, :full_html, :animation_opts, :default_width, :default_height]

function match_fuel_colors(data::DataFrames.DataFrame, backend)
function match_fuel_colors(data::DataFrames.DataFrame, backend; palette = PALETTE)
if backend == Plots.PlotlyJSBackend()
color_range = PLOTLY_FUEL_DEFAULT
color_range = get_palette_plotly_fuel(palette)
else
color_range = FUEL_DEFAULT
color_range = get_palette_fuel(palette)
end
color_fuel = DataFrames.DataFrame(fuels = CATEGORY_DEFAULT, colors = color_range)
color_fuel =
DataFrames.DataFrame(fuels = get_palette_category(palette), colors = color_range)
names = DataFrames.names(data)
default =
[(color_fuel[findall(in(["$(names[1])"]), color_fuel.fuels), :][:, :colors])[1]]
Expand Down
2 changes: 1 addition & 1 deletion src/plot_recipes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function _dataframe_plots_internal(
existing_colors = ones(length(plot.series_list))
seriescolor = permutedims(
set_seriescolor(
get(kwargs, :seriescolor, GR_DEFAULT),
get(kwargs, :seriescolor, get_palette_gr(get(kwargs, :palette, PALETTE))),
vcat(existing_colors, DataFrames.names(variable)),
)[(length(existing_colors) + 1):end],
)
Expand Down
2 changes: 1 addition & 1 deletion src/plotly_recipes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function _dataframe_plots_internal(
plot_length = length(traces)
seriescolor = permutedims(
set_seriescolor(
get(kwargs, :seriescolor, PLOTLY_DEFAULT),
get(kwargs, :seriescolor, get_palette_plotly(get(kwargs, :palette, PALETTE))),
vcat(ones(plot_length), names),
)[(plot_length + 1):end],
)
Expand Down
1 change: 1 addition & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ PowerSimulations = "e690365d-45e2-57bb-ac84-44ba829e73c4"
PowerSystemCaseBuilder = "f00506e0-b84f-492a-93c2-c0a9afc4364e"
PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
StorageSystemsSimulations = "e2f1a126-19d0-4674-9252-42b2384f8e3c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestSetExtensions = "98d24dd4-01ad-11ea-1b02-c9a08f80db04"
TimeSeries = "9e3dc215-6440-5c97-bce1-76c03772f85e"
Expand Down
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ using PowerGraphics
using PowerAnalytics
using PlotlyJS
using PowerSimulations
using StorageSystemsSimulations
using GLPK
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add HydroPowerSimulations.jl

using Weave
using TimeSeries
Expand Down
6 changes: 3 additions & 3 deletions test/test_data/results_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ function run_test_sim(result_dir::String)
@info "Reading results from last execution" sim
else
@info "Building UC system from"
c_sys5_hy_uc = PSB.build_system(PSB.SIIPExampleSystems, "5_bus_hydro_uc_sys")
c_sys5_hy_uc = PSB.build_system(PSB.PSISystems, "5_bus_hydro_uc_sys")
@info "Building ED system from"
c_sys5_hy_ed = PSB.build_system(PSB.SIIPExampleSystems, "5_bus_hydro_ed_sys")
c_sys5_hy_ed = PSB.build_system(PSB.PSISystems, "5_bus_hydro_ed_sys")

@info "Adding extra RE"
add_re!(c_sys5_hy_uc)
Expand Down Expand Up @@ -176,7 +176,7 @@ function run_test_sim(result_dir::String)
end

function run_test_prob()
c_sys5_hy_uc = PSB.build_system(PSB.SIIPExampleSystems, "5_bus_hydro_uc_sys")
c_sys5_hy_uc = PSB.build_system(PSB.PSISystems, "5_bus_hydro_uc_sys")
add_re!(c_sys5_hy_uc)
GLPK_optimizer =
optimizer_with_attributes(GLPK.Optimizer, "msg_lev" => GLPK.GLP_MSG_OFF)
Expand Down
28 changes: 28 additions & 0 deletions test/test_plot_creation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,34 @@ function test_plots(file_path::String; backend_pkg::String = "gr")
cleanup && rm(out_path, recursive = true)
end

@testset "test alternate mapping yamls" begin
# Alternate color palette makes curtailment hot pink
out_path = joinpath(file_path, backend_pkg * "_alternate_palette")
!isdir(out_path) && mkdir(out_path)

palette = PG.load_palette(joinpath(TEST_DIR, "test_yamls/color-palette.yaml"))

PG.plot_fuel(
results_uc,
set_display = set_display,
title = "fuel",
save = out_path,
bar = true,
generator_mapping_file = joinpath(
TEST_DIR,
"test_yamls/generator_mapping.yaml",
),
palette = palette,
)
list = readdir(out_path)
expected_files = ["fuel.png"]
@test isempty(setdiff(expected_files, list))
@test isempty(setdiff(list, expected_files))

@info "removing alternate test fuel outputs"
cleanup && rm(out_path, recursive = true)
end

@testset "test html saving" begin
plot_fuel(
results_ed,
Expand Down
Loading