Commit cd154513 authored by hazrmard's avatar hazrmard
Browse files

added code for animated plots of dataframes

parent 6a1f1eef
Loading
Loading
Loading
Loading
+7 −3
Changes for src/ioops.py: 7 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -67,10 +67,14 @@ def xlsx_to_csv(xlsx: str):
if __name__ == '__main__':
    import sys
    from glob import glob
    from argparse import ArgumentParser

    default = [abspath(join(os.environ.get('DATADIR', './'),
                            'EngineeringScienceBuilding', 'Chillers.xlsx'))]
    paths = sys.argv[2:] if len(sys.argv) >= 3 else default
    for arg in paths:
        for xl in glob(arg):
    parser = ArgumentParser()
    parser.add_argument("paths", help="Excel files to convert.", default=default,
                        nargs='*')
    args = parser.parse_args()
    for path in args.paths:
        for xl in glob(path):
            xlsx_to_csv(xl)

src/plotting.py

0 → 100644
+89 −0
Changes for src/plotting.py: 89 added lines, 0 removed lines.
Original line number Diff line number Diff line
"""
Specialized plot operations for data frames.
"""

from typing import Iterable, Tuple, Dict, Any

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

def animate_dataframes(frames: Iterable[pd.DataFrame], ax: plt.Axes,
                       lseries: Iterable[str], rseries: Iterable[str]=(),
                       xlim: Tuple[float]=None, ylim: Tuple[float]=None,
                       xlabel: str='', ylabel: str='', labels: Iterable[str]=None,
                       xscale: str='linear', yscale: str='linear', legend: bool=True,
                       anim_args: Dict[str, Any]={}) \
                       -> FuncAnimation:
    """
    Make an animated line plot from a list of DataFrames.

    Args:
    * `frames`: A list of DataFrames to plot,
    * `ax`: The axis on which to animate,
    * `lseries`: List of column names to plot on the left,
    * `rseries`: List of column names to plot on the right,
    * `xlim, ylim`: Tuples of min/max axis values,
    * `xlabel, ylabel`: String names of each axis. If `rseries` provided, ylabel
    must be a tuple of two labels,
    * `labels`: Iterable of string labels for each frame,
    * `xscale, yscale`: Axis scales ('log' etc.). If `rseries` provided, yscale
    must be a tuple of two strings,
    * `legend`: Whether to show legend on plot.
    * `anim_args`: A dictionary of arguments to pass to `matplotlib.animation.FuncAnimation`
    class.
    """
    # generate defaults
    if ylim is None:
        min1 = min(f[lseries].values.min() for f in frames)
        max1 = max(f[lseries].values.max() for f in frames)
        if rseries:
            min2 = min(f[rseries].values.min() for f in frames)
            max2 = max(f[rseries].values.max() for f in frames)
            ylim = ((min1, max1), (min2, max2))
        else:
            ylim = ((min1, max1),)
    elif isinstance(ylim, Iterable):
        if len(ylim) == 2 and not all(map(lambda x: isinstance(x, Iterable), ylim)):
            ylim = (ylim, ylim)
    
    if xlim is None:
        xlim = (min(f.index.values.min() for f in frames),
                max(f.index.values.max() for f in frames))
    
    if not rseries:
        ylabel = (ylabel,)
        yscale = (yscale,)

    # set up figure and axes
    fig = ax.get_figure()
    ax1 = ax        # left axis
    ax1.set(ylabel=ylabel[0], yscale=yscale[0], ylim=ylim[0],
            xlabel=xlabel, xscale=xscale, xlim=xlim)
    fig.autofmt_xdate()
    if rseries:     # right axis
         ax2 = ax1.twinx()
         ax2.set(ylabel=ylabel[1], yscale=yscale[1], ylim=ylim[1])

    lines1 = [ax1.plot([], [], label=s)[0] for s in lseries]
    lines2 = [ax2.plot([], [], label=s)[0] for s in rseries]

    if legend:
        ax1.legend(lines1+lines2, (*lseries, *rseries), loc='upper right')
    
    # define animation start and frames
    def init_func():
        return (*lines1, *lines2)
    
    def plot_func(i):
        frame = frames[i]
        if labels is not None:
            ax1.set_title(labels[i])
        for lines, series in zip((lines1, lines2), (lseries, rseries)):
            for line, s in zip(lines, series):
                line.set_data(frame.index, frame[s])
        return (*lines1, *lines2)

    anim = FuncAnimation(fig, func=plot_func, frames=len(frames),
                         init_func=init_func, **anim_args)
    return anim
+12 −4
Changes for src/preprocess.py: 12 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -146,16 +146,24 @@ def calculate_derivative_fields(df: pd.DataFrame) -> pd.DataFrame:

if __name__ == '__main__':
    import os
    from os.path import abspath, join, dirname
    from os.path import abspath, join
    import sys
    from glob import glob
    from argparse import ArgumentParser

    default = [abspath(join(os.environ.get('DATADIR', './'),
                            'EngineeringScienceBuilding', 'Chillers.csv'))]
    paths = sys.argv[2:] if len(sys.argv) >= 3 else default
    for arg in paths:
        for csv in glob(arg):
    parser = ArgumentParser()
    parser.add_argument("paths", help="CSV files to preprocess.", default=default,
                        nargs='*')
    parser.add_argument('--keep_zeros', help='Keep rows with 0 power values.',
                        action='store_true', default=False)
    args = parser.parse_args()

    for path in args.paths:
        for csv in glob(path):
            df = pd.read_csv(csv, index_col='Time', parse_dates=True, dtype=float)
            if not args.keep_zeros:
                df = drop_missing_rows(df)
            df = standardize(df)
            df = fill_missing_temperatures(df)