CEA Plugins - Part 2: Anatomy of a CEA plugin
Let’s take a bird’s-eye view of the parts that make up a CEA plugin. We’ll cover the interface expected by the CEA when you define a plugin as well as it’s default implementation: cea.plugin.CeaPlugin
.
If you’d rather just start with an example and tinker from there, skip to Part 3: Introduction to the CEA plugin template and come back here if you have any questions.
This is part 2 in a series of articles on CEA plugins:
-
Part 2: Anatomy of a CEA plugin (this article)
Anatomy of a CEA plugin
The CEA maintains a list of plugins in the config.plugins
list, stored in the Configuration file by fully qualified class name under general:plugins
. Fully qualified class name means: The whole “path” to the class, including the packages and module. The cea.config.Configuration
class uses those class names to instantiate plugin objects at runtime.
This leads to a first observation: A CEA plugin is a class that can be instantiated without arguments.
Each plugin is expected to expose the following fields:
scripts
: Adict
containing the definitions of the tools provided by the plugin (in the same shape ascea/scripts.yml
)plot_categories
: A list ofcea.plots.categories.PlotCategory
instancesschemas
: Adict
containing the definitions of the input and output files added by the plugin (in the same shape ascea/schemas.yml
)config
: aconfigparser.ConfigParser
instance containing the definitions of the parameters provided by the plugin (in the same format ascea/default.config
)
In addition, the __str__()
method is expected to return the fully qualified name of the plugin class - this is used to save the list of plugins to the config file. The class cea.plugin.CeaPlugin
would therefore return "cea.plugin.CeaPlugin"
This may sound like a lot to implement, but in practice, creating a CEA plugin is as easy as subclassing cea.plugin.CeaPlugin
and filling out some files - this is due to the default implementation of these fields as properties of CeaPlugin
.
scripts
The default implementation of the scripts
property will read a scripts.yml
file in the same folder as the class is defined in and return that.
The scripts.yml
file is optional. If you don’t provide one, then your plugin does not provide any scripts.
See Part 3: Introduction to the CEA plugin template for an in-depth look at the contents of such a file - or browse the cea/scripts.yml
file that defines the CEA core scripts on GitHub.
plot_categories
Each plot in the CEA is part of a category - this is represented internally by the cea.plots.categories.PlotCategory
class and exploses the property plots
to list all the plot classes in that category. See the Gory Details for the full story. You could implement this list yourself, but the default implementation will make your life much, much easier:
The default implementation reads a plots.yml
file in the same folder as the class is defined in and builds subclasses of cea.plugin.PluginPlotBase
automatically.
See Part 5: How to add your own plots to the CEA for a full explaination of how to write a plots.yml
file.
The plots.yml
file is optional. If you don’t provide one, then your plugin does not provide any plots
NOTE: If the plots.yml
mechanism is too simplistic, you can override this property to get the full power of CEA plotting.
schemas
The default implementation of the schemas
property will read a schemas.yml
file in the same folder as the class is defined in an return that.
The format is the exact same format as used by the cea: cea/schemas.yml
.
Any locator methods defined in your plugin’s schemas.yml
file will be added as methods to the cea.inputlocator.InputLocator
class at runtime. In addition, for csv, dbf and shapefiles, the locator method will support read()
and write()
to load and save Dataframes to disk. Some examples:
config = cea.config.Configuration()
locator = cea.inputlocator.InputLocator(scenario=config.scenario, plugins=config.plugins)
locator.get_zone_geometry()
Out[4]: u'c:\\project\\scenario\\inputs\\building-geometry\\zone.shp'
zone_df = locator.get_zone_geometry.read()
zone_df.Name
Out[7]:
0 B1000
1 B1001
2 B1002
3 B1003
4 B1004
5 B1005
Name: Name, dtype: object
The path denoted by the locator method definitions is given by the field file_path
. This is a string using forward slashes (/
) to separate path names, relative to the current scenario. You can embedd variables in this string using the syntax {varname}
and the InputLocator will replace those variables with keyword arguments provided when calling either the locator method itself or the read
and write
methods.
The schemas.yml
file is optional. If you don’t provide one, then your plugin does not provide any input and output files - this could be the case for a plugin that only provides new plots to data already provided by the CEA core.
config
The default implementation of the config
property will read a plugin.config
file in the same folder as the class is defined in and return it as a configparser.ConfigParser
object.
See Configuration File Details for more information on how to set this up.
The plugin.config
file is optional. If you don’t provide one, then your plugin does not provide any additional parameters to the ones provided by the CEA core.
Summary
The default implementation of the cea.plugin.CeaPlugin
class does most of the heavy lifting for you. This leaves you to focus on the content of your plugin: The scripts and plots.
To create your own plugin, you should therefore start with something like this:
import cea.plugin
class MyPlugin(cea.plugin.CeaPlugin):
pass
This is already a valid plugin, although one that doesn’t really do much - adding the files mentioned above (scripts.yml
, plots.yml
, schemas.yml
and plugin.config
) will automatically add functionality to your plugin.
A good starting point is the CEA plugin template repository on GitHub - read all about that in Part 3: Introduction to the CEA plugin template!