Skip to content

Commit

Permalink
Restore cmap to config; simpler config of cmap/dpi/image format
Browse files Browse the repository at this point in the history
Closes #776

+ Aligns command line and configuration field names with those in matplotlibrc files.
+ Restores the `cmap` configuration option to `default_config.yaml` and introduces `savefig_dpi` option.
+ Adds command line options for setting DPI (`--savefig-dpi`), Colormap (`--cmap`)and Output file
  format (`--savefig-format`).
+ Expands documentation on how to use custom configuration files or command line options to set the DPI/Colormap/Output
  format.
+ Updates the header to `topostats.mplstyle` to explain how to use it as typically users will have created a copy of the
  file (after the convenience function `topostats create-matplotlibrc` was introduced with #773).
+ To achieve this the dictionary `config["plotting"]` needed explicitly updating as the `update_config()` function
  doesn't update nested configurations (since this is the first PR that introduces command line options that modify any
  of the values in the nested dictionaries).
+ Updates options for `topostats toposum`` to align with `savefig_format` and adds flag to entry point so output format
  is consistent.
+ Updates and expands the configuration documentation explaining how to use these conveniences.

As a consequence quite a few files are touched to ensure that validation and processing functions all have variables
that align with those in the configuration.

If users could test this it would be very much appreciated, if you use the Git installed version something like the
following would switch branches and allow you test it.

```
conda create --name topostats-config # Create and activate a virtual env specific to this
conda activate topostats-config
cd ~/path/to/TopoStats
git pull
git checkout ns-rse/776-config-jigging
pip install -e .
topostats process --output-dir base
topostats create-config test_config.yaml   # Create test_config.yaml to try changing parameters
topostats process --config test_config.yaml --output-dir test1
topostats process  --output-dir test2 --savefig-dpi 10 --cmap rainbow --savefig-format svg
topostats process --config test_config.yaml  --output-dir test3 --savefig-dpi 80 --cmap viridis --savefig-format pdf
```

Each invocation of `topostats process` will save output to its own directory (either `base`, `test1`, `test2` and
`test3`) for comparison. There should be differences between each `base` the values used in `test_config.yaml` and
saved under `test1` and those under `test2` and `test3` should also differ.

I would really appreciate feedback on the documentation as without clear documentation it is perhaps confusing how the
components interact and work and can be modified and getting this as clear as possible will be really helpful.
  • Loading branch information
ns-rse committed Jan 12, 2024
1 parent dd5c9b7 commit 0649a79
Show file tree
Hide file tree
Showing 15 changed files with 350 additions and 174 deletions.
228 changes: 167 additions & 61 deletions docs/configuration.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion tests/test_plotting.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Tests for the plotting module."""

import importlib.resources as pkg_resources
from pathlib import Path

Expand Down Expand Up @@ -58,7 +59,7 @@ def test_toposum_class(toposum_object_multiple_directories: TopoSum) -> None:
assert isinstance(toposum_object_multiple_directories.image_id, str)
assert isinstance(toposum_object_multiple_directories.hist, bool)
assert isinstance(toposum_object_multiple_directories.kde, bool)
assert isinstance(toposum_object_multiple_directories.file_ext, str)
assert isinstance(toposum_object_multiple_directories.savefig_format, str)
assert isinstance(toposum_object_multiple_directories.output_dir, Path)
assert isinstance(toposum_object_multiple_directories.var_to_label, dict)

Expand Down
3 changes: 2 additions & 1 deletion tests/test_plottingfuncs.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Tests of plotting functions."""

from pathlib import Path

import matplotlib as mpl
Expand Down Expand Up @@ -282,7 +283,7 @@ def test_mask_cmap(plotting_config: dict, tmp_path: Path) -> None:
@pytest.mark.mpl_image_compare(baseline_dir="resources/img/", savefig_kwargs={"dpi": DPI})
def test_high_dpi(minicircle_grain_gaussian_filter: Grains, plotting_config: dict, tmp_path: Path) -> None:
"""Test plotting with high DPI."""
plotting_config["dpi"] = DPI
plotting_config["savefig_dpi"] = DPI
fig, _ = Images(
data=minicircle_grain_gaussian_filter.images["gaussian_filtered"],
output_dir=tmp_path,
Expand Down
5 changes: 3 additions & 2 deletions tests/test_processing.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test end-to-end running of topostats."""

from pathlib import Path

import filetype
Expand Down Expand Up @@ -108,7 +109,7 @@ def test_save_cropped_grains(
"""Tests if cropped grains are saved only when image set is 'all' rather than 'core'."""
process_scan_config["plotting"]["image_set"] = image_set
process_scan_config["plotting"] = update_plotting_config(process_scan_config["plotting"])
process_scan_config["plotting"]["dpi"] = 50
process_scan_config["plotting"]["savefig_dpi"] = 50

img_dic = load_scan_data.img_dict
_, _, _ = process_scan(
Expand Down Expand Up @@ -152,7 +153,7 @@ def test_save_cropped_grains(
def test_save_format(process_scan_config: dict, load_scan_data: LoadScans, tmp_path: Path, extension: str):
"""Tests if save format applied to cropped images."""
process_scan_config["plotting"]["image_set"] = "all"
process_scan_config["plotting"]["save_format"] = extension
process_scan_config["plotting"]["savefig_format"] = extension
process_scan_config["plotting"] = update_plotting_config(process_scan_config["plotting"])

img_dic = load_scan_data.img_dict
Expand Down
4 changes: 3 additions & 1 deletion topostats/default_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@ dnatracing:
plotting:
run: true # Options : true, false
style: topostats.mplstyle # Options : topostats.mplstyle or path to a matplotlibrc params file
save_format: png # Options : see https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.savefig.html
savefig_format: null # Options : null (defaults to png) or see https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.savefig.html
savefig_dpi: null # Options : null (defaults to format) see https://afm-spm.github.io/TopoStats/main/configuration.html#further-customisation and https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.savefig.html
pixel_interpolation: null # Options : https://matplotlib.org/stable/gallery/images_contours_and_fields/interpolation_methods.html
image_set: core # Options : all, core
zrange: [null, null] # low and high height range for core images (can take [null, null]). low <= high
colorbar: true # Options : true, false
axes: true # Options : true, false (due to off being a bool when parsed)
num_ticks: [null, null] # Number of ticks to have along the x and y axes. Options : null (auto) or integer > 1
cmap: null # Colormap/colourmap to use (default is 'nanoscope' which is used if null, other options are 'afmhot', 'viridis' etc.)
mask_cmap: blu # Options : blu, jet_r and any in matplotlib
histogram_log_axis: false # Options : true, false
summary_stats:
Expand Down
35 changes: 33 additions & 2 deletions topostats/entry_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Parses command-line arguments and passes input on to the relevant functions / modules.
"""

import argparse as arg
import sys

Expand All @@ -10,6 +11,8 @@
from topostats.plotting import run_toposum
from topostats.run_topostats import run_topostats

# pylint: disable=too-many-statements


def create_parser() -> arg.ArgumentParser:
"""Create a parser for reading options."""
Expand All @@ -29,8 +32,8 @@ def create_parser() -> arg.ArgumentParser:
# Create a sub-parsers for different stages of processing and tasks
process_parser = subparsers.add_parser(
"process",
description="Process AFM images. Additional arguments over-ride those in the configuration file.",
help="Process AFM images. Additional arguments over-ride those in the configuration file.",
description="Process AFM images. Additional arguments over-ride defaults or those in the configuration file.",
help="Process AFM images. Additional arguments over-ride defaults or those in the configuration file.",
)
process_parser.add_argument(
"-c",
Expand Down Expand Up @@ -106,6 +109,27 @@ def create_parser() -> arg.ArgumentParser:
required=False,
help="Whether to save plots.",
)
process_parser.add_argument(
"--savefig-format",
dest="savefig_format",
type=str,
required=False,
help="Format for saving figures to, options are 'png', 'svg', or other valid Matplotlib supported formats.",
)
process_parser.add_argument(
"--savefig-dpi",
dest="savefig_dpi",
type=int,
required=False,
help="Dots Per Inch for plots, should be integer for dots per inch.",
)
process_parser.add_argument(
"--cmap",
dest="cmap",
type=str,
required=False,
help="Colormap to use, options include 'nanoscope', 'afmhot' and any valid Matplotlib colormap.",
)
process_parser.add_argument("-m", "--mask", dest="mask", type=bool, required=False, help="Mask the image.")
process_parser.add_argument(
"-w",
Expand Down Expand Up @@ -151,6 +175,13 @@ def create_parser() -> arg.ArgumentParser:
required=False,
help="Filename to write a sample YAML label file to (should end in '.yaml').",
)
toposum_parser.add_argument(
"--savefig-format",
dest="savefig_format",
type=str,
required=False,
help="Format for saving figures to, options are 'png', 'svg', or other valid Matplotlib supported formats.",
)
toposum_parser.set_defaults(func=run_toposum)

load_parser = subparsers.add_parser(
Expand Down
10 changes: 6 additions & 4 deletions topostats/plotting.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Plotting and summary of TopoStats output statistics."""

from collections import defaultdict

import importlib.resources as pkg_resources
Expand Down Expand Up @@ -43,7 +44,7 @@ def __init__(
figsize: tuple = (16, 9),
alpha: float = 0.5,
palette: str = "deep",
file_ext: str = "png",
savefig_format: str = "png",
output_dir: Union[str, Path] = ".",
var_to_label: dict = None,
hue: str = "basename",
Expand Down Expand Up @@ -105,7 +106,7 @@ def __init__(
self.figsize = figsize
self.alpha = alpha
self.palette = palette
self.file_ext = file_ext
self.savefig_format = savefig_format
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
self.var_to_label = var_to_label
Expand Down Expand Up @@ -264,9 +265,10 @@ def save_plot(self, outfile: Path) -> None:
outfile: str
Output file name to save figure to.
"""
plt.savefig(self.output_dir / f"{outfile}.{self.file_ext}")
plt.savefig(self.output_dir / f"{outfile}.{self.savefig_format}")
LOGGER.info(
f"[plotting] Plotted {self.stat_to_sum} to : " f"{str(self.output_dir / f'{outfile}.{self.file_ext}')}"
f"[plotting] Plotted {self.stat_to_sum} to : "
f"{str(self.output_dir / f'{outfile}.{self.savefig_format}')}"
)

def _set_label(self, var: str):
Expand Down
Loading

0 comments on commit 0649a79

Please sign in to comment.