Skip to content

Commit 4b669c3

Browse files
eytanadlerA-CGray
andauthored
Switch to using stylesheets (#30)
* First pass at using stylesheets * Bug fixes and readme update * Updated the examples, removed dark mode examples, and fixed some bugs * Fixed some examples * Added Prompt font install to github actions * Ran black * Added a james-themed plot to the README * Attempting to fix GHA and updated testing matrix * Needed quotes around Python versions in GHA * Fixed docstrings for new styles * Maybe init file is needed in styles directory * Removed colors return from setStyle * Adding init to styles dir did not help GHA problems * Added all stylesheets to python install * Needed another option in setup file * Trying to debug GHA * Temporarily change testing matrix for debugging * Trying more complete stylesheet path specification * I think I fixed it, restored GHA script * Numpy 1.18 does not support Python 3.9 and 3.10, made it a newer version * Numpy 1.20 is not new enough, updating to 1.21 * Added Prompt font install to read the docs * Used the wrong yaml command for RTD font install * Switched to using matplotlib built in style sheet management * New function to get list of colors * Fixed formatting * Trying one more thing before giving up on RTD * I give up, RTD sux * Fixed docstring * Typo * Address changes from Neil * Removed default figure size and changed default font size * Removed hardcoded colors * Add generated docs to gitignore * Changed figure size in parula contours example * Ran black * Tweaking Doumont stylesheet, not done yet * Adding simple Doumont example * Trying to install Prompt better * Changed Prompt font install for RTD * Testing older numpy * Update Doumont styles * Replace default formatting example with gaussian plot * Add some comments to the gaussian plotting script * Tweak dark doumont style, update example png's * Fix readme image widths * Can we make Github actions update the png's for us? * Try again * Trying to fix conditional * Trying to get around permissions issue * Try a different pushing action * Try another push action * please work * Maybe this works * I hate GHA * Bump RTD dependencies * Try again * Improve readme * Rename styles example * Cleanup GHA * Update example figures * Add style names to style demo plots * Use svg images for example docs * Update example figures * Make sphinx gallery work properly * `black -l 120 .` * Update example figures * Remove old pngs * Friendship with png is over, svg is my best friend now * Update example figures * need to move files to auto_examples * Update example figures * Missed one svg * Update example figures * Ensure only GHA can push images to the repo * Update example figures * Add reference images and test against them * Add missing ref images * Improve dependency installation * typo * Trying to improve image comparison test * Make image test a little more forgiving * Even more forgiving * Super forgiving * backtracking * bisection * Try again with other matplotlib/numpy/pillow versions * So close * Please work * OK, back to 0.9 * Tweaked James * Added color cycle demo for each style * Fixed james gaussian and added refs * Alphabetize styles when returned * Fixed capitalization * Store odiff results as artifact to download * Upload artifact even if previous step fails * Make image comparison non-binding * Update ref nested_pie_chart.png * Update readme image paths * Comment out reference image upload * Add note on backwards incompatible changes to the readme Co-authored-by: Alasdair Gray <alachris@umich.edu> Co-authored-by: A-CGray <A-CGray@users.noreply.github.com>
1 parent 325af36 commit 4b669c3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+730
-393
lines changed

.github/workflows/niceplots.yml

+44-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ on:
88
tags:
99
- v*.*.*
1010
pull_request:
11-
branches: [main]
1211

1312
jobs:
1413
black:
@@ -21,27 +20,64 @@ jobs:
2120
runs-on: ubuntu-latest
2221
strategy:
2322
matrix:
24-
python-version: [3.7, 3.8, 3.9]
25-
numpy-version: ["1.16.6", "1.18.5"]
26-
mpl-version: ["3.2.*", "3.3.*", "3.4.*"]
23+
python-version: ["3.8", "3.9", "3.10"]
24+
numpy-version: ["1.19.*", "1.21.*", "1.24.*"]
25+
mpl-version: ["3.4.*", "3.6.*"]
26+
exclude:
27+
- python-version: "3.9"
28+
numpy-version: "1.19.*"
29+
- python-version: "3.10"
30+
numpy-version: "1.19.*"
2731
steps:
28-
- uses: actions/checkout@v2
32+
- uses: actions/checkout@v3
2933
- name: Set up Python ${{ matrix.python-version }}
3034
uses: actions/setup-python@v2
3135
with:
3236
python-version: ${{ matrix.python-version }}
33-
- name: Install dependencies
37+
- name: Install apt dependencies
38+
uses: awalsh128/cache-apt-pkgs-action@latest
39+
with:
40+
packages: fonts-cmu nodejs npm
41+
version: 1.0
42+
- name: Install node dependencies
43+
run: |
44+
sudo npm install -g odiff-bin
45+
- name: Install Prompt font
46+
run: |
47+
mkdir Prompt
48+
cd Prompt
49+
wget "https://fonts.google.com/download?family=Prompt" -O Prompt.zip
50+
unzip Prompt.zip
51+
mkdir ~/.fonts
52+
cp *.ttf ~/.fonts
53+
- name: Install python dependencies
3454
run: |
35-
sudo apt-get install fonts-cmu
3655
pip install --upgrade pip wheel
3756
pip install numpy==${{ matrix.numpy-version }}
3857
pip install matplotlib==${{ matrix.mpl-version }}
3958
pip install .
4059
- name: Test examples
4160
run: |
42-
# this is very janky for now
4361
cd examples
4462
bash testExamples.sh
63+
- name: Compare against reference images
64+
if: ${{ success() && matrix.python-version == '3.10' && matrix.numpy-version == '1.24.*' && matrix.mpl-version == '3.6.*' }}
65+
run: |
66+
cd examples
67+
bash ImageComparisonTest.sh
68+
- name: Upload examples if failed
69+
uses: actions/upload-artifact@v3
70+
if: ${{ failure() && matrix.python-version == '3.10' && matrix.numpy-version == '1.24.*' && matrix.mpl-version == '3.6.*' }}
71+
with:
72+
name: Examples
73+
path: examples/
74+
# - name: Upload new reference images
75+
# if: ${{ github.event_name == 'push' && success() && matrix.python-version == '3.10' && matrix.numpy-version == '1.24.*' && matrix.mpl-version == '3.6.*' }}
76+
# uses: stefanzweifel/git-auto-commit-action@v4
77+
# with:
78+
# file_pattern: 'examples/ref/*.png'
79+
# commit_message: Update reference images
80+
4581

4682
# --- publish to PyPI
4783
pypi:

.gitignore

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
# Ignore any pdf's or png's except in the examples folder
1+
# Ignore any figures, except the reference images used for testing
22
*.pdf
3-
!examples/*.pdf
43
*.png
5-
!examples/*.png
4+
!examples/ref/*.png
5+
*.svg
66

77
.vscode/
88

9+
# Ignore generated doc files
10+
doc/_build/
11+
doc/auto_examples/
12+
913
### Python ###
1014
# Byte-compiled / optimized / DLL files
1115
__pycache__/
@@ -152,4 +156,4 @@ dmypy.json
152156
!.vscode/tasks.json
153157
!.vscode/launch.json
154158
!.vscode/extensions.json
155-
*.code-workspace
159+
*.code-workspace

.readthedocs.yaml

+11-1
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,19 @@ version: 2
99
build:
1010
os: ubuntu-20.04
1111
tools:
12-
python: "3.9"
12+
python: "3.10"
1313
apt_packages:
1414
- fonts-cmu
15+
# Install the fonts for the james style
16+
jobs:
17+
pre_install:
18+
- mkdir Prompt
19+
- cd Prompt
20+
- wget "https://fonts.google.com/download?family=Prompt" -O Prompt.zip
21+
- unzip Prompt.zip
22+
- mkdir ~/.fonts
23+
- cp *.ttf ~/.fonts
24+
- cd ..
1525

1626
# Build documentation in the docs/ directory with Sphinx
1727
sphinx:

README.md

+40-19
Original file line numberDiff line numberDiff line change
@@ -7,53 +7,74 @@
77
[![PyPI - Downloads](https://img.shields.io/pypi/dm/niceplots)](https://pypi.org/project/niceplots/)
88
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
99

10-
<img src="https://raw.githubusercontent.com/mdolab/niceplots/main/examples/ParulaContours.png" width="62.22%" /> <img src="https://raw.githubusercontent.com/mdolab/niceplots/main/examples/optProb-shaded.png" width="35%" />
11-
<img src="https://raw.githubusercontent.com/mdolab/niceplots/main/examples/bar_chart.png" width="47.65%" /> <img src="https://raw.githubusercontent.com/mdolab/niceplots/main/examples/niceplotsPulseResponse.png" width="49.5%" />
10+
<img src="https://mdolab-niceplots.readthedocs-hosted.com/en/latest/_images/sphx_glr_plot_parula_contours_001.svg" width="61%" /> <img src="https://mdolab-niceplots.readthedocs-hosted.com/en/latest/_images/sphx_glr_plot_opt_prob_002.svg" width="38.2%" />
11+
<img src="https://mdolab-niceplots.readthedocs-hosted.com/en/latest/_images/sphx_glr_plot_bar_chart_001.svg" width="61%" /> <img src="https://mdolab-niceplots.readthedocs-hosted.com/en/latest/_images/sphx_glr_plot_style_demo_004.svg" width="38.2%" />
1212

13+
<!-- https://mdolab-niceplots.readthedocs-hosted.com/en/latest/_images/ -->
1314

14-
### How do I install?
15+
## How do I install?
1516

16-
Niceplots can be pip installed directly from PyPI
17+
NicePlots can be pip installed directly from PyPI
1718

1819
```shell
1920
pip install niceplots
2021
```
2122

22-
#### If you want to make changes
23+
### If you want to make changes
2324

2425
* Clone this repository, then enter the folder in the command line terminal.
2526
* Enter `pip install -e .` within the `niceplots` folder.
2627

27-
#### Font installation (optional)
28+
### Font installation (optional)
2829

29-
Niceplots will try and use the [computer modern bright](https://tug.org/FontCatalogue/computermodernbright/) font for the best looking plots so be sure to install it as a system font if you want to recreate the style of the plots above.
30-
Otherwise, niceplots will still work but revert back to the matplotlib default sans-serif font, DejaVu Sans.
30+
NicePlots styles use fonts that do not ship with most operating systems, so you'll need to install them separately.
31+
If they are not installed, matplotlib will revert back to its default sans-serif font, DejaVu Sans.
32+
33+
The font used by each style is as follows:
34+
- doumont-light (default niceplots): CMU Bright
35+
- doumont-dark: CMU Bright
36+
- james-dark: Prompt
37+
- james-light: Prompt
38+
39+
Install the fonts on your system and then delete Matplotlib's font cache, which is located in `~/.cache/matplotlib` by default on most operating systems.
40+
Matplotlib will rebuild the font cache next time it is run and (hopefully) find the new fonts.
41+
42+
#### CMU Bright (doumont-light and doumont-dark)
43+
44+
The computer modern bright font can be downloaded from [this link](https://tug.org/FontCatalogue/computermodernbright/).
45+
Alternatively, on Ubuntu, the font can be installed with the following commands:
3146

32-
To install the font on Ubuntu, run the following commands:
3347
```
3448
sudo apt-get update
3549
sudo apt-get install fonts-cmu
3650
```
3751
Arch linux users can get the font by installing the `otf-cm-unicode` package from AUR.
3852

39-
If niceplots doesn't recognize the font, it might be necessary to delete Matplotlib's font cache file from its location on your computer, likely in `~/.cache/matplotlib`
53+
#### Prompt (james-dark and james-light)
54+
55+
The Prompt font can be download from [Google Fonts](https://fonts.google.com/specimen/Prompt).
56+
57+
## How do I get set up?
58+
59+
* `import matplotlib.pyplot as plt` and `import niceplots` at the top of a file where you would like to use any function defined in this package.
60+
* Use `plt.style.use(niceplots.get_style())` to set some defaults for nice-looking plots. You can also try passing different styles to `get_style()`, such as NicePlots' `"james-dark"` or any of matplotlib's styles (see the function's documentation for a full list of available NicePlots styles).
61+
* Take advantage of NicePlots' helper functions, including (but not limited to) `adjust_spines`, `horiz_bar`, and `plot_nested_pie`, which are all documented in the [examples gallery](https://mdolab-niceplots.readthedocs-hosted.com/en/latest/auto_examples/index.html).
62+
* Admire your beautiful data.
4063

41-
### How do I get set up?
64+
## Do you have docs?
4265

43-
* Use `import niceplots` at the top of a file where you would like to use any function defined in this package.
44-
* Use `niceplots.setRCParams()` to set some matplotlib defaults for nice looking plots. Set `dark_mode=True` and `set_background_color=True` to make plots with a dark background.
45-
* Use `niceplots.All()` after all the plot commands to apply the niceplot standards on the figure.
46-
* To use the Matlab colormap "parula", execute `from niceplots import parula` then use `parula.parula_map` as your colormap within your plotting script. See the contour plot example code for an example of this.
66+
Sort of, you can find our examples gallery and API documentation [here](https://mdolab-niceplots.readthedocs-hosted.com/en/latest)
4767

48-
### Do you have docs?
68+
## Help, my old NicePlots code doesn't work anymore!
4969

50-
Sort of, you can find our examples gallery and api documentation [here](https://mdolab-niceplots.readthedocs-hosted.com/en/latest)
70+
We made a couple of changes to the API in version 2.0.0, most of them can be fixed with a simple find and replace.
71+
Check the [release notes](https://github.com/mdolab/niceplots/releases/tag/v2.0.0) for more details.
5172

52-
### Contribution guidelines
73+
## Contribution guidelines
5374

5475
* Make any changes you see fit. Please fork your own version and submit a pull request.
5576

56-
### Who do I talk to?
77+
## Who do I talk to?
5778

5879
* Alasdair Gray, alachris@umich.edu
5980
* Eytan Adler, eytana@umich.edu

doc/conf.py

+43
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,46 @@
11
from sphinx_mdolab_theme.config import *
2+
from glob import glob
3+
import shutil
4+
import os
5+
from sphinx_gallery.scrapers import figure_rst
6+
from pathlib import PurePosixPath
7+
8+
9+
class svgScraper(object):
10+
"""This is a custom scraper for sphinx-gallery that allows us to use the svg files written by our examples. It is
11+
almost entirely copied from the PNGScraper shown at:
12+
https://sphinx-gallery.github.io/dev/advanced.html#example-2-detecting-image-files-on-disk
13+
"""
14+
15+
def __init__(self):
16+
self.seen = set()
17+
18+
def __repr__(self):
19+
return "svgScraper"
20+
21+
def __call__(self, block, block_vars, gallery_conf):
22+
# Find all svg files in the directory of this example.
23+
path_current_example = os.path.dirname(block_vars["src_file"])
24+
svgs = sorted(glob(os.path.join(path_current_example, "*.svg")))
25+
26+
# Get the name of the current example, e.g if the file is called "plot_nested_pie_chart.py",
27+
# then example_name = "nested_pie_chart"
28+
example_name = os.path.splitext(os.path.basename(block_vars["src_file"]))[0].split("plot_")[0]
29+
30+
# Iterate through svgs, copy them to the sphinx-gallery output directory
31+
image_names = list()
32+
image_path_iterator = block_vars["image_path_iterator"]
33+
for svg in svgs:
34+
if svg not in self.seen and example_name.lower() in svg.lower():
35+
self.seen |= set(svg)
36+
this_image_path = image_path_iterator.next()
37+
image_path = PurePosixPath(this_image_path)
38+
image_path = image_path.with_suffix(".svg")
39+
image_names.append(image_path)
40+
shutil.move(svg, image_path)
41+
# Use the `figure_rst` helper function to generate rST for image files
42+
return figure_rst(image_names, gallery_conf["src_dir"])
43+
244

345
# -- Project information -----------------------------------------------------
446
project = "niceplots"
@@ -8,4 +50,5 @@
850
sphinx_gallery_conf = {
951
"examples_dirs": "../examples", # path to your example scripts
1052
"gallery_dirs": "auto_examples", # path to where to save gallery generated output
53+
"image_scrapers": (svgScraper(),),
1154
}

doc/index.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
You can adapt this file completely to your liking, but it should at least
44
contain the root `toctree` directive.
55
6-
Welcome to niceplots's documentation!
6+
Welcome to NicePlots's documentation!
77
=====================================
88

99

doc/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
sphinx_mdolab_theme
22
sphinx-gallery
3-
matplotlib>=3.4
3+
matplotlib>=3.6

examples/ImageComparisonTest.sh

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/bin/bash
2+
3+
# This script compares the images generated by the example scripts to a set of reference images
4+
5+
test_passed=true # Kepp track of whether any tests fail
6+
7+
# First check that there aren't any images produced by the examples that don't have a reference image
8+
for f in *.png
9+
do
10+
if ! test -f "ref/$f"; then
11+
echo ""
12+
echo "$f doesn't have a reference image to compare to"
13+
test_passed=false
14+
fi
15+
done
16+
17+
mkdir -p diffs
18+
19+
# For each image in the ref directory, check that there is a corresponding image in the current directory and then compare them
20+
for f in ref/*.png
21+
do
22+
echo ""
23+
base_name=$(basename ${f})
24+
25+
if test -f "$base_name"; then
26+
filename_no_ext="${base_name%.*}"
27+
echo "Comparing $base_name and $f"
28+
odiff --antialiasing --threshold=0.1 --diff-mask $base_name $f diffs/${filename_no_ext}-diff.png
29+
if [ $? -ne 0 ]; then
30+
test_passed=false
31+
fi
32+
else
33+
echo "Couldn't find image to compare against $f"
34+
test_passed=false
35+
fi
36+
done
37+
38+
echo ""
39+
echo "==========================="
40+
if [ "$test_passed" = true ] ; then
41+
echo "All comparisons passed"
42+
echo "==========================="
43+
exit 0
44+
else
45+
echo "Some comparisons failed"
46+
echo "==========================="
47+
exit 0 # In future (if we can make the image comparison more robust) we should exit with a non-zero exit code (e.g. 1)
48+
fi

examples/ParulaContours.png

-1010 KB
Binary file not shown.

examples/ParulaContours_dark.png

-1010 KB
Binary file not shown.

examples/ParulaContours_grey.png

-958 KB
Binary file not shown.

examples/ParulaContours_navy.png

-979 KB
Binary file not shown.

examples/bar_chart.png

-385 KB
Binary file not shown.

examples/coloredLine.png

-362 KB
Binary file not shown.

examples/coloredLine_dark.png

-299 KB
Binary file not shown.

examples/defaultPulseResponse.png

-685 KB
Binary file not shown.

examples/niceplotsPulseResponse.png

-846 KB
Binary file not shown.

examples/optProb-hashed.png

-1.82 MB
Binary file not shown.

examples/optProb-shaded.png

-1.55 MB
Binary file not shown.

examples/opt_stacks.png

-308 KB
Binary file not shown.

examples/opt_stacks_more_data.png

-637 KB
Binary file not shown.

examples/plot_bar_chart.py

+14-32
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,23 @@
33
=========
44
An example of a bar chart.
55
"""
6-
import random
76
import matplotlib.pyplot as plt
87
import niceplots
98

10-
niceplots.setRCParams()
119

12-
try:
13-
# use random words for the example
14-
word_file = "/usr/share/dict/words"
15-
words = open(word_file).read().splitlines()
16-
wl = len(words)
17-
random.seed(100)
10+
header = ["Method", "Time (sec)"]
11+
labels = [
12+
"Analytic Forward",
13+
"Analytic Adjoint",
14+
"FD Forward Diff.",
15+
"FD Central Diff.",
16+
"FD Backward Diff.",
17+
]
18+
times = [0.00456, 0.00847, 0.0110, 0.0213, 0.011]
19+
nd = 4
1820

19-
def rw():
20-
return random.choice(words)
21+
with plt.style.context(niceplots.get_style()):
22+
niceplots.horiz_bar(labels, times, header, nd=nd, size=[7, 0.65])
2123

22-
header = [rw(), rw()]
23-
n = 15 # number of bars to create
24-
labels = [rw() for i in range(n)]
25-
times = [random.random() * random.randint(0, 1000) for i in range(n)]
26-
nd = 1
27-
28-
except FileNotFoundError: # noqa: E722 if user is not on a *nix system
29-
header = ["Method", "Time (sec)"]
30-
labels = [
31-
"Analytic Forward",
32-
"Analytic Adjoint",
33-
"FD Forward Diff.",
34-
"FD Central Diff.",
35-
"FD Backward Diff.",
36-
]
37-
times = [0.00456, 0.00847, 0.0110, 0.0213, 0.011]
38-
nd = 4
39-
40-
niceplots.horiz_bar(labels, times, header, nd=nd, size=[7, 0.65])
41-
42-
plt.savefig("bar_chart.pdf", bbox_inches="tight")
43-
plt.savefig("bar_chart.png", dpi=400, bbox_inches="tight")
24+
plt.savefig("bar_chart.png")
25+
plt.savefig("bar_chart.svg")

0 commit comments

Comments
 (0)