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

Add line plots #325

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
3 changes: 1 addition & 2 deletions post-processing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,11 @@ pip install -e .[post-processing]
#### Command line

```sh
python post_processing.py log_path config_path [-p plot_type]
python post_processing.py log_path config_path
```

- `log_path` - Path to a perflog file, or a directory containing perflog files.
- `config_path` - Path to a configuration file containing plot details.
- `plot_type` - (Optional.) Type of plot to be generated. (`Note: only a generic bar chart is currently implemented.`)

Run `post_processing.py -h` for more information (including debugging and file output flags).

Expand Down
18 changes: 16 additions & 2 deletions post-processing/config_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def __init__(self, config: dict, template=False):
config = read_config(config)

# extract config information
self.plot_type = config.get("plot_type")
self.title = config.get("title")
self.x_axis = config.get("x_axis")
self.y_axis = config.get("y_axis")
Expand Down Expand Up @@ -60,6 +61,7 @@ def from_template(self):
"""

return self(dict({
"plot_type": None,
"title": None,
"x_axis": {"value": None, "units": {"custom": None}},
"y_axis": {"value": None, "units": {"custom": None}, "scaling": {"custom": None}},
Expand Down Expand Up @@ -191,6 +193,7 @@ def to_dict(self):
"""

return dict({
"plot_type": self.plot_type,
"title": self.title,
"x_axis": self.x_axis,
"y_axis": self.y_axis,
Expand Down Expand Up @@ -237,6 +240,13 @@ def read_config(config: dict):
config: dict, plot configuration information.
"""

# check plot_type information
plot_type = config.get("plot_type")
if not plot_type:
raise KeyError("Missing plot type information.")
elif (plot_type != 'generic') and (plot_type != 'line'):
raise RuntimeError("plot_type must be one of: 'generic', 'line'")
connoraird marked this conversation as resolved.
Show resolved Hide resolved

# check plot title information
if not config.get("title"):
raise KeyError("Missing plot title information.")
Expand Down Expand Up @@ -280,8 +290,12 @@ def read_config(config: dict):

# check optional series information
if config.get("series"):
if len(config.get("series")) == 1:
raise RuntimeError("Number of series must be >= 2.")
if plot_type == 'generic':
if len(config.get("series")) == 1:
raise RuntimeError("Number of series must be >= 2 for generic plot.")
if plot_type == 'line':
if len(config.get("series")) < 1:
raise RuntimeError("Number of series must be >= 1 for line plot.")
if len(set([s[0] for s in config.get("series")])) > 1:
raise RuntimeError("Currently supporting grouping of series by only one column. \
Please use a single column name in your series configuration.")
Expand Down
71 changes: 71 additions & 0 deletions post-processing/plot_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,77 @@
from bokeh.plotting import figure, output_file, save
from bokeh.transform import factor_cmap
from titlecase import titlecase
import itertools

def plot_line_chart(title, df: pd.DataFrame, x_axis, y_axis, series_filters):
"""
Create a line chart for the supplied data using bokeh.

Args:
title: str, plot title.
df: dataframe, data to plot.
x_axis: dict, x-axis column and units.
y_axis: dict, y-axis column and units.
series_filters: list, x-axis groups used to filter graph data.
"""
# get column names and labels for axes
x_column, x_label = get_axis_labels(df, x_axis, series_filters)
y_column, y_label = get_axis_labels(df, y_axis, series_filters)

# adjust axis ranges
min_y = (0 if min(df[y_column]) >= 0
else math.floor(np.nanmin(df[y_column])*1.2))
max_y = (0 if max(df[y_column]) <= 0
else math.ceil(np.nanmax(df[y_column])*1.2))
connoraird marked this conversation as resolved.
Show resolved Hide resolved
min_x = (0 if min(df[x_column]) >= 0
else math.floor(np.nanmin(df[x_column])*1.2))
max_x = (0 if max(df[x_column]) <= 0
else math.ceil(np.nanmax(df[x_column])*1.2))
connoraird marked this conversation as resolved.
Show resolved Hide resolved

# create html file to store plot in
output_file(filename=os.path.join(
Path(__file__).parent, "{0}.html".format(title.replace(" ", "_"))), title=title)

# create plot
plot = figure(x_range=(min_x, max_x), y_range=(min_y, max_y), title=title,
width=800, toolbar_location="above")

# configure tooltip
plot.add_tools(HoverTool(tooltips=[
(y_label, "@{0}".format(y_column)
+ ("{%0.2f}" if pd.api.types.is_float_dtype(df[y_column].dtype)
else ""))],
formatters={"@{0}".format(y_column): "printf"}))

# create legend outside plot
plot.add_layout(Legend(), "right")

colours = itertools.cycle(viridis(len(series_filters)))

for filter in series_filters:
filtered_df = None
if filter[1] == '==':
filtered_df = df[df[filter[0]] == int(filter[2])]
plot.line(x=x_column, y=y_column, source=filtered_df, legend_label=' '.join(filter), line_width=2, color=next(colours))

# add labels
plot.xaxis.axis_label = x_label
plot.yaxis.axis_label = y_label
# adjust font size
plot.title.text_font_size = "15pt"

# flip x-axis if sort is descending
if x_axis.get("sort"):
if x_axis["sort"] == "descending":
end = plot.x_range.end
start = plot.x_range.start
plot.x_range.start = end
plot.x_range.end = start

# save to file
save(plot)

return plot


def plot_generic(title, df: pd.DataFrame, x_axis, y_axis, series_filters, debug=False):
Expand Down
17 changes: 9 additions & 8 deletions post-processing/post_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import pandas as pd
from config_handler import ConfigHandler
from perflog_handler import PerflogHandler
from plot_handler import plot_generic
from plot_handler import plot_generic, plot_line_chart


class PostProcessing:
Expand Down Expand Up @@ -73,9 +73,14 @@ def run_post_processing(self, config: ConfigHandler):

# call a plotting script
if self.plotting:
self.plot = plot_generic(
config.title, self.df[self.mask][config.plot_columns],
config.x_axis, config.y_axis, config.series_filters, self.debug)
if config.plot_type == 'generic':
self.plot = plot_generic(
config.title, self.df[self.mask][config.plot_columns],
config.x_axis, config.y_axis, config.series_filters, self.debug)
elif config.plot_type == 'line':
self.plot = plot_line_chart(
config.title, self.df[self.mask][config.plot_columns],
config.x_axis, config.y_axis, config.series_filters)

# FIXME (#issue #255): maybe save this bit to a file as well for easier viewing
if self.debug & self.verbose:
Expand Down Expand Up @@ -416,10 +421,6 @@ def read_args():
parser.add_argument("config_path", type=Path,
help="path to a configuration file specifying what to plot")

# optional argument (plot type)
parser.add_argument("-p", "--plot_type", type=str, default="generic",
help="type of plot to be generated (default: 'generic')")

# info dump flags
parser.add_argument("-d", "--debug", action="store_true",
help="debug flag for printing additional information")
Expand Down
8 changes: 8 additions & 0 deletions post-processing/streamlit_post_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ def update_ui(post: PostProcessing, config: ConfigHandler, e: 'Exception | None'
# config file uploader
st.file_uploader("Upload Config", type="yaml", key="uploaded_config", on_change=update_config)

# set plot type
plot_type_options = ['generic', 'line']
plot_type_index = plot_type_options.index(config.plot_type) if config.plot_type else None
connoraird marked this conversation as resolved.
Show resolved Hide resolved
plot_type = st.selectbox("#### Plot type", plot_type_options,
key="plot_type", index=plot_type_index)
if plot_type != config.plot_type:
config.plot_type = plot_type

# set plot title
title = st.text_input("#### Title", config.title, placeholder="None")
if title != config.title:
Expand Down
Loading