From dceeae3808ee3511376ef42a06b561ce8813aa1c Mon Sep 17 00:00:00 2001 From: Hamish Graham <hgraham@hpc-201-11-01-a.cr.cnaf.infn.it> Date: Wed, 15 Sep 2021 10:48:21 +0200 Subject: [PATCH] update --- tree_maker/monitoring_sim.py | 109 ++++++++++++++++++++++++ tree_maker/pandas_skeleton.py | 155 ++++++++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 tree_maker/monitoring_sim.py create mode 100644 tree_maker/pandas_skeleton.py diff --git a/tree_maker/monitoring_sim.py b/tree_maker/monitoring_sim.py new file mode 100644 index 0000000..50a387a --- /dev/null +++ b/tree_maker/monitoring_sim.py @@ -0,0 +1,109 @@ +import pandas_skeleton as ps +import tree_maker as tm +from pandas import DataFrame + +from bokeh.layouts import column +from bokeh.models import ColumnDataSource, Slider, WheelZoomTool, BoxZoomTool, Button, PanTool +from bokeh.plotting import figure +from bokeh.themes import Theme +from bokeh.io import show, output_notebook +from bokeh.models import Select + +def bkapp(doc, root, last_key, my_dict): + """ + This creates an interactive plot showing a tree of jobs in a 'flower' shape. + """ + global my_df + global source + global this_df + global my_df_plot + + try: + ps.create_tree(root) + except: + raise Exception('Sorry, I need a root of a tree!') + + x_values, y_values, path = ps.create_xypath(root) + my_colors = ps.create_color(root) + angles = ps.create_tree_cartesian(root) + + my_df = ps.create_df(root, path, x_values, y_values, my_colors) + + del my_df['handle'] + + my_df_plot = my_df + + this_df = my_df.copy() + + final_status = my_dict['status'][-1] + + def callback(attr, _, index_list): + global my_df + global my_df_selected + global my_df_plot + source.data = ColumnDataSource.from_df(my_df_plot) + my_df_selected = my_df_plot.loc[index_list] + + def initialise(): + global my_df_plot + global my_df + my_df_plot = ps.update_color(this_df, my_dict, my_df) + my_df = ps.update_color(this_df, my_dict, my_df) + + def my_function(this_df, my_dict): + return my_dict['color'][my_dict['status'].index(this_df['status'])] + + def update_color(): + global my_df_plot + global my_df + ps.update_status(root) + this_df['status'] = ps.create_status(root) + this_df['color'] = this_df.apply(lambda x: my_function(x, my_dict), axis=1) + my_df = this_df + my_df_plot = this_df + + def update_color2(): + global my_df_plot + global my_df + ps.update_status(root) + this_df['status'] = ps.create_status(root) + this_df['color'] = this_df.apply(lambda x: my_function(x, my_dict), axis=1) + my_df = this_df + my_df_plot = this_df + source.data = ColumnDataSource.from_df(my_df_plot) + + update_color() + + source = ColumnDataSource(data=my_df_plot) + + TOOLTIPS = [ + ('index', "@index"), + ('status', "@status"), + ('path', "@path") +] + plot = figure(plot_width=400, plot_height=400, tools="lasso_select", title="Select Here", tooltips = TOOLTIPS) + plot.circle('x', 'y', source=source, alpha=0.6, size = 15, line_color="black", color = 'color') + plot.add_tools(BoxZoomTool(), WheelZoomTool(), PanTool()) + + source.selected.on_change('indices', callback) + + select = Select(title="Option:", value="plot", options=["full_df", f"{last_key}", f"not {last_key}"]) + + def callback1(attr, old, new): + global my_df_plot + if new == "full_df": + my_df_plot = my_df.copy() + if new == f"{last_key}": + my_df_plot = my_df[my_df.status == last_key].copy() + if new == f"not {last_key}": + my_df_plot = my_df[my_df.status != last_key].copy() + my_df_plot.reset_index(drop=True, inplace=True) + source.data = ColumnDataSource.from_df(my_df_plot) + + select.on_change('value', callback1) + + button = Button(label="Update", button_type="success") + + button.on_click(update_color2) + + doc.add_root(column(plot, button, select)) \ No newline at end of file diff --git a/tree_maker/pandas_skeleton.py b/tree_maker/pandas_skeleton.py new file mode 100644 index 0000000..007216a --- /dev/null +++ b/tree_maker/pandas_skeleton.py @@ -0,0 +1,155 @@ +import tree_maker as tm +import numpy as np +import math +import random +from anytree import AnyNode, RenderTree +import numpy as np +import json +import pandas as pd + +def create_tree(node): + """ + Creates a tree with the shape of a 'flower'. The nodes that have attributes; x, y, ragius, short_path, angle, min_angle, max_angle and color. + """ + if node.is_leaf: + pass + else: + if node.is_root: + node.x = 0 + node.y = 0 + node.radius = 0 + #node.min_x = -2 + #node.max_x = 2 + node.short_path = '/'.join(node.path.split('/')[-3:]) + node.angle = 2 * math.pi + node.min_angle = 0 + node.max_angle = 2 * math.pi + node.color = 'black' + for my_child, my_angle in zip(node.children, np.linspace(node.min_angle , node.max_angle, (len(node.children)+1))): + #my_child.min_x = xx - (node.max_x - node.min_x)/len(node.children)/2 + #my_child.max_x = xx + (node.max_x - node.min_x)/len(node.children)/2 + my_child.color = "black" + my_child.short_path = '/'.join(my_child.path.split('/')[-3:]) + my_child.angle = my_angle + my_child.min_angle = my_angle - (node.max_angle - node.min_angle)/len(node.children)/2 + my_child.max_angle = my_angle + (node.max_angle - node.min_angle)/len(node.children)/2 + my_child.radius = node.radius + 1 + my_child.x = my_child.radius * math.cos(my_angle) + my_child.y = my_child.radius * math.sin(my_angle) + create_tree(my_child) + + +def create_xypath(node): + """ + Creates a list for x_values and y_values for the nodes of a tree. + """ + x_values = [node.x] + y_values = [node.y] + path = [node.short_path] + for descendant in node.descendants: + x_values.append(descendant.x) + y_values.append(descendant.y) + path.append(descendant.short_path) + return x_values, y_values, path + +def get_status(handle): + """ + Returns last key, the status of the job, from 'log_file'. Incase of an empty log_file, 'None' is returned. + """ + keys = list(tm.from_json(handle.get_abs('path')+'/'+handle.log_file)) + if len(keys) > 0: + return keys[-1] + else: + return None + + +def update_status(node): + if node.is_leaf: + pass + else: + if node.is_root: + node.status = get_status(node) + for my_child in node.children: + my_child.status = get_status(my_child) + update_status(my_child) + + +def create_status(node): + my_status = [node.status] + for descendant in node.descendants: + my_status.append(descendant.status) + return my_status + + +def update_color(): + global my_df_plot + global my_df + update_status(root) + create_status(root) + this_df['color'] = this_df.apply(lambda x: my_function(x, my_dict), axis=1) + my_df = this_df + my_df_plot = this_df + +def create_color(node): + """ + Adds colors of nodes to an array. + """ + my_colors = [node.color] + for descendant in node.descendants: + my_colors.append(descendant.color) + return my_colors + +def create_tree_cartesian(node): + """ + Adds the angle attribute to an array. + """ + angles = [node.angle] + for descendant in node.descendants: + angles.append(node.angle) + return angles + + +def create_df(node, path, x_values, y_values, my_colors): + """ + Creating a dataframe and its attributes. Here its attributes are; node, path, x_values, y_values and my_colors. + """ + my_df = pd.DataFrame([node]+list(node.descendants), columns=['handle']).copy() + my_df['name'] = my_df['handle'].apply(lambda x:x.name) + my_df['path'] = path + my_df['x'] = x_values # to check the order + my_df['y'] = y_values # to check the order + my_df['status'] = my_df['handle'].apply(get_status) + my_df['color'] = my_colors + return my_df + +def update(my_df, last_key, my_color, status_df): + """ + Filtering through the dataframe using the 'last_key'. The color that is connected to this 'last_key', can also be chosen. + """ + new_df1 = my_df[(my_df.status == last_key)].copy() + #new_df1['color'] = new_df1.apply(my_function) + new_df1['color'] = 'green' + new_df2 = my_df[(my_df.status != last_key)].copy() + my_df = pd.concat([new_df1, new_df2]).sort_index() + #print(status_df) + return my_df + +def update2(my_df, status_df): + """ + Filtering through the dataframe using the 'last_key'. The color that is connected to this 'last_key', can also be chosen. + """ + #new_df1 = my_df[(my_df.status == last_key)].copy() + for row in status_df.loc[0:len(status_df)]: + my_df['color'] = status_df.loc[row]['color'] + my_df['status'] = status_df.loc[row]['color'] + return my_df + +def my_function(my_df, my_dict): + global this_df + this_df = my_df.copy() + return my_dict['color'][my_dict['status'].index(this_df['status'])] + +#def update_color(this_df, my_dict, my_df): +# this_df['color'] = this_df.apply(lambda x: my_function(x, my_dict), axis=1) +# my_df = this_df +# return my_df \ No newline at end of file -- GitLab