Forked from
SWIFT / SWIFTsim
1696 commits behind the upstream repository.
plot_task_level.py 6.52 KiB
#!/usr/bin/env python3
description = """
Plot the number of tasks for each depth level and each type of task.
Usage:
./plot_task_level.py task_level_0.txt
or
./plot_task_level.py task_level_*_0.txt
"""
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sys
import argparse
from os import path
def parse_args():
"""
Parses command line arguments.
Returns
-------
args: Namespace
Namespace returned by argparse.ArgumentParser.parse_args()
containing all arguments
files:
List of files parsed from the command line.
Raises
------
FileNotFoundError
If the required filename provided on the command line doesn't exist
"""
# description is string at the top of this file.
parser = argparse.ArgumentParser(description=description)
parser.add_argument(
"-c",
"--count",
dest="count_levels",
help="count on how many different levels the tasks can be found"
" and add it to the label",
action="store_true",
)
parser.add_argument(
"-d",
"--displace",
dest="displace",
help="attempt to displace overlapping point on the plot a bit"
" and try to make them visible",
action="store_true",
)
parser.add_argument(
"file",
type=str,
nargs="+",
help="Required file name(s) of .txt file(s) of the task levels "
"generated by swift.",
)
args = parser.parse_args()
files = args.file
for f in files:
if not path.exists(f):
raise FileNotFoundError("File not found:'" + f + "'")
return args, files
def read_data(files):
"""
Reads in data from the .txt file.
Parameters
----------
files: list
list of filenames to be read from
Returns
-------
data: pandas dataframe
dataframe containing read in data
"""
# Column names
names = ["type", "subtype", "depth", "count"]
alldata = None
for f in files:
# read file
data = pd.read_csv(f, sep=" ", comment="#", names=names)
if alldata is None:
alldata = data
else:
concat = pd.concat([alldata, data])
alldata = concat.groupby(["type", "subtype", "depth"], as_index=False).sum()
return data
def get_discrete_cmap(nentries):
"""
Returns a discrete colormap.
Parameters
----------
nentries: int
how many entries you want for your colormap
Returns
-------
cmap: list
list of colors
Raises
------
IndexError:
When you want more entries than there are available.
Current maximum is 21.
"""
fullcolorlist = [
"red",
"green",
"blue",
"gold",
"magenta",
"cyan",
"lime",
"saddlebrown",
"darkolivegreen",
"cornflowerblue",
"orange",
"dimgrey",
"navajowhite",
"darkslategray",
"mediumpurple",
"lightpink",
"mediumseagreen",
"maroon",
"midnightblue",
"silver",
"black",
]
if nentries >= len(fullcolorlist) - 1:
raise IndexError(
"I can't handle more than 21 different colors."
"Add more manually in get_discrete_cmap() function"
)
return fullcolorlist[: nentries + 1]
def add_levelcounts(data):
"""
Adds a column to the data with the counts on how many levels a given task
is executed on.
Parameters
----------
data: pandas dataframe
The dataframe to use
Returns
-------
data: pandas dataframe
the modified dataframe
"""
# add new column
data["nlevels"] = ["1" for _ in range(data.shape[0])]
# count on how many levels each task exists
for i, (ttype, tsubtype) in enumerate(zip(data["type"], data["subtype"])):
istype = data["type"] == ttype
issubtype = data["subtype"] == tsubtype
isthis = np.logical_and(istype, issubtype)
count = np.count_nonzero(isthis)
data.at[i, "nlevels"] = str(count)
return data
def add_displacement(data):
"""
Add small displacements to the task number counts and try
to make them better visible
Parameters
----------
data: pandas dataframe
the data to be modified
Returns
-------
data: pandas dataframe
the modified data
"""
# add new column
data["yvals"] = data["count"] * 1.0
data["yval_modified"] = False
inds = np.arange(0, data.shape[0])
# count on how many levels each task exists
for i, (ttype, tsubtype) in enumerate(zip(data["type"], data["subtype"])):
if data["yval_modified"][i]:
continue
istype = data["type"] == ttype
issubtype = data["subtype"] == tsubtype
isthis = np.logical_and(istype, issubtype)
uniques = np.unique(data["count"][isthis])
for u in uniques:
occurances = np.count_nonzero(data["count"][isthis] == u)
for o in range(occurances):
thisind = inds[isthis][o]
step = 0.05 * max(int(np.log10(u) + 0.5), 1) * o * (-1) ** o
data.at[thisind, "yvals"] += step
data.at[thisind, "yval_modified"] = True
return data
if __name__ == "__main__":
args, files = parse_args()
data = read_data(files)
cmap = get_discrete_cmap(data["depth"].max())
# are we counting the levels?
if args.count_levels:
data = add_levelcounts(data)
# are we displacing the particles on the y axis?
if args.displace:
data = add_displacement(data)
# plot data
for i in range(data["depth"].max() + 1):
ind = data["depth"] == i
label = "depth = {0:d}".format(i)
if args.count_levels:
xvals = (
data["type"][ind]
+ "_"
+ data["subtype"][ind]
+ "["
+ data["nlevels"][ind]
+ "]"
)
else:
xvals = data["type"][ind] + "_" + data["subtype"][ind]
if args.displace:
yvals = data["yvals"][ind]
else:
yvals = data["count"][ind]
c = cmap[i]
plt.plot(xvals, yvals, "o", label=label, color=c, alpha=0.7)
# modify figure parameters and show it
plt.gca().set_yscale("log")
plt.xticks(rotation=90)
plt.ylabel("Number of Tasks")
plt.gcf().subplots_adjust(bottom=0.225)
plt.legend()
plt.grid()
plt.show()