Source code for viswaternet.drawing.unique

# -*- coding: utf-8 -*-
"""
The viswaternet.drawing.unique module handles custom data, excel data, and
unique data drawing.
"""
import matplotlib.pyplot as plt
import pandas as pd
from viswaternet.network import processing
from viswaternet.utils import convert_excel, save_fig, unit_conversion
from viswaternet.drawing import base
from viswaternet.drawing import discrete


[docs]def plot_unique_data( self, ax=None, parameter=None, parameter_type=None, data_type=None, data_file=None, excel_columns=None, custom_data_values=None, unit=None, intervals="automatic", num_intervals=5, label_list=None, vmin=None, vmax=None, draw_nodes=False, discrete_legend_title=None, savefig=False, save_name=None, color_bar_title=None, element_size_intervals=None, element_size_legend_title=None, element_size_legend_loc=None, element_size_legend_labels=None, disable_interval_deleting=True, style=None): """A complex function that accomplishes tasks relating to categorical data, or 'unique' as used in viswaternet, as well as data not retrieved from WNTR. There are three distinct modes of operation, and which one is used is controlled by the 'parameter' argument, which differs from previous use of the argument. Setting the parameter argument to 'demand_patterns', 'diameter', or 'roughness' simply plots that parameter. These parameters are treated differently from others because in usually they are categorical. For instance, pipe diameters are not randomly chosen, and instead are chosen from a list of standard pipe sizes. When the parameter argument is set to 'excel_data', the function deals with excel data, or data imported from an .xlsx file. Two excel columns with elements and data pairs are provided by the user, which are then converted into a format usable by viswaternet for plotting. When the parameter argument is set to 'custom_data', the function deals with data directly inside of python. The user should expect to format the data themselves, although this shouldn't be difficult. An example of 'custom_data' being used can be seen in example 10 located in the github repository. Arguments --------- ax : axes._subplots.AxesSubplot Matplotlib axes object. parameter : string Should be set to 'demand_patterns', 'diameter', 'roughness', 'custom_data' or 'excel_data'. parameter_type : string Type of parameter (nodal, link) data_type : string The type of data that the excel data is (Unique, continuous, or discrete.) data_file : string excel_columns : array-like Two values should be provided: The first should be the excel column that contains element names. Column A in excel is considered the 0th column for use with viswaternet. The second should be the excel column that contains element data. Column A in excel is considered the 0th column for use with viswaternet. If intending to animate data using this method, all columns except the first column are treated as data columns and will be animated in order. custom_data_values : array-like Similar to 'excel_columns' two values should be provided. The first value should be an array with element names, and the second should be one with the element data. If intending to animate data using this method, all values except the first value are treated as data values and will be animated in order. This means that, for example, when animating 10 timesteps using this method you should have 11 arrays inside this array. unit : string The unit that the network data is to be converted to. intervals : integer, string If set to 'automatic' then intervals are created automatically on a equal interval basis. Otherwise, it is the edges of the intervals to be created. intervals array length should be num_intervals + 1. num_intervals : integer The number of intervals. disable_interval_deleting : boolean If True, empty intervals will be automatically deleted. vmin : integer The minimum value of the color bar. vmax : integer The maximum value of the color bar. label_list : string, array-like List of labels for each interval. draw_nodes : boolean Determines if draw_nodes with no data associated with them are drawn. discrete_legend_title : string Title of the intervals legend. savefig : boolean Determines if the figure is saved. save_name : string The inputted string will be appended to the name of the network. Example ------- >>>import viswaternet as vis >>>model = vis.VisWNModel(r'Networks/Net3.inp') ... >>>model.save_fig(save_name='_example') <Net3_example.png> color_bar_title : string The title of the color bar. element_size_intervals : integer The number of intervals to be used if an element size legend is used. element_size_legend_title : string The title of the element size legend. element_size_legend_loc : string The location of the element size legend on the figure. element_size_legend_labels : array-like The labels of each interval of the element size legend. disable_interval_deleting : boolean If True, empty intervals will be automatically deleted. style : VisWaterNet Style Object The style object to be used. """ model = self.model if style is None: style = self.default_style args = style.args draw_color_bar = args['draw_color_bar'] pump_element = args['pump_element'] draw_pumps = args['draw_pumps'] valve_element = args['valve_element'] draw_valves = args['draw_valves'] legend_decimal_places = args['legend_decimal_places'] if len(self.model['G_list_pumps_only']) == 0: draw_pumps = False if ax is None: fig, ax = plt.subplots(figsize=self.figsize) ax.set_frame_on(self.axis_frame) def call_draw_base_elements(element_list=None): base.draw_base_elements(self, ax, draw_nodes=draw_nodes, element_list=element_list, draw_originator=parameter_type, style=style) def call_draw_legend(intervals=None, element_list=None): draw_links = True if parameter_type == 'link' \ or parameter == 'diameter' \ or parameter == 'roughness': link_list = [name for name in element_list if ((name not in model["pump_names"] or pump_element == 'node' or draw_pumps is False) and (name not in model["valve_names"] or valve_element == 'node' or draw_valves is False) and (name not in element_list))] if not link_list: draw_links = False base.draw_legend( self, ax, intervals=intervals, title=discrete_legend_title, element_size_intervals=element_size_intervals, element_size_legend_title=element_size_legend_title, element_size_legend_loc=element_size_legend_loc, element_size_legend_labels=element_size_legend_labels, style=style) def call_draw_color_bar(): base.draw_color_bar(self, ax, g, color_bar_title=color_bar_title, style=style) if parameter == "demand_patterns": demand_pattern_nodes, patterns = processing.get_demand_patterns(self) discrete.draw_discrete_nodes( self, ax, demand_pattern_nodes, patterns, label_list=label_list, style=style) call_draw_base_elements(element_list=model['node_names']) call_draw_legend(intervals=patterns, element_list=model['node_names']) if savefig: save_fig(self, save_name=save_name, style=style) return elif parameter == "diameter" or parameter == "roughness": parameter_results, link_list = processing.get_parameter( self, "link", parameter) link_list = [link_list[link_list.index(name)] for name in link_list if ((name not in model["pump_names"] or pump_element == 'node' or draw_pumps is False) and (name not in model["valve_names"] or valve_element == 'node' or draw_valves is False))] parameter_results = parameter_results.loc[link_list] parameter_results = parameter_results.values.tolist() if unit is not None: parameter_results = unit_conversion( parameter_results, parameter, unit) uniques = sorted(list(set(parameter_results))) interval_names = [("{:.{j}f}".format(i, j=legend_decimal_places)) for i in uniques] interval_results = {} for interval_name in interval_names: interval_results[interval_name] = {} for i, link in enumerate(link_list): interval_results["{:.{j}f}".format( parameter_results[i], j=legend_decimal_places)][link] = \ model["G_pipe_name_list"].index(link) # return interval_results,parameter_results,uniques discrete.draw_discrete_links( self, ax, interval_results, interval_names, label_list=label_list, style=style) call_draw_base_elements(element_list=link_list) call_draw_legend(intervals=interval_names, element_list=link_list) if savefig: save_fig(self, save_name=save_name, style=style) return elif parameter == "tag": parameter_results, node_list = processing.get_parameter( self, "node", parameter) uniques = [] if any(i is not None for i in (parameter_results)): uniques = list(set(parameter_results)) interval_names = uniques if not uniques: pass if None in interval_names: interval_names.remove(None) interval_names.append('No Tag') interval_results = {} for interval_name in interval_names: interval_results[interval_name] = {} for i, node in enumerate(node_list): if parameter_results[i] is None: interval_results["No Tag"][node] = model["node_names"].index( node) continue interval_results[parameter_results[i]][node] = model[ "node_names" ].index(node) discrete.draw_discrete_nodes( self, ax, interval_results, interval_names, label_list=label_list, style=style) call_draw_base_elements(element_list=model["node_names"]) call_draw_legend(intervals=interval_names, element_list=model["node_names"]) if savefig: save_fig(self, save_name=save_name, style=style) return elif parameter == "custom_data": if data_type == "unique": interval_names = list(sorted(set(custom_data_values[1]))) interval_results = {} for interval in interval_names: interval_results[interval] = {} if parameter_type == 'node': for element, data in zip( custom_data_values[0], custom_data_values[1]): interval_results[data][element] = \ model["node_names"].index(element) discrete.draw_discrete_nodes( self, ax, interval_results, interval_names, label_list=label_list, style=style) elif parameter_type == 'link': for element, data in zip( custom_data_values[0], custom_data_values[1]): interval_results[data][element] = \ model["G_pipe_name_list"].index(element) discrete.draw_discrete_links( self, ax, interval_results, interval_names, style=style) call_draw_base_elements(element_list=custom_data_values[0]) call_draw_legend(intervals=interval_names, element_list=custom_data_values[0]) if savefig: save_fig(self, save_name=save_name, style=style) return elif data_type == "discrete": interval_results, interval_names = processing.bin_parameter( self, custom_data_values[1], custom_data_values[0], intervals=intervals, num_intervals=num_intervals, disable_interval_deleting=disable_interval_deleting, style=style) if parameter_type == "link": discrete.draw_discrete_links( self, ax, interval_results, interval_names, label_list=label_list, style=style) call_draw_base_elements(element_list=custom_data_values[0]) call_draw_legend(element_list=custom_data_values[0], intervals=interval_names) elif parameter_type == "node": discrete.draw_discrete_nodes( self, ax, interval_results, interval_names, label_list=label_list, style=style) call_draw_base_elements(element_list=custom_data_values[0]) call_draw_legend(intervals=interval_names, element_list=custom_data_values[0]) if savefig: save_fig(self, save_name=save_name, style=style) return elif data_type == "continuous": if parameter_type == "link": if isinstance(custom_data_values[1], list): parameter_results = pd.Series(custom_data_values[1], custom_data_values[0]) else: parameter_results = custom_data_values[1] g = base.draw_links( self, ax, custom_data_values[0], parameter_results=parameter_results, vmin=vmin, vmax=vmax, style=style) call_draw_base_elements(element_list=custom_data_values[0]) call_draw_legend(element_list=custom_data_values[0]) elif parameter_type == "node": if isinstance(custom_data_values[1], list): parameter_results = pd.Series(custom_data_values[1], custom_data_values[0]) else: parameter_results = custom_data_values[1] g = base.draw_nodes( self, ax, custom_data_values[0], parameter_results=parameter_results, vmin=vmin, vmax=vmax, style=style) call_draw_base_elements(element_list=custom_data_values[0]) call_draw_legend(element_list=custom_data_values[0]) if draw_color_bar is True: call_draw_color_bar() if savefig: save_fig(self, save_name=save_name, style=style) return elif parameter == 'excel_data': if data_type == "unique": interval_results, intervals = convert_excel( self, data_file, parameter_type, data_type, excel_columns[0], excel_columns[1]) element_list, results = convert_excel( self, data_file, parameter_type, 'discrete', excel_columns[0], excel_columns[1]) if parameter_type == "link": discrete.draw_discrete_links( self, ax, interval_results, intervals, label_list=label_list, style=style) call_draw_base_elements(element_list=element_list) call_draw_legend(element_list=element_list, intervals=intervals) elif parameter_type == "node": discrete.draw_discrete_nodes( self, ax, interval_results, intervals, label_list=label_list, style=style) call_draw_base_elements(element_list=element_list) call_draw_legend(intervals=intervals, element_list=element_list) if savefig: save_fig(self, save_name=save_name, style=style) return if data_type == "discrete": element_list, results = convert_excel( self, data_file, parameter_type, data_type, excel_columns[0], excel_columns[1]) results = results.values.tolist() interval_results, interval_names = processing.bin_parameter( self, results, element_list, intervals=intervals, num_intervals=num_intervals, disable_interval_deleting=disable_interval_deleting, style=style) if parameter_type == "link": discrete.draw_discrete_links( self, ax, interval_results, interval_names, label_list=label_list, style=style) call_draw_base_elements(element_list=element_list) call_draw_legend(element_list=element_list, intervals=interval_names) if parameter_type == "node": discrete.draw_discrete_nodes( self, ax, interval_results, interval_names, label_list=label_list, style=style) call_draw_base_elements(element_list=element_list) call_draw_legend(intervals=interval_names, element_list=element_list) if savefig: save_fig(self, save_name=save_name, style=style) return if data_type == "continuous": element_list, results = convert_excel( self, data_file, parameter_type, data_type, excel_columns[0], excel_columns[1]) if parameter_type == "link": g = base.draw_links( self, ax, element_list, results, vmin=vmin, vmax=vmax, style=style) call_draw_base_elements(element_list=element_list) call_draw_legend(element_list=element_list) elif parameter_type == "node": g = base.draw_nodes( self, ax, element_list, results, vmin=vmin, vmax=vmax, style=style) call_draw_base_elements(element_list=element_list) call_draw_legend(element_list=element_list) if draw_color_bar is True: call_draw_color_bar() if savefig: save_fig(self, save_name=save_name, style=style) return elif isinstance(parameter, str): pass else: raise Exception("Invalid input, check docs for valid inputs.")