#!/usr/bin/python # lint:ok
# -*- coding: utf-8
import matplotlib.pyplot as plt
import pandas as pd
import logging
[docs]class stackplot:
r''' Creates a plot around a bus with all inputs as bar plots and all
outputs as lineplots.
Parameters
----------
plot_dc : dictionary of pandas.DataFrame
A dictionary with the keys 'in' and 'out' containing a DataFrame with
all input time series ('in') and all output time series 'out'.
es : oemof.core.EnergySystem object
An EnergySystem object containing a results dictionary.
Attributes
----------
plot_dc : dictionary of pandas.DataFrame
A dictionary with the keys 'in' and 'out' containing a DataFrame with
all input time series ('in') and all output time series 'out'.
es : oemof.core.EnergySystem object
An EnergySystem object containing a results dictionary.
Note
----
The EnergySystem object needs to have a results dictionary.
'''
# TODO: Check if EnergySystem contains a results dictionary!
# TODO: Option to remove empty time series from legend(e.g. unused storage)
# TODO: Combine legends in a combined plot and keep only the lowest x-axis.
# TODO: Default naming for title, axis...
# TODO: Passing kwargs to 'bar' or 'line' plot but not both (e.g. lw=4).
# TODO: Set order of columns to plot
# TODO: Sink has to be the lowest line but plotted on top.
def __init__(self, **kwargs):
self.plot_dc = kwargs.get('plot_dc', {})
self.es = kwargs.get('es')
[docs] def create_io_df(self, uid):
r'''Create a dictionary of DataFrames containing all time series around
a bus.
The returned dictionary has two keys ('in', 'out') that contain the
DataFrame of the incoming and outgonig flows of the bus.
Parameters
----------
uid : string or tuple
The uid of the bus, that should be plotted
Returns
-------
dictionary : Dicionary of DataFrames
'''
logging.debug('Getting bus for uid: {0}'.format(uid))
bus = [obj for obj in self.es.entities if obj.uid == uid][0]
index = pd.date_range(pd.datetime(self.es.year, 1, 1, 0, 0),
pd.datetime(self.es.year, 12, 31, 23, 0),
freq='H')
tmp_dc = {}
tmp_dc['in'] = pd.DataFrame()
tmp_dc['out'] = pd.DataFrame()
logging.debug(
'Creating DataFrame for all inputs of bus: {0}'.format(bus))
for entity in bus.inputs:
tmp_dc['in'][entity.uid] = pd.Series(self.es.results[entity][bus],
index=index)
logging.debug(
'Creating DataFrame for all outputs of bus: {0}'.format(bus))
for entity in bus.outputs:
tmp_dc['out'][entity.uid] = pd.Series(self.es.results[bus][entity],
index=index)
return tmp_dc
[docs] def create_fig(self, figw=24, figh=14, fontl=14, fontg=19):
r'''Creating a matplotlib figure object.
Parameters
----------
figw : float or int
Width of the figure object (default: 24).
figh : float or int
Height of the figure object (default: 14).
fontg : float or int
General font size within the plot (default: 19).
fontl : float or int
Font size of the legend (default: 14).
'''
fig = plt.figure(figsize=(figw, figh))
plt.rcParams.update({'font.size': fontg})
plt.rc('legend', **{'fontsize': fontl})
return fig
[docs] def core(self, eid, ax, kind, prange, **kwargs):
r'''Plotting a DataFrame of the dictionary.
Parameters
----------
eid : str
The key of the plot_dc dictionary.
ax : matplotlib artist object
If an artist object is passed the plot will be added to this artist
object.
kind : string
The type of the plot ('bar', 'line', ...). See the pandas plot
documentation for more information.
prange : range of the pandas index
The range of the pandas.DataFrame to be plotted. The range should
be of the same time a the DataFrame index.
Returns
-------
matplotlib artis object
'''
logging.debug('Plotting from {0} to {1}.'.format(prange[0],
prange[-1]))
df_slice = self.plot_dc[eid].loc[prange].reset_index(
drop=True)
logging.debug('Creating a {0}-plot.'.format(kind))
return df_slice.plot(kind=kind, stacked=True, ax=ax, **kwargs)
[docs] def full(self, prange, **kwargs):
r'''Create a full plot of a valid plot_dc dictionary
Parameters
----------
prange : range of the pandas index
The range of the pandas.DataFrame to be plotted. The range should
be of the same time a the DataFrame index. The DataFrames are part
of the plot_dc dictionary with the keys 'in' and 'out'.
\**kwargs : keyword arguments
Additional arguments to be passed to the plotting command.
'''
fig = self.create_fig()
ax = fig.add_subplot(1, 1, 1)
self.part(prange, ax, **kwargs)
[docs] def part(self, prange, ax, **kwargs):
r'''Create a part of plot within an existing artist object using a
valid plot_dc dictionary.
Parameters
----------
prange : range of the pandas index
The range of the pandas.DataFrame to be plotted. The range should
be of the same time a the DataFrame index. The DataFrames are part
of the plot_dc dictionary with the keys 'in' and 'out'.
ax : matplotlib artist object
The new plot will be added to this artist object.
\**kwargs : keyword arguments
Additional arguments to be passed to the plotting command.
'''
in_color = None
if kwargs.get('out_color') is not None:
logging.debug('Using an own color set for "out": {0}'.format(
kwargs.get('out_color')))
kwargs['color'] = kwargs.pop('out_color')
logging.debug('Using an own color set for "in": {0}'.format(
kwargs.get('in_color')))
in_color = kwargs.pop('in_color')
ax = self.core('out', ax, 'line', prange, linewidth=2, **kwargs)
if in_color is not None:
kwargs['color'] = in_color
ax = self.core('in', ax, 'bar', prange, width=1, linewidth=0, **kwargs)
# Shrink current axis by 20%
handles, labels = ax.get_legend_handles_labels()
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
# Put a legend to the right of the current axis
ax.legend(reversed(handles), reversed(labels), loc='center left',
bbox_to_anchor=(1, 0.5), ncol=1, fancybox=True,
shadow=True)
fg = pd.date_range(pd.datetime(2010, 6, 1, 0, 0),
periods=168, freq='H')
labels = fg[0::24].format(formatter=lambda x: x.strftime(
'%d.%m.-%H:%M'))
ticks = list(range(len(fg)))[0::24]
ax.set_xticks(ticks)
ax.set_xticklabels(labels, rotation=10)