This document describes how to use switch graph
and switch compare
as well as
how to make new graphs.
Run switch graph
in your scenario folder, this will create a graphs
folder containing
graphs. For more options, run switch graph --help
.
Run switch compare <path_to_scenario_1> <path_to_scenario_2> <path_to_scenario_3> ...
. This will create a folder with
comparison graphs. For example, if you run
switch compare storage ca_policies
while in the /examples
folder, a new folder
called compare_storage_to_ca_policies
will be created with comparison graphs (this assumes both storage
and ca_policies
have already been solved).
New graphs can be added with the @graph(...)
annotation.
from switch_model.tools.graph import graph
@graph(
name="my_custom_graph",
title="An example plot",
note="Some optional note to add below the graph",
# Other options are possible see code documentation
)
def my_graphing_function(tools):
# Your graphing code
...
In my_graphing_function()
you can use the tools
object to create graphs. Here are some important methods.
-
tools.get_dataframe(filename)
will return a pandas dataframe for the file calledfilename
. You can also specifyfrom_inputs=True
to load a csv from the inputs directory. -
tools.get_axes()
ortools.get_figure()
will return a matplotlib axes or figure that should be used while graphing. When possible, always useget_axes
instead ofget_figure
since this allows plots from different scenarios to share the same figure. -
tools.save_figure(fig)
. Some libraries (e.g. plotnine) always generate their own figures. In this case we can add the figure to our outputs with this function. When possible, usetools.get_axes()
instead. -
tools.pd
,tools.sns
,tools.np
,tools.mplt
,tools.pn
are references to the pandas, seaborn, numpy, matplotlib and plotnine graphing libraries. This is useful if your graphing code needs to access these libraries since it doesn't require adding an import to your file. -
tools.transform
is a reference to aTransformTools
object that provides useful helper methods for modyfing a dataframe for graphing. Full documentation can be found in theTransformTools
class but some examples include.-
tools.transform.build_year(df)
which will convert build years that aren't a period to the stringPre-existing
. -
tools.transform.gen_type(df)
which adds a column calledgen_type
to the dataframe.gen_type
is a user-friendly name for the technology (e.g. Nuclear instead of Uranium) and is determined using the mappings ininputs/graph_tech_types.csv
. -
tools.transform.timestamp(df)
: which adds columns such as the hour, the timestamp in datetime format in the correct timezone, etc. -
tools.transform.load_zone(df)
: Adds a column called 'region' to the dataframe which normally corresponds to the load zone state.
-
-
tools.get_colors()
returns a mapping ofgen_type
to its color. This is useful for graphing and can normally be passed straight tocolor=
in standard plotting libraries. The color mapping is based oninputs/graph_tech_colors.csv
.
Sometimes you may want to create graphs that compare data from multiple scenarios.
To do this, add supports_multi_scenario=True
inside the @graph()
decorator.
from switch_model.tools.graph import graph
@graph(
name="my_custom_comparison_graph",
title="My Comparison plot",
supports_multi_scenario=True,
# Instead of supports_multi_scenario, you can use
# requires_multi_scenario if you want the graphing function
# to *only* be run when we have multiple scenarios.
# requires_multi_scenario=True,
)
def my_graphing_comparison_function(tools):
# Read data from all the scenarios
df = tools.get_dataframe("some_file.csv")
# Plot data
...
Now everytime you call tools.get_dataframe(filename)
, data for all the scenarios
gets returned. The way this works is that the
returned dataframe will contain a column called scenario_name
to indicate which rows correspond to which scenarios.
You can then use this column to create a graph comparing the different scenarios (still
using tools.get_axes
).
At this point, when you run switch compare
, your my_graphing_comparison_function
function will be called and your comparison graph
will be generated.
In this example we create a graph that shows the power capacity during each period broken down by technology.
from switch_model.tools.graph import graph
@graph(
"capacity_per_period",
title="Capacity per period"
)
def graph(tools):
# Get a dataframe of gen_cap.csv
df = tools.get_dataframe("gen_cap.csv")
# Add a 'gen_type' column to your dataframe
df = tools.transform.gen_type(df)
# Aggregate the generation capacity by gen_type and PERIOD
df = df.pivot_table(
index='PERIOD',
columns='gen_type',
values='GenCapacity',
aggfunc=tools.np.sum,
fill_value=0 # Missing values become 0
)
# Plot
df.plot(
kind='bar',
ax=tools.get_axes(),
stacked=True,
ylabel="Capacity Online (MW)",
xlabel="Period",
color=tools.get_colors(len(df.index))
)
Running switch graph
would run the graph()
function above and create
capacity_per_period.png
containing your plot.
Running switch compare
would create capacity_per_period.png
containing
your plot side-by-side with the same plot but for the scenario you're comparing to.
To test your graphs, you can run switch graph
or switch compare
. However,
this takes quite some time. If you want to test just one graphing function
you can run switch graph/compare -f FIGURE
. This will run only the graphing function
you've defined. Here FIGURE
should be the name of the graph (the first
argument in @graph()
, so capacity_per_period
in the example above).
Sometimes you may want to create graphs but don't want to permently add them to the switch code. To do this create the following Python file anywhere on your computer.
from switch_model.tools.graph import graph
from switch_model.tools.graph.cli_graph import main as graph
@graph(
...
)
def my_first_graph(tools):
...
@graph(
...
)
def my_second_graph(tools):
...
if __name__=="__main__":
graph(["--ignore-modules-txt"])