"""
Helper Methods used in the AGE-ABM Visual Interface Backend
@Author Matthew Fleischman
@Co-Authors Meghan Ireland and Max Hall
"""
[docs]
def get_data_types(agent):
"""
This function takes a agent as a parameter and gets its valid_plot_types.
Parameters
----------
agent : AgentOfInterest
agent to be checked.
Returns
-------
valid_plot_data_types : list[str]
| Returns the valid_plot_data_types for the given agent.
"""
valid_plot_data_types = []
if agent.get_count():
valid_plot_data_types.append("count")
if agent.get_individual():
valid_plot_data_types.append("individual")
if agent.get_mean_val():
valid_plot_data_types.append("mean_val")
if agent.get_median_val():
valid_plot_data_types.append("median_val")
if agent.get_total_val():
valid_plot_data_types.append("total_val")
if agent.get_min_val():
valid_plot_data_types.append("min_val")
if agent.get_max_val():
valid_plot_data_types.append("max_val")
if agent.get_variance():
valid_plot_data_types.append("variance_val")
if agent.get_std_dev():
valid_plot_data_types.append("std_dev_val")
return valid_plot_data_types
[docs]
def valid_plot_data_type(plot_data_type : str):
"""
This function takes a plot_data_type as a parameter and ensures that it is a valid
plot_data_type.
Parameters
----------
plot_data_type : str
plot_data_type to be checked.
Returns
-------
plot_data_type : str
| Returns the plot_data_type if valid.
| Returns 1 if not valid
"""
valid_plot_data_types = ["count", "individual", "mean_val", "median_val", "total_val"
, "min_val", "max_val", "variance_val", "std_dev_val"]
if plot_data_type in valid_plot_data_types:
return plot_data_type
return 1
[docs]
def valid_plot_type(plot_type : str):
"""
This function takes a plot_type as a parameter and ensures that it is a valid plot_type.
Parameters
----------
plot_type : str
plot_type to be checked.
Returns
-------
plot_type : str
| Returns valid plot type on success
| Returns 1 if plot type invalid
"""
valid_plot_types = ["plot", "bar", "scatter"]
if plot_type in valid_plot_types:
return plot_type
return 1
[docs]
def adding_name_checker(name : str, list_to_go_in : list, is_attribute : bool = False):
"""
This function takes a name as a parameter and ensures that it is a valid python class name
as well as is not an existing name already.
Parameters
----------
name : str
name to be checked.
list_to_go_in : list[str]
list it will be put into
Returns
-------
error term : str
| Returns formatted name on success
| Returns 1 if name already in use
| Returns 2 if name uses invalid characters
"""
# Gets the whole list in lowercase
lowercase_list = [word.lower() for word in list_to_go_in]
# Constructing a Valid Name
return_name = ""
name = (name.strip().replace("_", " "))
parts_of_name = [word.strip().capitalize() for word in name.split(" ")]
for word in parts_of_name:
if parts_of_name.index(word) == 0:
return_name += word
else:
return_name += "_" + word
# Checking if this name already in use
lowercase_name = return_name.lower()
for exist_name in lowercase_list:
# Checks if name already in use
if lowercase_name == exist_name:
return 1 # Name already in use
# Checks if any non-permitted char's used
if name_validator(return_name) != 0:
return 2 # Name invalid
# Valid name returned
if is_attribute:
return return_name.lower()
return return_name
[docs]
def getting_name_checker(name : str, list_to_come_from : list, is_attribute : bool = False):
"""
This function takes a name as a parameter and ensures that it is a valid python class name
as well as is not an existing name already.
Parameters
----------
name : str
name to be checked.
list_to_come_from : list[str]
list it will be taken from
Returns
-------
error term : str
| Returns formatted name on success
| Returns 1 if name isn't already in list
| Returns 2 if name uses invalid characters
"""
# Gets the whole list in lowercase
lowercase_list = [word.lower() for word in list_to_come_from]
# Constructing a Valid Name
return_name = ""
name = (name.strip().replace("_", " "))
parts_of_name = [word.strip().capitalize() for word in name.split(" ")]
for word in parts_of_name:
if parts_of_name.index(word) == 0:
return_name += word
else:
return_name += "_" + word
# Checking if this name already in use
lowercase_name = return_name.lower()
not_in = True
for exist_name in lowercase_list:
# Checks if name already in use
if lowercase_name == exist_name:
not_in = False
if not_in:
return 1 # Name isn't in list
# Checks if any non-permitted char's used
if name_validator(return_name) != 0:
return 2 # Name invalid
# Valid name returned
if is_attribute:
return return_name.lower()
return return_name
[docs]
def name_validator(name : str):
"""
This function takes a name as a parameter and ensures that it is a valid python class name.
Parameters
----------
name : str
name to be checked.
Returns
-------
error term : int
| Returns 0 on success
| Returns 1 if invalid chars used
"""
# Checks if name has a length
if len(name) == 0:
return 1
# Checks first char is a number
if 48 <= ord(name[0]) <= 57:
return 1
# Ensures only valid characters are used
for i in name:
char = ord(i)
if char < 48 or 57 < char < 65 or 90 < char < 95 or 95 < char < 97 or 122 < char:
return 1
# Confirms name is valid
return 0
[docs]
def plotting_string(indent : str, agent : str, attr : str, interest : str, plot_type : str
, title : str, xlabel : str, ylabel : str, compare_agents : list[str]):
"""Method to help write plots to the visualisation ouptut file.
Parameters
----------
indent : str
Indentation for the plotting code.
agent : str
Name of the agent whos data is being plotted.
attr : str
Attribute data being plotted.
interest : str
Data interests for the attribute being plotted.
plot_type : str
Type of plot (line graph, scatter plot, bar graph).
title : str
Title of the plot.
xlabel : str
Label of x-axis.
ylabel : str
Label of y-axis.
compare_agents : list[str]
List of agents to compare to the current agent whos data is being plotted.
Returns
-------
plotter : str
| Returns the compiled string to be written to the visualisation output file.
"""
# Comment and create new plot
plotter = f"{indent}# Plotting data for the {interest} values of the {attr} attribute\n"
plotter += f"{indent}fig, ax = plt.subplots()\n"
# Collect data from records
# Get valus of attributes
length_compare_agents = len(compare_agents)
if attr != "":
# Get final data of individual values
if interest == "individual":
plotter += f"{indent}y_vals = {agent}_records['{attr}']['{interest}'][-1]\n"
for i in range(length_compare_agents):
plotter += f"{indent}y_vals{str(i+1)} = {compare_agents[i]}_records['{attr}']"
plotter += f"['{interest}'][-1]\n"
# Get other data types
else:
plotter += f"{indent}y_vals = {agent}_records['{attr}']['{interest}']\n"
for i in range(length_compare_agents):
plotter += f"{indent}y_vals{str(i+1)} = {compare_agents[i]}_records['{attr}']"
plotter += f"['{interest}']\n"
# Get agent count
else:
plotter += f"{indent}y_vals = {agent}_records['count']\n"
for i in range(length_compare_agents):
plotter += f"{indent}y_vals{str(i+1)} = {compare_agents[i]}_records['count']\n"
# Create x-axis
plotter += f"{indent}x_vals = list(range(len(y_vals)))\n"
# Plot data and comparing agents
plotter += f"{indent}ax.{plot_type}(x_vals, y_vals, label='{agent}')\n"
for i in range(length_compare_agents):
plotter += f"{indent}ax.{plot_type}(x_vals, y_vals{str(i+1)}"
plotter += f", label='{compare_agents[i]}')\n"
# Give title and axis labels
plotter += f"{indent}ax.set_title('{title}')\n"
plotter += f"{indent}ax.set_xlabel('{xlabel}')\n"
plotter += f"{indent}ax.set_ylabel('{ylabel}')\n"
# Provides legend
plotter += f"{indent}ax.legend()\n"
plotter += f"{indent}return fig\n\n"
return plotter