Skip to content

Commit 91d7e64

Browse files
committed
feat(graphics)!: drop pgf, add support for pdf and svg
BREAKING CHANGE: `pgf` format is dropped, please use `pdf` or `svg` instead
1 parent 8ffa8a0 commit 91d7e64

File tree

3 files changed

+36
-97
lines changed

3 files changed

+36
-97
lines changed

codesectools/sasts/all/cli.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import typer
99
from click import Choice
1010
from rich import print
11-
from typing_extensions import Annotated
11+
from typing_extensions import Annotated, Literal
1212

1313
from codesectools.datasets import DATASETS_ALL
1414
from codesectools.datasets.core.dataset import FileDataset, GitRepoDataset
@@ -200,26 +200,16 @@ def plot(
200200
help="Overwrite existing figures",
201201
),
202202
] = False,
203-
show: Annotated[
204-
bool,
205-
typer.Option(
206-
"--show",
207-
help="Display figures",
208-
),
209-
] = False,
210-
pgf: Annotated[
211-
bool,
212-
typer.Option(
213-
"--pgf",
214-
help="Export figures to pgf format (for LaTeX document)",
215-
),
216-
] = False,
203+
format: Annotated[
204+
Literal["png", "pdf", "svg"],
205+
typer.Option("--format", help="Figures export format"),
206+
] = "png",
217207
) -> None:
218208
"""Generate and display plots for a project's aggregated analysis results."""
219209
from codesectools.sasts.all.graphics import ProjectGraphics
220210

221211
project_graphics = ProjectGraphics(project_name=project)
222-
project_graphics.export(overwrite=overwrite, show=show, pgf=pgf)
212+
project_graphics.export(overwrite=overwrite, format=format)
223213

