Skip to content
Snippets Groups Projects
Commit 415ed29a authored by Laura Christine Kühle's avatar Laura Christine Kühle
Browse files

Contained all plotting in 'Plotting'.

parent f1031ee3
Branches
No related tags found
No related merge requests found
......@@ -10,8 +10,6 @@ TODO: Add README for ANN training
"""
import numpy as np
import time
import matplotlib
from matplotlib import pyplot as plt
import os
import torch
import json
......@@ -21,9 +19,6 @@ from sklearn.metrics import accuracy_score, precision_recall_fscore_support, \
roc_auc_score
import ANN_Model
from Plotting import plot_classification_barplot, plot_classification_boxplot
matplotlib.use('Agg')
class ModelTrainer:
......@@ -347,64 +342,3 @@ def evaluate_models(models: dict, directory: str, num_iterations: int = 100,
json_file.write(json.dumps(classification_stats))
toc = time.perf_counter()
print(f'Total runtime: {toc - tic:0.4f}s')
def plot_evaluation_results(evaluation_file: str, directory: str,
colors: dict = None) -> None:
"""Plots given evaluation results of model classifications.
Plots evaluation results for all measures for which a color is given. If
colors is set to None, all measures are plotted with a default color
scheme.
Parameters
----------
evaluation_file: str
Path to file containing evaluation results.
directory : str
Path to directory for saving resulting plots.
colors : dict, optional
Dictionary containing plotting colors. If None, set to default colors.
Default: None.
"""
tic = time.perf_counter()
# Set colors if not given
if colors is None:
colors = {'Accuracy': 'magenta', 'Precision_Smooth': 'red',
'Precision_Troubled': '#8B0000', 'Recall_Smooth': 'blue',
'Recall_Troubled': '#00008B', 'F-Score_Smooth': 'green',
'F-Score_Troubled': '#006400', 'AUROC': 'yellow'}
# Read evaluation results
print('Reading evaluation results.')
with open(evaluation_file) as json_file:
classification_stats = json.load(json_file)
# Plot data
print('\nPlotting evaluation of trained models...')
print('Plotting data in boxplot.')
models = classification_stats[list(colors.keys())[0]].keys()
plot_classification_boxplot(classification_stats, colors)
print('Plotting averaged data in barplot.')
classification_stats = {measure: {model: np.array(
classification_stats[measure][model]).mean()
for model in models}
for measure in colors}
plot_classification_barplot(classification_stats, colors)
print('Finished plotting evaluation of trained models!\n')
# Set paths for plot files if not existing already
plot_dir = directory + '/model evaluation'
if not os.path.exists(plot_dir):
os.makedirs(plot_dir)
# Save plots
print('Saving plots.')
file_name = evaluation_file.split('/')[-1].rstrip('.json')
for identifier in plt.get_figlabels():
plt.figure(identifier)
plt.savefig(plot_dir + '/' + file_name + '.' + identifier + '.pdf')
toc = time.perf_counter()
print(f'Total runtime: {toc - tic:0.4f}s')
......@@ -5,6 +5,8 @@
Discussion:
Urgent:
TODO: Rename Vector to Basis
TODO: Extract ndarray encoding and decoding
TODO: Hard-code simplification of cell average/reconstruction in basis
TODO: Make basis variables public (if feasible)
TODO: Contain polynomial degree in basis
......@@ -13,7 +15,7 @@ TODO: Introduce Mesh class
TODO: Check whether ghost cells are handled/set correctly
TODO: Find error in centering for ANN training
TODO: Investigate g-mesh(?)
TODO: Contain all plotting in Plotting
TODO: Contain all plotting in Plotting -> Done
TODO: Remove use of DGScheme from ANN_Data_Generator
TODO: Clean up docstrings
TODO: Adapt TCD from Soraya
......@@ -52,14 +54,11 @@ TODO: Discuss adding kwargs to attributes in documentation
TODO: Add type annotations to function heads
"""
import os
import json
import numpy as np
from sympy import Symbol
import math
import seaborn as sns
import matplotlib
from matplotlib import pyplot as plt
import Troubled_Cell_Detector
import Initial_Condition
......@@ -67,12 +66,8 @@ import Limiter
import Quadrature
import Update_Scheme
from Basis_Function import OrthonormalLegendre
from projection_utils import calculate_cell_average, \
calculate_exact_solution, calculate_approximate_solution
from Plotting import plot_solution_and_approx, plot_semilog_error, \
plot_error, plot_shock_tube, plot_details
from projection_utils import calculate_cell_average
matplotlib.use('Agg')
x = Symbol('x')
sns.set()
......@@ -406,195 +401,3 @@ def do_initial_projection(initial_condition, basis, quadrature,
# print(np.array(output_matrix).shape)
return np.transpose(np.array(output_matrix))
def plot_approximation_results(data_file, directory, plot_name, quadrature,
init_cond, basis):
"""Plots given approximation results.
Generates plots based on given data, sets plot directory if not
already existing, and saves plots.
Parameters
----------
data_file: str
Path to data file for plotting.
directory: str
Path to directory in which plots will be saved.
plot_name : str
Name of plot.
basis: Vector object
Basis used for calculation.
quadrature: Quadrature object
Quadrature used for evaluation.
init_cond : InitialCondition object
Initial condition used for calculation.
"""
# Read approximation results
with open(data_file + '.json') as json_file:
approx_stats = json.load(json_file)
# Decode all ndarrays by converting lists
approx_stats = {key: decode_ndarray(approx_stats[key])
for key in approx_stats.keys()}
# Plot exact/approximate results, errors, shock tubes,
# and any detector-dependant plots
plot_results(quadrature=quadrature, basis=basis,
init_cond=init_cond, **approx_stats)
# Set paths for plot files if not existing already
if not os.path.exists(directory):
os.makedirs(directory)
# Save plots
for identifier in plt.get_figlabels():
# Set path for figure directory if not existing already
if not os.path.exists(directory + '/' + identifier):
os.makedirs(directory + '/' + identifier)
plt.figure(identifier)
plt.savefig(directory + '/' + identifier + '/' +
plot_name + '.pdf')
def plot_results(projection, troubled_cell_history, time_history, mesh,
num_grid_cells, polynomial_degree, wave_speed, final_time,
left_bound, right_bound, basis, quadrature, init_cond,
colors=None, coarse_projection=None,
multiwavelet_coeffs=None):
"""Plots results and troubled cells of a projection.
Plots exact and approximate solution, errors, and troubled cells of a
projection given its evaluation history.
If coarse grid and projection are given, solutions are displayed for
both coarse and fine grid. Additionally, coefficient details are plotted.
Parameters
----------
projection : ndarray
Matrix of projection for each polynomial degree.
troubled_cell_history : list
List of detected troubled cells for each time step.
time_history : list
List of value of each time step.
mesh : ndarray
List of mesh valuation points.
num_grid_cells : int
Number of cells in the mesh. Usually exponential of 2.
polynomial_degree : int
Polynomial degree.
wave_speed : float
Speed of wave in rightward direction.
final_time : float
Final time for which approximation is calculated.
left_bound : float
Left boundary of interval.
right_bound : float
Right boundary of interval.
basis: Vector object
Basis used for calculation.
quadrature: Quadrature object
Quadrature used for evaluation.
init_cond : InitialCondition object
Initial condition used for calculation.
colors: dict
Dictionary of colors used for plots.
coarse_projection: ndarray, optional
Matrix of projection on coarse grid for each polynomial degree.
Default: None.
multiwavelet_coeffs: ndarray, optional
Matrix of wavelet coefficients. Default: None.
"""
# Set colors
if colors is None:
colors = {}
colors = _check_colors(colors)
# Calculate needed variables
interval_len = right_bound-left_bound
cell_len = interval_len/num_grid_cells
# Plot troubled cells
plot_shock_tube(num_grid_cells, troubled_cell_history, time_history)
# Determine exact and approximate solution
grid, exact = calculate_exact_solution(
mesh[2:-2], cell_len, wave_speed,
final_time, interval_len, quadrature,
init_cond)
approx = calculate_approximate_solution(
projection[:, 1:-1], quadrature.get_eval_points(),
polynomial_degree, basis.get_basis_vector())
# Plot multiwavelet solution (fine and coarse grid)
if coarse_projection is not None:
coarse_cell_len = 2*cell_len
coarse_mesh = np.arange(left_bound - (0.5*coarse_cell_len),
right_bound + (1.5*coarse_cell_len),
coarse_cell_len)
# Plot exact and approximate solutions for coarse mesh
coarse_grid, coarse_exact = calculate_exact_solution(
coarse_mesh[1:-1], coarse_cell_len, wave_speed,
final_time, interval_len, quadrature,
init_cond)
coarse_approx = calculate_approximate_solution(
coarse_projection, quadrature.get_eval_points(),
polynomial_degree, basis.get_basis_vector())
plot_solution_and_approx(
coarse_grid, coarse_exact, coarse_approx, colors['coarse_exact'],
colors['coarse_approx'])
# Plot multiwavelet details
num_coarse_grid_cells = num_grid_cells//2
plot_details(projection[:, 1:-1], mesh[2:-2], coarse_projection,
basis.get_basis_vector(),
basis.get_wavelet_vector(), multiwavelet_coeffs,
num_coarse_grid_cells,
polynomial_degree)
plot_solution_and_approx(grid, exact, approx,
colors['fine_exact'],
colors['fine_approx'])
plt.legend(['Exact (Coarse)', 'Approx (Coarse)', 'Exact (Fine)',
'Approx (Fine)'])
# Plot regular solution (fine grid)
else:
plot_solution_and_approx(grid, exact, approx, colors['exact'],
colors['approx'])
plt.legend(['Exact', 'Approx'])
# Calculate errors
pointwise_error = np.abs(exact-approx)
max_error = np.max(pointwise_error)
# Plot errors
plot_semilog_error(grid, pointwise_error)
plot_error(grid, exact, approx)
print('p =', polynomial_degree)
print('N =', num_grid_cells)
print('maximum error =', max_error)
def _check_colors(colors):
"""Checks plot colors.
Checks whether colors for plots were given and sets them if required.
"""
# Set colors for general plots
colors['exact'] = colors.get('exact', 'k-')
colors['approx'] = colors.get('approx', 'y')
# Set colors for multiwavelet plots
colors['fine_exact'] = colors.get('fine_exact', 'k-.')
colors['fine_approx'] = colors.get('fine_approx', 'b-.')
colors['coarse_exact'] = colors.get('coarse_exact', 'k-')
colors['coarse_approx'] = colors.get('coarse_approx', 'y')
return colors
......@@ -6,6 +6,9 @@ TODO: Give option to select plotting color
"""
import os
import time
import json
import numpy as np
import matplotlib
from matplotlib import pyplot as plt
......@@ -13,6 +16,13 @@ import seaborn as sns
from numpy import ndarray
from sympy import Symbol
from Quadrature import Quadrature
from Initial_Condition import InitialCondition
from Basis_Function import Vector
from projection_utils import calculate_exact_solution,\
calculate_approximate_solution
from DG_Approximation import decode_ndarray
matplotlib.use('Agg')
x = Symbol('x')
......@@ -248,3 +258,270 @@ def plot_classification_boxplot(evaluation_dict: dict, colors: dict) -> None:
ax.legend([bp["boxes"][0] for bp in boxplots], evaluation_dict.keys(),
loc='center right', bbox_to_anchor=(1.4, 0.75), shadow=True,
ncol=1, fancybox=True, fontsize=8)
def plot_evaluation_results(evaluation_file: str, directory: str,
colors: dict = None) -> None:
"""Plots given evaluation results of model classifications.
Plots evaluation results for all measures for which a color is given. If
colors is set to None, all measures are plotted with a default color
scheme.
Parameters
----------
evaluation_file: str
Path to file containing evaluation results.
directory : str
Path to directory for saving resulting plots.
colors : dict, optional
Dictionary containing plotting colors. If None, set to default colors.
Default: None.
"""
tic = time.perf_counter()
# Set colors if not given
if colors is None:
colors = {'Accuracy': 'magenta', 'Precision_Smooth': 'red',
'Precision_Troubled': '#8B0000', 'Recall_Smooth': 'blue',
'Recall_Troubled': '#00008B', 'F-Score_Smooth': 'green',
'F-Score_Troubled': '#006400', 'AUROC': 'yellow'}
# Read evaluation results
print('Reading evaluation results.')
with open(evaluation_file) as json_file:
classification_stats = json.load(json_file)
# Plot data
print('\nPlotting evaluation of trained models...')
print('Plotting data in boxplot.')
models = classification_stats[list(colors.keys())[0]].keys()
plot_classification_boxplot(classification_stats, colors)
print('Plotting averaged data in barplot.')
classification_stats = {measure: {model: np.array(
classification_stats[measure][model]).mean()
for model in models}
for measure in colors}
plot_classification_barplot(classification_stats, colors)
print('Finished plotting evaluation of trained models!\n')
# Set paths for plot files if not existing already
plot_dir = directory + '/model evaluation'
if not os.path.exists(plot_dir):
os.makedirs(plot_dir)
# Save plots
print('Saving plots.')
file_name = evaluation_file.split('/')[-1].rstrip('.json')
for identifier in plt.get_figlabels():
plt.figure(identifier)
plt.savefig(plot_dir + '/' + file_name + '.' + identifier + '.pdf')
toc = time.perf_counter()
print(f'Total runtime: {toc - tic:0.4f}s')
def plot_approximation_results(data_file: str, directory: str, plot_name: str,
basis: Vector, quadrature: Quadrature,
init_cond: InitialCondition) -> None:
"""Plots given approximation results.
Generates plots based on given data, sets plot directory if not
already existing, and saves plots.
Parameters
----------
data_file: str
Path to data file for plotting.
directory: str
Path to directory in which plots will be saved.
plot_name : str
Name of plot.
basis: Vector object
Basis used for calculation.
quadrature: Quadrature object
Quadrature used for evaluation.
init_cond : InitialCondition object
Initial condition used for calculation.
"""
# Read approximation results
with open(data_file + '.json') as json_file:
approx_stats = json.load(json_file)
# Decode all ndarrays by converting lists
approx_stats = {key: decode_ndarray(approx_stats[key])
for key in approx_stats.keys()}
# Plot exact/approximate results, errors, shock tubes,
# and any detector-dependant plots
plot_results(quadrature=quadrature, basis=basis,
init_cond=init_cond, **approx_stats)
# Set paths for plot files if not existing already
if not os.path.exists(directory):
os.makedirs(directory)
# Save plots
for identifier in plt.get_figlabels():
# Set path for figure directory if not existing already
if not os.path.exists(directory + '/' + identifier):
os.makedirs(directory + '/' + identifier)
plt.figure(identifier)
plt.savefig(directory + '/' + identifier + '/' +
plot_name + '.pdf')
def plot_results(projection: ndarray, troubled_cell_history: list,
time_history: list, mesh: ndarray, num_grid_cells: int,
polynomial_degree: int, wave_speed: float, final_time: float,
left_bound: float, right_bound: float, basis: Vector,
quadrature: Quadrature, init_cond: InitialCondition,
colors: dict = None, coarse_projection: ndarray = None,
multiwavelet_coeffs: ndarray = None) -> None:
"""Plots results and troubled cells of a projection.
Plots exact and approximate solution, errors, and troubled cells of a
projection given its evaluation history.
If coarse grid and projection are given, solutions are displayed for
both coarse and fine grid. Additionally, coefficient details are plotted.
Parameters
----------
projection : ndarray
Matrix of projection for each polynomial degree.
troubled_cell_history : list
List of detected troubled cells for each time step.
time_history : list
List of value of each time step.
mesh : ndarray
List of mesh valuation points.
num_grid_cells : int
Number of cells in the mesh. Usually exponential of 2.
polynomial_degree : int
Polynomial degree.
wave_speed : float
Speed of wave in rightward direction.
final_time : float
Final time for which approximation is calculated.
left_bound : float
Left boundary of interval.
right_bound : float
Right boundary of interval.
basis: Vector object
Basis used for calculation.
quadrature: Quadrature object
Quadrature used for evaluation.
init_cond : InitialCondition object
Initial condition used for calculation.
colors: dict
Dictionary of colors used for plots.
coarse_projection: ndarray, optional
Matrix of projection on coarse grid for each polynomial degree.
Default: None.
multiwavelet_coeffs: ndarray, optional
Matrix of wavelet coefficients. Default: None.
"""
# Set colors
if colors is None:
colors = {}
colors = _check_colors(colors)
# Calculate needed variables
interval_len = right_bound-left_bound
cell_len = interval_len/num_grid_cells
# Plot troubled cells
plot_shock_tube(num_grid_cells, troubled_cell_history, time_history)
# Determine exact and approximate solution
grid, exact = calculate_exact_solution(
mesh[2:-2], cell_len, wave_speed,
final_time, interval_len, quadrature,
init_cond)
approx = calculate_approximate_solution(
projection[:, 1:-1], quadrature.get_eval_points(),
polynomial_degree, basis.get_basis_vector())
# Plot multiwavelet solution (fine and coarse grid)
if coarse_projection is not None:
coarse_cell_len = 2*cell_len
coarse_mesh = np.arange(left_bound - (0.5*coarse_cell_len),
right_bound + (1.5*coarse_cell_len),
coarse_cell_len)
# Plot exact and approximate solutions for coarse mesh
coarse_grid, coarse_exact = calculate_exact_solution(
coarse_mesh[1:-1], coarse_cell_len, wave_speed,
final_time, interval_len, quadrature,
init_cond)
coarse_approx = calculate_approximate_solution(
coarse_projection, quadrature.get_eval_points(),
polynomial_degree, basis.get_basis_vector())
plot_solution_and_approx(
coarse_grid, coarse_exact, coarse_approx, colors['coarse_exact'],
colors['coarse_approx'])
# Plot multiwavelet details
num_coarse_grid_cells = num_grid_cells//2
plot_details(projection[:, 1:-1], mesh[2:-2], coarse_projection,
basis.get_basis_vector(),
basis.get_wavelet_vector(), multiwavelet_coeffs,
num_coarse_grid_cells,
polynomial_degree)
plot_solution_and_approx(grid, exact, approx,
colors['fine_exact'],
colors['fine_approx'])
plt.legend(['Exact (Coarse)', 'Approx (Coarse)', 'Exact (Fine)',
'Approx (Fine)'])
# Plot regular solution (fine grid)
else:
plot_solution_and_approx(grid, exact, approx, colors['exact'],
colors['approx'])
plt.legend(['Exact', 'Approx'])
# Calculate errors
pointwise_error = np.abs(exact-approx)
max_error = np.max(pointwise_error)
# Plot errors
plot_semilog_error(grid, pointwise_error)
plot_error(grid, exact, approx)
print('p =', polynomial_degree)
print('N =', num_grid_cells)
print('maximum error =', max_error)
def _check_colors(colors: dict) -> dict:
"""Checks plot colors.
Checks whether colors for plots were given and sets them if required.
Parameters
----------
colors: dict
Dictionary containing color strings for plotting.
Returns
-------
dict
Dictionary containing color strings for plotting.
"""
# Set colors for general plots
colors['exact'] = colors.get('exact', 'k-')
colors['approx'] = colors.get('approx', 'y')
# Set colors for multiwavelet plots
colors['fine_exact'] = colors.get('fine_exact', 'k-.')
colors['fine_approx'] = colors.get('fine_approx', 'b-.')
colors['coarse_exact'] = colors.get('coarse_exact', 'k-')
colors['coarse_approx'] = colors.get('coarse_approx', 'y')
return colors
......@@ -3,6 +3,7 @@ import numpy as np
import ANN_Training
from ANN_Training import *
from Plotting import plot_evaluation_results
configfile: 'config.yaml'
......
......@@ -2,10 +2,10 @@ import sys
import time
import numpy as np
import Troubled_Cell_Detector
import Initial_Condition
import Quadrature
from DG_Approximation import DGScheme, plot_approximation_results
from DG_Approximation import DGScheme
from Plotting import plot_approximation_results
from Basis_Function import OrthonormalLegendre
configfile: 'config.yaml'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment