From ae8b554a91f515d6cfc57f0935b34c99b68f0a75 Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Mon, 9 Aug 2021 18:39:12 +0300 Subject: [PATCH 01/13] Moved to plotters/ --- .../plots/{common/plotters.py => plotters/diffs_plotters.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/python/evaluation/plots/{common/plotters.py => plotters/diffs_plotters.py} (100%) diff --git a/src/python/evaluation/plots/common/plotters.py b/src/python/evaluation/plots/plotters/diffs_plotters.py similarity index 100% rename from src/python/evaluation/plots/common/plotters.py rename to src/python/evaluation/plots/plotters/diffs_plotters.py From 8bbd90b561a124b0ef105a72a26be330efcfb1ba Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Mon, 9 Aug 2021 18:39:38 +0300 Subject: [PATCH 02/13] Added line plot and histogram --- src/python/evaluation/plots/common/utils.py | 46 ++++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/python/evaluation/plots/common/utils.py b/src/python/evaluation/plots/common/utils.py index 8fb1673e..05c6b9c1 100644 --- a/src/python/evaluation/plots/common/utils.py +++ b/src/python/evaluation/plots/common/utils.py @@ -1,6 +1,6 @@ import os from pathlib import Path -from typing import List, Optional +from typing import Dict, List, Optional import pandas as pd import plotly.express as px @@ -30,7 +30,7 @@ def create_bar_plot( def create_box_plot( df: pd.DataFrame, - x_axis: str, + x_axis: Optional[str], y_axis: str, margin: Optional[plotly_consts.MARGIN] = None, sort_order: Optional[plotly_consts.SORT_ORDER] = None, @@ -41,11 +41,43 @@ def create_box_plot( return fig +def create_line_plot( + df: pd.DataFrame, + x_axis: str, + y_axis: str, + margin: Optional[plotly_consts.MARGIN] = None, + color: Optional[plotly_consts.COLOR] = None, + vertical_lines: Optional[Dict[int, Optional[str]]] = None, +) -> go.Figure: + fig = px.line(df, x=x_axis, y=y_axis, text=y_axis) + update_figure(fig, margin=margin, color=color, vertical_lines=vertical_lines) + return fig + + +def create_histogram( + df: pd.DataFrame, + x_axis: str, + y_axis: str, + n_bins: Optional[int] = None, + margin: Optional[plotly_consts.MARGIN] = None, + color: Optional[plotly_consts.COLOR] = None, + vertical_lines: Optional[Dict[int, Optional[str]]] = None, +) -> go.Figure: + fig = px.histogram(df, x=x_axis, y=y_axis, nbins=n_bins) + update_figure( + fig, margin=margin, color=color, vertical_lines=vertical_lines, x_axis_name=x_axis, y_axis_name=y_axis, + ) + return fig + + def update_figure( fig: go.Figure, margin: Optional[plotly_consts.MARGIN] = None, sort_order: Optional[plotly_consts.SORT_ORDER] = None, color: Optional[plotly_consts.COLOR] = None, + vertical_lines: Optional[Dict[int, Optional[str]]] = None, + x_axis_name: Optional[str] = None, + y_axis_name: Optional[str] = None, ) -> None: new_layout = {} @@ -55,6 +87,12 @@ def update_figure( if sort_order is not None: new_layout["xaxis"] = {"categoryorder": sort_order.value} + if x_axis_name is not None: + new_layout['xaxis_title'] = x_axis_name + + if y_axis_name is not None: + new_layout['yaxis_title'] = y_axis_name + fig.update_layout(**new_layout) new_trace = {} @@ -64,6 +102,10 @@ def update_figure( fig.update_traces(**new_trace) + if vertical_lines is not None: + for x, annotation in vertical_lines.items(): + fig.add_vline(x=x, annotation_text=annotation) + def save_plot( fig: go.Figure, From 4b7d3091a529787cbb4189b3964956e9b5276eb6 Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Mon, 9 Aug 2021 18:39:50 +0300 Subject: [PATCH 03/13] Updated whitelist --- whitelist.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/whitelist.txt b/whitelist.txt index 67d97c06..7bea9fac 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -12,6 +12,7 @@ checkstyle cloneable concat config +configs conftest const consts @@ -108,6 +109,7 @@ multilabel multiline multithreading namespace +nbins ncss ndarray nl @@ -179,6 +181,7 @@ usecols util utils varargs +vline wandb warmup webp From 422dd368dc34625fda69a1482ea01e0aea6dbc54 Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Mon, 9 Aug 2021 18:40:10 +0300 Subject: [PATCH 04/13] Added plotters --- .../evaluation/plots/plotters/__init__.py | 0 .../raw_issues_statistics_plotters.py | 99 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/python/evaluation/plots/plotters/__init__.py create mode 100644 src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py diff --git a/src/python/evaluation/plots/plotters/__init__.py b/src/python/evaluation/plots/plotters/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py b/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py new file mode 100644 index 00000000..032d02a2 --- /dev/null +++ b/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py @@ -0,0 +1,99 @@ +from dataclasses import dataclass +from enum import Enum, unique +from typing import Callable, Dict, Optional, Tuple + +import numpy as np +import pandas as pd +import plotly.graph_objects as go +from src.python.evaluation.issues_statistics.get_raw_issues_statistics import VALUE +from src.python.evaluation.plots.common import plotly_consts +from src.python.evaluation.plots.common.utils import create_histogram, create_line_plot + + +@unique +class PlotTypes(Enum): + LINE_CHART = 'line_chart' + HISTOGRAM = 'histogram' + + def to_plotter_function(self) -> Callable[..., go.Figure]: + type_to_function = { + PlotTypes.LINE_CHART: plot_line_chart, + PlotTypes.HISTOGRAM: plot_histogram, + } + + return type_to_function[self] + + +@dataclass +class PlotConfig: + column: str + type: PlotTypes + x_axis_name: Optional[str] = None + y_axis_name: Optional[str] = None + margin: Optional[plotly_consts.MARGIN] = None + color: Optional[plotly_consts.COLOR] = None + boundaries: Optional[Dict[int, Optional[str]]] = None + range_of_values: Optional[range] = None + n_bins: Optional[int] = None + + +def _prepare_stats(stats: pd.DataFrame, config: PlotConfig, x_axis_name: str, y_axis_name: str) -> pd.DataFrame: + result_df = stats[[VALUE, config.column]] + + if config.range_of_values is not None: + result_df = result_df[result_df[VALUE].isin(config.range_of_values)] + + result_df.set_index(VALUE, inplace=True) + + # Trim trailing zeros + result_df = result_df.apply(lambda column: np.trim_zeros(column, trim='b')).dropna() + + # Fill in the missing intermediate values with zeros + min_index, max_index = result_df.index.min(), result_df.index.max() + result_df = result_df.reindex(range(min_index, max_index + 1), fill_value=0) + + result_df.reset_index(inplace=True) + + return result_df.rename(columns={VALUE: x_axis_name, config.column: y_axis_name}) + + +def _get_axis_names(config: PlotConfig, default_x_axis_name: str, default_y_axis_name: str) -> Tuple[str, str]: + x_axis_name = default_x_axis_name + if config.x_axis_name is not None: + x_axis_name = config.x_axis_name + + y_axis_name = default_y_axis_name + if config.y_axis_name is not None: + y_axis_name = config.y_axis_name + + return x_axis_name, y_axis_name + + +def plot_line_chart(stats: pd.DataFrame, config: PlotConfig) -> go.Figure: + x_axis_name, y_axis_name = _get_axis_names( + config, default_x_axis_name='Value', default_y_axis_name='Number of fragments', + ) + + stats = _prepare_stats(stats, config, x_axis_name, y_axis_name) + + return create_line_plot( + stats, x_axis_name, y_axis_name, margin=config.margin, color=config.color, vertical_lines=config.boundaries, + ) + + +def plot_histogram(stats: pd.DataFrame, config: PlotConfig) -> go.Figure: + x_axis_name, y_axis_name = _get_axis_names( + config, default_x_axis_name='Value', default_y_axis_name='Number of fragments', + ) + + stats = _prepare_stats(stats, config, x_axis_name, y_axis_name) + + return create_histogram( + stats, + x_axis_name, + y_axis_name, + margin=config.margin, + color=config.color, + n_bins=config.n_bins, + vertical_lines=config.boundaries, + ) From 764115a4e06d1875f14271f05230959d248625f2 Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Mon, 9 Aug 2021 18:40:21 +0300 Subject: [PATCH 05/13] Added script --- .../plots/raw_issues_statistics_plotter.py | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 src/python/evaluation/plots/raw_issues_statistics_plotter.py diff --git a/src/python/evaluation/plots/raw_issues_statistics_plotter.py b/src/python/evaluation/plots/raw_issues_statistics_plotter.py new file mode 100644 index 00000000..12841b39 --- /dev/null +++ b/src/python/evaluation/plots/raw_issues_statistics_plotter.py @@ -0,0 +1,129 @@ +import argparse +from enum import Enum, unique +from pathlib import Path +from typing import Dict, List, Optional + +import pandas as pd +from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path +from src.python.evaluation.plots.common import plotly_consts +from src.python.evaluation.plots.common.utils import ( + get_supported_extensions, + save_plot, +) +from src.python.evaluation.plots.plotters.raw_issues_statistics_plotters import PlotConfig, PlotTypes +from src.python.review.common.file_system import Extension, parse_yaml + + +@unique +class ConfigFields(Enum): + X_AXIS_NAME = 'x_axis_name' + Y_AXIS_NAME = 'y_axis_name' + MARGIN = 'margin' + COLOR = 'color' + BOUNDARIES = 'boundaries' + COMMON = 'common' + RANGE_OF_VALUES = 'range_of_values' + N_BINS = 'n_bins' + + +X_AXIS_NAME = ConfigFields.X_AXIS_NAME.value +Y_AXIS_NAME = ConfigFields.Y_AXIS_NAME.value +MARGIN = ConfigFields.MARGIN.value +COLOR = ConfigFields.COLOR.value +BOUNDARIES = ConfigFields.BOUNDARIES.value +COMMON = ConfigFields.COMMON.value +RANGE_OF_VALUES = ConfigFields.RANGE_OF_VALUES.value +N_BINS = ConfigFields.N_BINS.value + + +def configure_arguments(parser: argparse.ArgumentParser) -> None: + parser.add_argument( + 'stats', + type=lambda value: Path(value).absolute(), + help='Path to dataset with statistics.', + ) + + parser.add_argument( + 'save_dir', + type=lambda value: Path(value).absolute(), + help='The directory where the plotted charts will be saved.', + ) + + parser.add_argument( + 'config_path', + type=lambda value: Path(value).absolute(), + help='Path to the yaml file containing information about the graphs to be plotted.', + ) + + parser.add_argument( + '--file-extension', + type=str, + default=Extension.SVG.value, + choices=get_supported_extensions(), + help='Allows you to select the extension of output files.', + ) + + +def _get_plot_config( + column_name: str, + plot_type: str, + plot_config: Optional[Dict], + common: Optional[Dict], +) -> PlotConfig: + params = {'column': column_name, 'type': PlotTypes(plot_type.lower())} + + if common is not None: + params.update(common) + + if plot_config is not None: + params.update(plot_config) + + if MARGIN in params: + margin_value = params.get(MARGIN).upper() + params[MARGIN] = plotly_consts.MARGIN[margin_value] + + if COLOR in params: + color_value = params.get(COLOR).upper() + params[COLOR] = plotly_consts.COLOR[color_value] + + if RANGE_OF_VALUES in params: + params[RANGE_OF_VALUES] = range(*params[RANGE_OF_VALUES]) + + return PlotConfig(**params) + + +def get_plot_configs(column_name: str, column_config: Dict) -> List[PlotConfig]: + common = column_config.pop(COMMON, None) + + plot_configs = [] + for plot_type, plot_config in column_config.items(): + plot_configs.append(_get_plot_config(column_name, plot_type, plot_config, common)) + + return plot_configs + + +def plot_and_save(config: Dict, stats: pd.DataFrame, save_dir: Path, extension: Extension) -> None: + for column_name, column_config in config.items(): + plot_configs = get_plot_configs(column_name, column_config) + for plot_config in plot_configs: + plotter_function = plot_config.type.to_plotter_function() + plot = plotter_function(stats, plot_config) + subdir = save_dir / plot_config.column + save_plot(plot, subdir, plot_name=f'{plot_config.column}_{plot_config.type.value}', extension=extension) + + +def main(): + parser = argparse.ArgumentParser() + configure_arguments(parser) + args = parser.parse_args() + + stats = get_solutions_df_by_file_path(args.stats) + + extension = Extension(args.file_extension) + config = parse_yaml(args.config_path) + + plot_and_save(config, stats, args.save_dir, extension) + + +if __name__ == "__main__": + main() From 4b5601cd280239ec9ddf43ae762724c28dcb22e4 Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Tue, 10 Aug 2021 11:04:17 +0300 Subject: [PATCH 06/13] Added the ability to draw horizontal lines when plotting box plot --- src/python/evaluation/plots/common/utils.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/python/evaluation/plots/common/utils.py b/src/python/evaluation/plots/common/utils.py index 05c6b9c1..f036a156 100644 --- a/src/python/evaluation/plots/common/utils.py +++ b/src/python/evaluation/plots/common/utils.py @@ -30,14 +30,15 @@ def create_bar_plot( def create_box_plot( df: pd.DataFrame, - x_axis: Optional[str], + x_axis: str, y_axis: str, margin: Optional[plotly_consts.MARGIN] = None, sort_order: Optional[plotly_consts.SORT_ORDER] = None, color: Optional[plotly_consts.COLOR] = None, + horizontal_lines: Optional[Dict[int, Optional[str]]] = None, ) -> go.Figure: fig = px.box(df, x=x_axis, y=y_axis) - update_figure(fig, margin, sort_order, color) + update_figure(fig, margin=margin, sort_order=sort_order, color=color, horizontal_lines=horizontal_lines) return fig @@ -49,7 +50,7 @@ def create_line_plot( color: Optional[plotly_consts.COLOR] = None, vertical_lines: Optional[Dict[int, Optional[str]]] = None, ) -> go.Figure: - fig = px.line(df, x=x_axis, y=y_axis, text=y_axis) + fig = px.line(df, x=x_axis, y=y_axis) update_figure(fig, margin=margin, color=color, vertical_lines=vertical_lines) return fig @@ -75,6 +76,7 @@ def update_figure( margin: Optional[plotly_consts.MARGIN] = None, sort_order: Optional[plotly_consts.SORT_ORDER] = None, color: Optional[plotly_consts.COLOR] = None, + horizontal_lines: Optional[Dict[int, Optional[str]]] = None, vertical_lines: Optional[Dict[int, Optional[str]]] = None, x_axis_name: Optional[str] = None, y_axis_name: Optional[str] = None, @@ -102,6 +104,10 @@ def update_figure( fig.update_traces(**new_trace) + if horizontal_lines is not None: + for y, annotation in horizontal_lines.items(): + fig.add_hline(y=y, annotation_text=annotation) + if vertical_lines is not None: for x, annotation in vertical_lines.items(): fig.add_vline(x=x, annotation_text=annotation) From 99339b892a3b4cfc73d90359185737c507b909e1 Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Tue, 10 Aug 2021 11:05:02 +0300 Subject: [PATCH 07/13] Added boxplot --- .../raw_issues_statistics_plotters.py | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py b/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py index 032d02a2..c804bd58 100644 --- a/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py +++ b/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py @@ -1,24 +1,26 @@ from dataclasses import dataclass from enum import Enum, unique -from typing import Callable, Dict, Optional, Tuple +from typing import Callable, Dict, Optional, Tuple, List import numpy as np import pandas as pd import plotly.graph_objects as go from src.python.evaluation.issues_statistics.get_raw_issues_statistics import VALUE from src.python.evaluation.plots.common import plotly_consts -from src.python.evaluation.plots.common.utils import create_histogram, create_line_plot +from src.python.evaluation.plots.common.utils import create_histogram, create_line_plot, create_box_plot @unique class PlotTypes(Enum): LINE_CHART = 'line_chart' HISTOGRAM = 'histogram' + BOXPLOT = 'boxplot' def to_plotter_function(self) -> Callable[..., go.Figure]: type_to_function = { PlotTypes.LINE_CHART: plot_line_chart, PlotTypes.HISTOGRAM: plot_histogram, + PlotTypes.BOXPLOT: plot_boxplot, } return type_to_function[self] @@ -97,3 +99,26 @@ def plot_histogram(stats: pd.DataFrame, config: PlotConfig) -> go.Figure: n_bins=config.n_bins, vertical_lines=config.boundaries, ) + + +def _get_all_values_from_stats(stats: pd.DataFrame, column_name: str) -> List[int]: + result = [] + stats.apply(lambda row: result.extend([row[VALUE]] * row[column_name]), axis=1) + return result + + +def plot_boxplot(stats: pd.DataFrame, config: PlotConfig) -> go.Figure: + x_axis_name, y_axis_name = _get_axis_names( + config, + default_x_axis_name="Category", + default_y_axis_name='Values', + ) + + values = _get_all_values_from_stats(stats, config.column) + + if config.range_of_values is not None: + values = list(filter(lambda elem: elem in config.range_of_values, values)) + + values_df = pd.DataFrame.from_dict({x_axis_name: config.column, y_axis_name: values}) + + return create_box_plot(values_df, x_axis_name, y_axis_name, horizontal_lines=config.boundaries) From a58316f4769f804fdaa4d7c51521dee4a0a384fb Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Tue, 10 Aug 2021 11:09:18 +0300 Subject: [PATCH 08/13] Fixed flake8 issues --- .../plots/plotters/raw_issues_statistics_plotters.py | 10 +++++----- whitelist.txt | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py b/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py index c804bd58..2e2955eb 100644 --- a/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py +++ b/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py @@ -1,26 +1,26 @@ from dataclasses import dataclass from enum import Enum, unique -from typing import Callable, Dict, Optional, Tuple, List +from typing import Callable, Dict, List, Optional, Tuple import numpy as np import pandas as pd import plotly.graph_objects as go from src.python.evaluation.issues_statistics.get_raw_issues_statistics import VALUE from src.python.evaluation.plots.common import plotly_consts -from src.python.evaluation.plots.common.utils import create_histogram, create_line_plot, create_box_plot +from src.python.evaluation.plots.common.utils import create_box_plot, create_histogram, create_line_plot @unique class PlotTypes(Enum): LINE_CHART = 'line_chart' HISTOGRAM = 'histogram' - BOXPLOT = 'boxplot' + BOX_PLOT = 'box_plot' def to_plotter_function(self) -> Callable[..., go.Figure]: type_to_function = { PlotTypes.LINE_CHART: plot_line_chart, PlotTypes.HISTOGRAM: plot_histogram, - PlotTypes.BOXPLOT: plot_boxplot, + PlotTypes.BOX_PLOT: plot_box_plot, } return type_to_function[self] @@ -107,7 +107,7 @@ def _get_all_values_from_stats(stats: pd.DataFrame, column_name: str) -> List[in return result -def plot_boxplot(stats: pd.DataFrame, config: PlotConfig) -> go.Figure: +def plot_box_plot(stats: pd.DataFrame, config: PlotConfig) -> go.Figure: x_axis_name, y_axis_name = _get_axis_names( config, default_x_axis_name="Category", diff --git a/whitelist.txt b/whitelist.txt index 7bea9fac..cae7f1ef 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -66,6 +66,7 @@ getuid gradle groupby hashtable +hline hyperstyle idx ignorecase From a70a0491d420eaae248c2f0fdf41e69e1ce37544 Mon Sep 17 00:00:00 2001 From: Ilya Vlasov <55441714+GirZ0n@users.noreply.github.com> Date: Tue, 10 Aug 2021 11:57:05 +0300 Subject: [PATCH 09/13] Update README.md --- src/python/evaluation/plots/README.md | 58 ++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/src/python/evaluation/plots/README.md b/src/python/evaluation/plots/README.md index 6c8c3f11..3608e757 100644 --- a/src/python/evaluation/plots/README.md +++ b/src/python/evaluation/plots/README.md @@ -1,7 +1,7 @@ # Hyperstyle evaluation: plots -This module allows you to visualize the data obtained with the [inspectors](../inspectors) module +This module allows you to visualize the data. -## [diffs_plotter.py](diffs_plotter.py) +## Diffs plotter This script allows you to visualize a dataset obtained with [diffs_between_df.py](../inspectors/diffs_between_df.py). The script can build the following charts: @@ -83,3 +83,57 @@ The result will be four graphs (`unique_issues_by_category`, `unique_penalty_iss #### Distribution of influence on penalty by category + +## Raw issues statistics plotter +This script allows you to visualize a dataset obtained with [get_raw_issues_statistics.py](../issues_statistics/get_raw_issues_statistics.py). + +The script can build the following charts: +* Line chart ([Example](#number-of-unique-issues-by-category)) # TODO +* Box plot ([Example](#number-of-issues-by-category)) # TODO +* Histogram ([Example](#number-of-unique-penalty-issues-by-category)) # TODO + +### Usage +Run the [diffs_plotter.py](diffs_plotter.py) with the arguments from command line. + +**Required arguments**: +1. `stats` — path to a file with stats that were founded by [get_raw_issues_statistics.py](../issues_statistics/get_raw_issues_statistics.py). +2. `save_dir` — directory where the plotted charts will be saved. +3. `config_path` — path to the yaml file containing information about the charts to be plotted. A description of the config and its example is provided in [this section](#config). + +**Optional arguments**: + +Argument | Description +--- | --- +**‑‑file‑extension** | Allows you to select the extension of output files. Available extensions: `.png`, `.jpg`, `.jpeg`, `.webp`, `.svg`, `.pdf`, `.eps`, `.json`. Default is `.svg`. + +### Config +The configuration file is a dictionary in yaml format, where for each column of the original dataset the types of graphs to be plotted are specified. You can also put the common parameters when plotting multiple graphs for one column in a separate `common` group. + +**Possible values of the charts**: +* `line_chart` +* `histogram` +* `box_plot` + +**Possible parameters**: +Parametr | Description +---|--- +**x_axis_name** | Name of the x-axis. The default value depends on the type of chart. +**y_axis_name** | Name of the y-axis. The default value depends on the type of chart. +**boundaries** | Dictionary consisting of pairs `boundary value`: `boundary name` (boundary name may not exist). Allows to draw vertical or horizontal lines on graphs (depending on the type of plot). By default, the boundaries are not drawn. +**range_of_values** | Allows you to filter the values. It is an array of two values: a and b. Only values that belong to the range [a, b) are taken into account when plotting. By default, all values are taken into account when plotting. +**margin** | Defines the outer margin on all four sides of the chart. The available values are specified in the Enum class `MARGIN` from [plots const file](./common/plotly_consts.py). If not specified, the default value provided by Plotly is used. +**sort_order** | Defines the sorting order of the chart. The available values are specified in the Enum class `SORT_ORDER` from [plots const file](./common/plotly_consts.py). If not specified, the default value provided by Plotly is used. +**color** | Defines the color of the chart. The available values are specified in the Enum class `COLOR` from [plots const file](./common/plotly_consts.py). If not specified, the default value provided by Plotly is used. +**n_bins** | Allows you to adjust the number of bins when plotting a box plot. By default, this value is set by Plotly. + +#### Example of config +```yaml +CYCLOMATIC_COMPLEXITY: + line_chart: + x_axis_name: Cyclomatic complexity value + histigram: + common: + range_of_values: [0, 20] +``` + +The result will be two graphs: line chart and histogram. The values in both charts will be between 0 and 19 inclusive. In the line chart the x-axis will be named "Cyclomatic complexity value". From 80bd00b8bbf6067206d32f07dfa4225935183fba Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Tue, 10 Aug 2021 11:58:03 +0300 Subject: [PATCH 10/13] create_line_plot -> create_line_chart --- src/python/evaluation/plots/common/utils.py | 2 +- .../plots/plotters/raw_issues_statistics_plotters.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/python/evaluation/plots/common/utils.py b/src/python/evaluation/plots/common/utils.py index f036a156..5c14d07c 100644 --- a/src/python/evaluation/plots/common/utils.py +++ b/src/python/evaluation/plots/common/utils.py @@ -42,7 +42,7 @@ def create_box_plot( return fig -def create_line_plot( +def create_line_chart( df: pd.DataFrame, x_axis: str, y_axis: str, diff --git a/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py b/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py index 2e2955eb..c545313d 100644 --- a/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py +++ b/src/python/evaluation/plots/plotters/raw_issues_statistics_plotters.py @@ -7,7 +7,7 @@ import plotly.graph_objects as go from src.python.evaluation.issues_statistics.get_raw_issues_statistics import VALUE from src.python.evaluation.plots.common import plotly_consts -from src.python.evaluation.plots.common.utils import create_box_plot, create_histogram, create_line_plot +from src.python.evaluation.plots.common.utils import create_box_plot, create_histogram, create_line_chart @unique @@ -78,7 +78,7 @@ def plot_line_chart(stats: pd.DataFrame, config: PlotConfig) -> go.Figure: stats = _prepare_stats(stats, config, x_axis_name, y_axis_name) - return create_line_plot( + return create_line_chart( stats, x_axis_name, y_axis_name, margin=config.margin, color=config.color, vertical_lines=config.boundaries, ) From 733bc70ce823a68abff861842be19cf6b7ba5381 Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Tue, 10 Aug 2021 12:22:08 +0300 Subject: [PATCH 11/13] Added examples and fixed small errors --- src/python/evaluation/plots/README.md | 21 +++++++++++++----- .../examples/BEST_PRACTICES_box_plot.png | Bin 0 -> 19384 bytes .../examples/CODE_STYLE_ratio_histogram.png | Bin 0 -> 24492 bytes .../CYCLOMATIC_COMPLEXITY_line_chart.png | Bin 0 -> 44576 bytes 4 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 src/python/evaluation/plots/examples/BEST_PRACTICES_box_plot.png create mode 100644 src/python/evaluation/plots/examples/CODE_STYLE_ratio_histogram.png create mode 100644 src/python/evaluation/plots/examples/CYCLOMATIC_COMPLEXITY_line_chart.png diff --git a/src/python/evaluation/plots/README.md b/src/python/evaluation/plots/README.md index 3608e757..bacce3d2 100644 --- a/src/python/evaluation/plots/README.md +++ b/src/python/evaluation/plots/README.md @@ -88,17 +88,17 @@ The result will be four graphs (`unique_issues_by_category`, `unique_penalty_iss This script allows you to visualize a dataset obtained with [get_raw_issues_statistics.py](../issues_statistics/get_raw_issues_statistics.py). The script can build the following charts: -* Line chart ([Example](#number-of-unique-issues-by-category)) # TODO -* Box plot ([Example](#number-of-issues-by-category)) # TODO -* Histogram ([Example](#number-of-unique-penalty-issues-by-category)) # TODO +* Line chart ([Example](#line-chart)) +* Box plot ([Example](#box-plot)) +* Histogram ([Example](#histogram)) ### Usage -Run the [diffs_plotter.py](diffs_plotter.py) with the arguments from command line. +Run the [raw_issues_statistics_plotter.py](raw_issues_statistics_plotter.py) with the arguments from command line. **Required arguments**: 1. `stats` — path to a file with stats that were founded by [get_raw_issues_statistics.py](../issues_statistics/get_raw_issues_statistics.py). 2. `save_dir` — directory where the plotted charts will be saved. -3. `config_path` — path to the yaml file containing information about the charts to be plotted. A description of the config and its example is provided in [this section](#config). +3. `config_path` — path to the yaml file containing information about the charts to be plotted. A description of the config and its example is provided in [this section](#config-1). **Optional arguments**: @@ -137,3 +137,14 @@ CYCLOMATIC_COMPLEXITY: ``` The result will be two graphs: line chart and histogram. The values in both charts will be between 0 and 19 inclusive. In the line chart the x-axis will be named "Cyclomatic complexity value". + +### Examples + +#### Line chart + + +#### Box plot + + +#### Histogram + \ No newline at end of file diff --git a/src/python/evaluation/plots/examples/BEST_PRACTICES_box_plot.png b/src/python/evaluation/plots/examples/BEST_PRACTICES_box_plot.png new file mode 100644 index 0000000000000000000000000000000000000000..b0108a1a12f6e24014a4cf0996f466e16213e2ce GIT binary patch literal 19384 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 Gg!~WCipA{! literal 0 HcmV?d00001 diff --git a/src/python/evaluation/plots/examples/CODE_STYLE_ratio_histogram.png b/src/python/evaluation/plots/examples/CODE_STYLE_ratio_histogram.png new file mode 100644 index 0000000000000000000000000000000000000000..6ebce84e9a02194903771ca8000fb919c0f8e82c GIT binary patch literal 24492 zcmeIac|6qn+dqzENtP1IUXp`wO7<+JQVQ93Dj^1weHgnFN=Sw5WM3y~tivQiWM3xR z7|FiOSO;VIzNS;B?sLxPzVFZX_xpVx_wV~Sf1Dl%@Avz)Kd($Rq5j2iEbQc&{O9H)XSI%4fXx4BaVM<8oQr)>2RWxngzu4-v%aWGS}s8CS;{tq|XRel&x^68vA1~2aEPi{P{JVet{?GjUvp@dNo{xGsj+9E|OgZin z+Tr6=Y18JfU9?!KN|esys$_7sp?=MRQ~I(_KII?xt8;YN`aP9Z+E)jW^$EhTJgHCS z;D;sio#DDf5l8_JyX4&<%ttM1#Bu&m1ql^`yz(9CFbXP4Iu?{oGc_WfuMRTZG`7gV zf?Di&!E+)&6ArVcWxM&R6Xt{{OQNs>09 zbo?w{l;HUnIH{FVaTwq9#&2bN8{sZrt`a;_B%n@h$!9Mq(nex5Wb|$>nC8RwNZ1v;rHRWYXUoO?lp$7K3AQa9+0~>6({C8>>8gu_im*_fBJ=}M2!j$pMA9RM<^Pv z?GhK5py-^&JKbriyt7;o$u0NNm&E*we=Q0-$B8LQH}JXsU@X~hD>U^qOto}-GtM$b zz?NyEC0f(=MpBaBXcZTiKEJC|KfQh`Ys2lF!!047seG?;idz0#f3G20E#OyM2SeQ{`*~4b{yr{EhmR{eyj|IlC{>gr8P3t=ISM6yX&2V*X29NjGHjf)<(#14x#M9{ z2Y>DQK$H7XW(}N}Zx~1Gz9~2b$85P0c&j%!Ed4TWYqj-eMk_Mrw2t}F-DO8LE!KDX zC;hfqKI%W3!J9mI*UaU^b;MlioYJbzNcKc>(|&vj{G=OncW%6mQ_`zAK^mpu4$)t; z`jE5_n1L`ku(S>*!NR9X)^Xi=Q9W(Fv(dvOm8)wWd_|*2SG8L7%$c}Ygjs>10XoZB zwOccv?JlA0o|$P!%`2VpP!GfQBsn^ZdXh|7y%rlPU1}RLZljTmygDA@(P5-RatiKS zh$gLVJb9R)R0eHKRZp7t8`_wenw4~WIjO~!ZzktTQzBLzNI^wMEuun5aArl>_-XFP z*QtiabUVHh>aNvbHFtmi9=o^K&@5c_xtpOc*C`^G7N5JDd~SKhR)4JJdLJPYeFzmo zgtCODiol2q3TZjE=kYrqF0@wT39)Y`3h?Ka;`ej*mj{PLCZ}`ii{^Dp8NxcO*ZGV* zk&D^KeRXP-AL7Ves5k|>pz)l%(a*y6wvS;S8JcG+nGf0gawER-6UpaGVGivt(3D~9 z-tN6rA$|OMqPy$Fqj(y8s&ajzg6B)3=Fp5^=Gfh-1Lm@;(IK~^lwYchUXW+*tiMK_o)wi?@}f;*A}?VrMIA(XA2^{MEjYyiTbSy> z^o}JDys`nt!nd+rHX~pWYSPi;<Hn%FJ26q z)Zlq3dEiUODi8Jw(WC2GFmIpNR1!~m@_iG)K={4MfT9QhWlE2*er)>SxAKT z20G6}WUh6+Lq~OnL@DFA|j zp=N`cjTUqkr6uwls6I}mmx^$rbuPEk)8Ye$X1TU0^TnOaO$WW~BQ3lglMl1H=9?F6 z*$?8Tq0B=iD>91G_g*V)xrIMs6VBWId*aX^CW4VqQxo=eG#6Wt(V3O2KIC7mc4?N4@EFg z1cu|WK`lznKiSD1QDSeFlaN0GbI}nq! z5zkey-<9f_dYaIG9M-m|92vQfGDwCgiAeCVRIg-YO z^`XPs3_0tDOD`Xw(0;^v4Ne)~=#=UHE5eFbAOj!kjwP_#oL*8|F+~_m+(^BC%|3UB zHtK~2e~_A1Lgl4rHezc^1;dM21p%0#W`xQl)o|!A4_!mH3Q3K*Y4Y7cLn*%oJ~Z_Q zg5DW-SV{x;86@uz`?v$4*mp`mBa!sf=J8_6nP-Dy-RJC#Y-7Z9yGf%4=*_@M3G<>| z^P${pE|z!!#wK3XrVjmwcOK~D`&;6bIJV3P9o0+?^B+^=OZ7TFniltK%;meUY@Mmr zWS=afAf^wkSbMG?$Xrv}N)$JTAM`yjf)w*230q80tBHFhr394Lk=|z1*FbMoWX&Rv zon3%G?jLb45M3P@>a^NI#l2Z*;+ak9Hq)QYnVzVu*U!D>hp+tdMjH!(47+J$ck~sS zL`R)V!umF8JD+^3#`*c)Cx<=}N~P{weH9IAoF6AA?h^cVCp^^`mDCX*j}<4$?QIAI zOcY@IKeIt3YqQcXlPEc#^k2bPxIf%Fm|Fb#GJ~kp%yjv=%vJ6Tw$ji%m0gsvQd2qD zApzVA!062FJ|0L<1{iPdDgbLEe}0`;+I*s2Y{HjqU{C3aW)ebB0-+D=#3IzC`l2$7 z-FtqpMop1MqiZW75%iyOZP5+dST1*Wjk^xwvCrkrcgpE;fCc5z1}srx+_O5!m8Ufs z^w@c?rP&Que%Ls4a{dz&U@ehyJf?!=%@437s^dRU)*tV4{Dsc`^EdLm{xdH>yEy-Q zd&0vvv^XTaz;$kP>d7-xa0D9F2??8kiTZIb{(d~nM~~M*Fu&1TR8O+?+S6O8&fxvA z5LievkLJBg?Xi-f5^sHv*0LcUYXDS~o_acvPxr^8c0W0LB`aJf0a^mz41)?X5vzmz zqCw!Ka;aDWhi^r|!!H<|L4i}i7#Q9x5QH&iftFO5JS_rn?tTsJ&?h(~qyap!a=;!* zjYvON2cc^oYX{b}J?hgY<6)FX#0&6*#f73+oYeDEFh)wbVY0)wc}M|$AqZ1^h!vbg z(cHensF3cT-OMSOtH3tg0Z(}CN16m-ZYJQQsK4Bw0``4MZGM{ujQYwA@B|{w;5va* zofQ=lz`ck9u(2JMJjxG-682+W{>Keg{us*AzudfD=wn}qhNXyMJ9mQ2l5@;221aU; znUH2(*VS&w-18SNbQete40~v#&d>2E`1e=^pPI|iD$g~FzBoH7b&ajn(x+vL4x8qr zUu;zXSo+)-BjOn_wZ-tj-)FqP5;w9#vKZ+pMpV6lyyTQI&-m@P-ww7ukfAdgmgger&-)|ZIQOu-FUnkKwPiBEp06zRiNrC^8cfKS z0qiW(jC2R9hTTVvNOlch%}-{)+Hw?km+^V#USC!e`XrbWp;u7tq#L7d=-ts~@=C|F zeD9_B2MxVSKX^^;tvAaPZ3~KVgOEZ_OkTFVj79Q{YoDkgOC8sY>GPE#ali?bF7$UO zpgcxE3t#tD`+jIBcHC{?z4cmuHQ!wM2;5EeeQRIVh+<2!g7!~bp~G`Qf$JQ+OJoiH z25FMb)SK@maCTTtBLQ*Z0mE!$f`8j;WoEWJn6yQ`VyhxBX$#Xv8~$KZRXgqfw%4YD z%4bw}$Oe#cp-lemLKddXN=>SmE)flGEr)=8<}+I^wH3HoISNxMmggzb49q@%Ir!lL7og>g9w zN@eN_=AD~gxVw&Ao$)@I5H~eAa0F%#i*(?<-PF1=*>2Z#(aJ3b48Qex;DHCz5o~*( zqtSa^HW~>?y=S4y`9F~exYJr9-@V=LzS&V^M8Zkpno{@u`7>_YW_a3>*%1@Do~gle z1sSQH3sGHN>Kz}Avu!8E4Ck`l`>MQZUYH9pxS9r#Iu|w@>leGdtB>6*Zg-kyb=sv> zU%KdJ#$(J+auJ8AD*Lc+4KMIWL02h8{qR<87OVLwoV^$R%q37ABo8gSVv#l7)#c$a zY;}FQn#76UfzX@WJWPx#k_Gf_}hBptBA^7 zY0jl<^SX*L5?W5~-ae>&GyklF5o6s}!$Uds&8i}Q3n8`)?ty_O-*fd#QHo?!e{5LoTS8q{^y8|0P%rTjJ4!|Xfmd-+9ihV|3;TS6V z3Tb7N9?OrcjEw-O8lh{|=Fg7fv8Z08{l638{s+K0{-J<}RGJwhqv6!Vtg??;4fA!5 zj;YyZssTVxns0nJaT0Y9l7=R*BxGy!7h4mASx-y?Xd3i)7LFRRAR`A%4fWrd8hVQ% zs0;WcJurcPF>r@bWusrfCs~2v{fk)@ggK%=fKQ$xTfjftx9fyKzh?k_HOO}N&sH@K zhuk?O1U^YNfPc2-{|xjid-#8EMYlLnw9GsPcZ!paL6m(q!lWGrUp}>E?-{UVW3bl> zvb+V2OPM6Kb z1PvPA!W@U~%b2_v3+yg6BCFh~@%2wTV-7+vuzT|Ifi9__H~#&b$s%Schj(UT3G2Tp z4Q$73MI@wiq#QfiTT4~VRL6BxisQ9j08S7lR^v`@ah+C;U?N{ZCozP<6&cN4s9E{k zqkiLK7A-GN@t}Y8g$R6ZcBdMbNS{;AnrO}?m_l7@3XTz*BswTa9*@UJ$&#eR5FnLX z^cIFfkTMC&;Bq?`p(RE%Ck3{QH(49LI??vbbjWWwJ;c#_rYLK?&44RdjTLo9 z_DJjzT@VG>rhZSm$Lw(d@%GH;P0dPAizk%dd1;a1qJI4c+QKj943H<@8Ec@6=c58WK~kbqfWacJRcG z(OM(igt#j-J2Hc16-WM?ff=>4uf0LrtC!@^3sltPBdkbfz2C74OuEa?y3kJ2q856- zccHC%wkA$U&Bqdi&rQ(t+ZxOxL%81{|B8?uF@aAf<9xha;T=4rN66o)SUSQ|04AWM zBYvxrqV77u#E&8T=WR<3&1p*2@vb6oHoclxss(IyV_E~M`I@h~ifyv?P(8;&N^vfu*Pxx(A7OVPdEPc7XZ=@2R5_#%IbQ22HcaGGY_pCU;_7Sfbmn7W+cZ^6Z{;*ov zS>5jwB14FFxzI|zakc*8KG(IVX7inlyM|NN1Ip^}EQ$+=$4BeA*2V63a{$~;kCMt{ ze37}2mRVRUrGZuaXoExwov*6uW~;m8`cr$$hOR1NH{KgWP2;mb6}XAroODnnOM# zfcKt-+8RXv18k)E;R^E01XBI#)y^FaC&Ovlj*C&|)x_MUG+`68bLj!L(>ULvffA@| zGl;y(*k??>iv?L#5Sou2etNpc8TfHal&O>J09Q;CmAr>#c#Q7c4r&R1tK(0QWv!=#<@GboNt1X58N6l<+BgnT>$tl z{z*69VsJH!>tzRaILAKn@*(2KhK~SW{7OrR4;d6KQlY|{p(?SUV=`A8f;~I1tmsGc z9UN_`5(rmaSXzDEi;*4~)416o$5uDZ58m?SdOHq9J$?SS?lJ^&kWP>Rymt6%5_RCO z`^|QU9G2JFCmEl7X!Y?8#W)Ci@M;hS@ho>1q&^uGSIz$!PYCg2!v{@3 zRzE}L-t6R9BJZr<#3w*&%C*t>fvFvDOAIeH0>Wyo?Dus&M~O$KRQW~0@JIrm>qx5~ zIaa$1=6Vaq#5kq>B9(mH6Fl42xTFh4bJ24TY-!|WfLmA@{rY$+@DYPBQ>Kr4jz7tw zsB2|Byo4+A^0d|98PK1KQ#56B@>St0PM9@c!6aAfk1uMPpj{rh>hi;qxrDivjmdV` zw>C?b2h0yqrEI^?&OzvV6Xw~7_f|Fdu^m@}-%=kDOzo(9tI%C|V2K}C)j8HXzFl7p z&b`rKGv!)pSg1_xB+sG~*oC20%6ZFi$%s%qT2cV!xwvIMLUTheU2+)$!-u{zkCQ?O zz>1EsF+@BiPuP{2{_)q&AobHYgVQQ;1REf90iD}3uI0sddt*J6&;7mN#Oiy)(V1?B zR{M{vc`i#FS}dsThzBbD$m*SRcnVC6k+M9MR|q$pB4WiBYzZ;El#b42)d4b(!$k6tQ{evUMQXzJdE_!IANw?dd@Grzi^T_9N441}|Gbi$?uY$92uTeIbba<*NI9 zrL=IMO@Q05eNhK<@h0%uo6T^jThE%IFchG{dRMJ`JwK7X8A*p#c~Kemp4=K_X`!`S z45S6bxJ@XouS>!9JPg%pWFfiBQ?0CTyRF6#Q$rm-2I@Byf9?I^$cGj)@U(eS{$>go z@=&5@PpfN4Jfh{LBnyh2F+A(aW%8P4xQsh@RRE`N++)?)X&8g!Iqy_PPU2+RxIcd( zYHJq8igG? zf!TXMD&)|uLT-W4iI3?r{}3QcWgk9&rmzf_IZ{2*65CzWSFD>dT&YD-=&kBCb(8+@ zk7Dx&YS8;cF89ua2N^L>p0LOaQbUIyCq$%VlgF7dSyX?UE-99x4sPPm&i4gE=trY- z*l#QrfG=;WpEVRDv%A*X?Zf0Fj$RaO4_1){U6EB^B65Ol6yd(tz0%r0y?YAjzHa

HqBzq?|K31Y;xhp%fJY{&r866 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 JF6*2Ung9h+NYVfR literal 0 HcmV?d00001 From 9a6fd2cbad6ca7c1a5e1e082147da9b33bcb042d Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Tue, 10 Aug 2021 12:25:25 +0300 Subject: [PATCH 12/13] Fixed imports --- src/python/evaluation/plots/diffs_plotter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/evaluation/plots/diffs_plotter.py b/src/python/evaluation/plots/diffs_plotter.py index 500b018e..5ecce6f7 100644 --- a/src/python/evaluation/plots/diffs_plotter.py +++ b/src/python/evaluation/plots/diffs_plotter.py @@ -15,13 +15,13 @@ ) from src.python.evaluation.inspectors.print_inspectors_statistics import gather_statistics from src.python.evaluation.plots.common import plotly_consts -from src.python.evaluation.plots.common.plotters import ( +from src.python.evaluation.plots.common.utils import get_supported_extensions, save_plot +from src.python.evaluation.plots.plotters.diffs_plotters import ( get_issues_by_category, get_median_penalty_influence_by_category, get_penalty_influence_distribution, get_unique_issues_by_category, ) -from src.python.evaluation.plots.common.utils import get_supported_extensions, save_plot from src.python.review.common.file_system import deserialize_data_from_file, Extension, parse_yaml From 869ab5ccda4f6a0c4ee1d1e84e9e936feab00f9e Mon Sep 17 00:00:00 2001 From: Ilya Vlasov Date: Tue, 10 Aug 2021 12:26:18 +0300 Subject: [PATCH 13/13] Added sys.path --- src/python/evaluation/plots/raw_issues_statistics_plotter.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/python/evaluation/plots/raw_issues_statistics_plotter.py b/src/python/evaluation/plots/raw_issues_statistics_plotter.py index 12841b39..02888080 100644 --- a/src/python/evaluation/plots/raw_issues_statistics_plotter.py +++ b/src/python/evaluation/plots/raw_issues_statistics_plotter.py @@ -1,8 +1,11 @@ import argparse +import sys from enum import Enum, unique from pathlib import Path from typing import Dict, List, Optional +sys.path.append('../../../..') + import pandas as pd from src.python.evaluation.common.pandas_util import get_solutions_df_by_file_path from src.python.evaluation.plots.common import plotly_consts