224214
@cli.command(help="Generate an HTML report")
225215
def report(

codesectools/sasts/core/cli.py

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import typer
1313
from click import Choice
1414
from rich import print
15-
from typing_extensions import Annotated
15+
from typing_extensions import Annotated, Literal
1616

1717
from codesectools.datasets import DATASETS_ALL
1818
from codesectools.datasets.core.dataset import FileDataset, GitRepoDataset
@@ -314,30 +314,12 @@ def plot(
314314
help="Overwrite existing figures",
315315
),
316316
] = False,
317-
show: Annotated[
318-
bool,
319-
typer.Option(
320-
"--show",
321-
help="Display figures",
322-
),
323-
] = False,
324-
pgf: Annotated[
325-
bool,
326-
typer.Option(
327-
"--pgf",
328-
help="Export figures to pgf format (for LaTeX document)",
329-
),
330-
] = False,
317+
format: Annotated[
318+
Literal["png", "pdf", "svg"],
319+
typer.Option("--format", help="Figures export format"),
320+
] = "png",
331321
) -> None:
332-
"""Generate and export plots for a given project or dataset result.
333-
334-
Args:
335-
result: The name of the analysis result to plot.
336-
overwrite: If True, overwrite existing figure files.
337-
show: If True, display the generated figures.
338-
pgf: If True, export figures in PGF format for LaTeX documents.
339-
340-
"""
322+
"""Generate and export plots for a given project or dataset result."""
341323
from codesectools.sasts.core.graphics import (
342324
FileDatasetGraphics,
343325
GitRepoDatasetGraphics,
@@ -347,7 +329,7 @@ def plot(
347329
if result in self.sast.list_results(project=True):
348330
project = result
349331
project_graphics = ProjectGraphics(self.sast, project_name=project)
350-
project_graphics.export(overwrite=overwrite, show=show, pgf=pgf)
332+
project_graphics.export(overwrite=overwrite, format=format)
351333
elif result in self.sast.list_results(dataset=True):
352334
dataset = result
353335
dataset_name, lang = dataset.split("_")
@@ -356,15 +338,11 @@ def plot(
356338
file_dataset_graphics = FileDatasetGraphics(
357339
self.sast, dataset=dataset
358340
)
359-
file_dataset_graphics.export(
360-
overwrite=overwrite, show=show, pgf=pgf
361-
)
341+
file_dataset_graphics.export(overwrite=overwrite, format=format)
362342
elif isinstance(dataset, GitRepoDataset):
363343
git_repo_dataset_graphics = GitRepoDatasetGraphics(
364344
self.sast, dataset=dataset
365345
)
366-
git_repo_dataset_graphics.export(
367-
overwrite=overwrite, show=show, pgf=pgf
368-
)
346+
git_repo_dataset_graphics.export(overwrite=overwrite, format=format)
369347
else:
370348
print("Not supported yet")

codesectools/sasts/core/graphics.py

Lines changed: 21 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
benchmark performance.
66
"""
77

8-
import shutil
9-
import tempfile
10-
118
import matplotlib
129
import matplotlib.pyplot as plt
1310
import numpy as np
@@ -20,28 +17,24 @@
2017
from codesectools.shared.cwe import CWE
2118
from codesectools.utils import shorten_path
2219

23-
## Matplotlib config
24-
matplotlib.rcParams.update(
25-
{
26-
"font.family": "serif",
27-
"font.size": 11,
28-
}
29-
)
30-
3120

3221
class Graphics:
33-
"""Base class for generating graphics from SAST results.
22+
"""Base class for generating plots and visualizations from SAST results.
3423
3524
Attributes:
36-
sast (SAST): The SAST tool instance.
37-
output_dir (Path): The directory containing the analysis results.
38-
color_mapping (dict): A mapping of categories to colors for plotting.
39-
plot_functions (list): A list of methods that generate plots.
40-
limit (int): The maximum number of items to show in top-N plots.
41-
has_latex (bool): True if a LaTeX installation is found.
25+
limit (int): The maximum number of items to display in charts (default is 10).
26+
filetypes (dict[str, str]): A mapping of file extensions to matplotlib backends.
27+
sast (SAST): The SAST tool instance associated with the graphics.
28+
output_dir (Path): The directory where the analysis results are stored.
29+
color_mapping (dict): A dictionary mapping categories to colors for plots.
30+
plot_functions (list): A list of methods responsible for generating plots.
4231
4332
"""
4433

34+
limit = 10
35+
36+
filetypes = {"png": "AGG", "pdf": "PDF", "svg": "SVG"}
37+
4538
def __init__(self, sast: SAST, project_name: str) -> None:
4639
"""Initialize the Graphics object.
4740
@@ -56,44 +49,27 @@ def __init__(self, sast: SAST, project_name: str) -> None:
5649
self.color_mapping["NONE"] = "BLACK"
5750
self.plot_functions = []
5851

59-
# Plot options
60-
self.limit = 10
61-
62-
self.has_latex = shutil.which("pdflatex")
63-
if self.has_latex:
64-
matplotlib.use("pgf")
65-
matplotlib.rcParams.update(
66-
{
67-
"pgf.texsystem": "pdflatex",
68-
"text.usetex": True,
69-
"pgf.rcfonts": False,
70-
}
71-
)
72-
else:
73-
print("pdflatex not found, pgf will not be generated")
74-
75-
def export(self, overwrite: bool, pgf: bool, show: bool) -> None:
76-
"""Generate, save, and optionally display all registered plots.
52+
def export(self, overwrite: bool, format: str) -> None:
53+
"""Generate and save the configured plots to the output directory.
54+
55+
Iterates through the registered plot functions, generates the figures,
56+
and saves them to a `_figures` subdirectory within the output directory.
7757
7858
Args:
79-
overwrite: If True, overwrite existing figure files.
80-
pgf: If True and LaTeX is available, export figures in PGF format.
81-
show: If True, open the generated figures using the default viewer.
59+
overwrite: If True, overwrite existing figure files without prompting.
60+
format: The file format for the exported figures (e.g., "png", "pdf", "svg").
8261
8362
"""
63+
matplotlib.use(self.filetypes[format])
64+
8465
for plot_function in self.plot_functions:
8566
fig = plot_function()
8667
fig_name = plot_function.__name__.replace("plot_", "")
8768
fig.set_size_inches(12, 7)
8869

89-
if show:
90-
with tempfile.NamedTemporaryFile(delete=True) as temp:
91-
fig.savefig(f"{temp.name}.png", bbox_inches="tight")
92-
typer.launch(f"{temp.name}.png", wait=False)
93-
9470
figure_dir = self.output_dir / "_figures"
9571
figure_dir.mkdir(exist_ok=True, parents=True)
96-
figure_path = figure_dir / f"{fig_name}.png"
72+
figure_path = figure_dir / f"{fig_name}.{format}"
9773
if figure_path.is_file() and not overwrite:
9874
if not typer.confirm(
9975
f"Found existing figure at {figure_path}, would you like to overwrite?"
@@ -104,11 +80,6 @@ def export(self, overwrite: bool, pgf: bool, show: bool) -> None:
10480
fig.savefig(figure_path, bbox_inches="tight")
10581
print(f"Figure {fig_name} saved at {figure_path}")
10682

107-
if pgf and self.has_latex:
108-
figure_path_pgf = figure_dir / f"{fig_name}.pgf"
109-
fig.savefig(figure_path_pgf, bbox_inches="tight")
110-
print(f"Figure {fig_name} exported to pgf")
111-
11283
plt.close(fig)
11384

11485

0 commit comments

Comments
 (0)