Skip to content

Commit

Permalink
Switch to using stylesheets (#30)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: A-CGray <[email protected]>
  • Loading branch information
3 people authored Jan 25, 2023
1 parent 325af36 commit 4b669c3
Show file tree
Hide file tree
Showing 54 changed files with 730 additions and 393 deletions.
52 changes: 44 additions & 8 deletions .github/workflows/niceplots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ on:
tags:
- v*.*.*
pull_request:
branches: [main]

jobs:
black:
Expand All @@ -21,27 +20,64 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8, 3.9]
numpy-version: ["1.16.6", "1.18.5"]
mpl-version: ["3.2.*", "3.3.*", "3.4.*"]
python-version: ["3.8", "3.9", "3.10"]
numpy-version: ["1.19.*", "1.21.*", "1.24.*"]
mpl-version: ["3.4.*", "3.6.*"]
exclude:
- python-version: "3.9"
numpy-version: "1.19.*"
- python-version: "3.10"
numpy-version: "1.19.*"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
- name: Install apt dependencies
uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: fonts-cmu nodejs npm
version: 1.0
- name: Install node dependencies
run: |
sudo npm install -g odiff-bin
- name: Install Prompt font
run: |
mkdir Prompt
cd Prompt
wget "https://fonts.google.com/download?family=Prompt" -O Prompt.zip
unzip Prompt.zip
mkdir ~/.fonts
cp *.ttf ~/.fonts
- name: Install python dependencies
run: |
sudo apt-get install fonts-cmu
pip install --upgrade pip wheel
pip install numpy==${{ matrix.numpy-version }}
pip install matplotlib==${{ matrix.mpl-version }}
pip install .
- name: Test examples
run: |
# this is very janky for now
cd examples
bash testExamples.sh
- name: Compare against reference images
if: ${{ success() && matrix.python-version == '3.10' && matrix.numpy-version == '1.24.*' && matrix.mpl-version == '3.6.*' }}
run: |
cd examples
bash ImageComparisonTest.sh
- name: Upload examples if failed
uses: actions/upload-artifact@v3
if: ${{ failure() && matrix.python-version == '3.10' && matrix.numpy-version == '1.24.*' && matrix.mpl-version == '3.6.*' }}
with:
name: Examples
path: examples/
# - name: Upload new reference images
# if: ${{ github.event_name == 'push' && success() && matrix.python-version == '3.10' && matrix.numpy-version == '1.24.*' && matrix.mpl-version == '3.6.*' }}
# uses: stefanzweifel/git-auto-commit-action@v4
# with:
# file_pattern: 'examples/ref/*.png'
# commit_message: Update reference images


# --- publish to PyPI
pypi:
Expand Down
12 changes: 8 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# Ignore any pdf's or png's except in the examples folder
# Ignore any figures, except the reference images used for testing
*.pdf
!examples/*.pdf
*.png
!examples/*.png
!examples/ref/*.png
*.svg

.vscode/

# Ignore generated doc files
doc/_build/
doc/auto_examples/

### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down Expand Up @@ -152,4 +156,4 @@ dmypy.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
*.code-workspace
12 changes: 11 additions & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,19 @@ version: 2
build:
os: ubuntu-20.04
tools:
python: "3.9"
python: "3.10"
apt_packages:
- fonts-cmu
# Install the fonts for the james style
jobs:
pre_install:
- mkdir Prompt
- cd Prompt
- wget "https://fonts.google.com/download?family=Prompt" -O Prompt.zip
- unzip Prompt.zip
- mkdir ~/.fonts
- cp *.ttf ~/.fonts
- cd ..

# Build documentation in the docs/ directory with Sphinx
sphinx:
Expand Down
59 changes: 40 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,74 @@
[![PyPI - Downloads](https://img.shields.io/pypi/dm/niceplots)](https://pypi.org/project/niceplots/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)

<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%" />
<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%" />
<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%" />
<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%" />

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

### How do I install?
## How do I install?

Niceplots can be pip installed directly from PyPI
NicePlots can be pip installed directly from PyPI

```shell
pip install niceplots
```

#### If you want to make changes
### If you want to make changes

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

#### Font installation (optional)
### Font installation (optional)

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.
Otherwise, niceplots will still work but revert back to the matplotlib default sans-serif font, DejaVu Sans.
NicePlots styles use fonts that do not ship with most operating systems, so you'll need to install them separately.
If they are not installed, matplotlib will revert back to its default sans-serif font, DejaVu Sans.

The font used by each style is as follows:
- doumont-light (default niceplots): CMU Bright
- doumont-dark: CMU Bright
- james-dark: Prompt
- james-light: Prompt

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.
Matplotlib will rebuild the font cache next time it is run and (hopefully) find the new fonts.

#### CMU Bright (doumont-light and doumont-dark)

The computer modern bright font can be downloaded from [this link](https://tug.org/FontCatalogue/computermodernbright/).
Alternatively, on Ubuntu, the font can be installed with the following commands:

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

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`
#### Prompt (james-dark and james-light)

The Prompt font can be download from [Google Fonts](https://fonts.google.com/specimen/Prompt).

## How do I get set up?

* `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.
* 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).
* 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).
* Admire your beautiful data.

### How do I get set up?
## Do you have docs?

* Use `import niceplots` at the top of a file where you would like to use any function defined in this package.
* 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.
* Use `niceplots.All()` after all the plot commands to apply the niceplot standards on the figure.
* 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.
Sort of, you can find our examples gallery and API documentation [here](https://mdolab-niceplots.readthedocs-hosted.com/en/latest)

### Do you have docs?
## Help, my old NicePlots code doesn't work anymore!

Sort of, you can find our examples gallery and api documentation [here](https://mdolab-niceplots.readthedocs-hosted.com/en/latest)
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.
Check the [release notes](https://github.com/mdolab/niceplots/releases/tag/v2.0.0) for more details.

### Contribution guidelines
## Contribution guidelines

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

### Who do I talk to?
## Who do I talk to?

* Alasdair Gray, [email protected]
* Eytan Adler, [email protected]
Expand Down
43 changes: 43 additions & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,46 @@
from sphinx_mdolab_theme.config import *
from glob import glob
import shutil
import os
from sphinx_gallery.scrapers import figure_rst
from pathlib import PurePosixPath


class svgScraper(object):
"""This is a custom scraper for sphinx-gallery that allows us to use the svg files written by our examples. It is
almost entirely copied from the PNGScraper shown at:
https://sphinx-gallery.github.io/dev/advanced.html#example-2-detecting-image-files-on-disk
"""

def __init__(self):
self.seen = set()

def __repr__(self):
return "svgScraper"

def __call__(self, block, block_vars, gallery_conf):
# Find all svg files in the directory of this example.
path_current_example = os.path.dirname(block_vars["src_file"])
svgs = sorted(glob(os.path.join(path_current_example, "*.svg")))

# Get the name of the current example, e.g if the file is called "plot_nested_pie_chart.py",
# then example_name = "nested_pie_chart"
example_name = os.path.splitext(os.path.basename(block_vars["src_file"]))[0].split("plot_")[0]

# Iterate through svgs, copy them to the sphinx-gallery output directory
image_names = list()
image_path_iterator = block_vars["image_path_iterator"]
for svg in svgs:
if svg not in self.seen and example_name.lower() in svg.lower():
self.seen |= set(svg)
this_image_path = image_path_iterator.next()
image_path = PurePosixPath(this_image_path)
image_path = image_path.with_suffix(".svg")
image_names.append(image_path)
shutil.move(svg, image_path)
# Use the `figure_rst` helper function to generate rST for image files
return figure_rst(image_names, gallery_conf["src_dir"])


# -- Project information -----------------------------------------------------
project = "niceplots"
Expand All @@ -8,4 +50,5 @@
sphinx_gallery_conf = {
"examples_dirs": "../examples", # path to your example scripts
"gallery_dirs": "auto_examples", # path to where to save gallery generated output
"image_scrapers": (svgScraper(),),
}
2 changes: 1 addition & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to niceplots's documentation!
Welcome to NicePlots's documentation!
=====================================


Expand Down
2 changes: 1 addition & 1 deletion doc/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
sphinx_mdolab_theme
sphinx-gallery
matplotlib>=3.4
matplotlib>=3.6
48 changes: 48 additions & 0 deletions examples/ImageComparisonTest.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash

# This script compares the images generated by the example scripts to a set of reference images

test_passed=true # Kepp track of whether any tests fail

# First check that there aren't any images produced by the examples that don't have a reference image
for f in *.png
do
if ! test -f "ref/$f"; then
echo ""
echo "$f doesn't have a reference image to compare to"
test_passed=false
fi
done

mkdir -p diffs

# For each image in the ref directory, check that there is a corresponding image in the current directory and then compare them
for f in ref/*.png
do
echo ""
base_name=$(basename ${f})

if test -f "$base_name"; then
filename_no_ext="${base_name%.*}"
echo "Comparing $base_name and $f"
odiff --antialiasing --threshold=0.1 --diff-mask $base_name $f diffs/${filename_no_ext}-diff.png
if [ $? -ne 0 ]; then
test_passed=false
fi
else
echo "Couldn't find image to compare against $f"
test_passed=false
fi
done

echo ""
echo "==========================="
if [ "$test_passed" = true ] ; then
echo "All comparisons passed"
echo "==========================="
exit 0
else
echo "Some comparisons failed"
echo "==========================="
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)
fi
Binary file removed examples/ParulaContours.png
Binary file not shown.
Binary file removed examples/ParulaContours_dark.png
Binary file not shown.
Binary file removed examples/ParulaContours_grey.png
Binary file not shown.
Binary file removed examples/ParulaContours_navy.png
Binary file not shown.
Binary file removed examples/bar_chart.png
Binary file not shown.
Binary file removed examples/coloredLine.png
Binary file not shown.
Binary file removed examples/coloredLine_dark.png
Binary file not shown.
Binary file removed examples/defaultPulseResponse.png
Binary file not shown.
Binary file removed examples/niceplotsPulseResponse.png
Binary file not shown.
Binary file removed examples/optProb-hashed.png
Binary file not shown.
Binary file removed examples/optProb-shaded.png
Binary file not shown.
Binary file removed examples/opt_stacks.png
Binary file not shown.
Binary file removed examples/opt_stacks_more_data.png
Binary file not shown.
46 changes: 14 additions & 32 deletions examples/plot_bar_chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,23 @@
=========
An example of a bar chart.
"""
import random
import matplotlib.pyplot as plt
import niceplots

niceplots.setRCParams()

try:
# use random words for the example
word_file = "/usr/share/dict/words"
words = open(word_file).read().splitlines()
wl = len(words)
random.seed(100)
header = ["Method", "Time (sec)"]
labels = [
"Analytic Forward",
"Analytic Adjoint",
"FD Forward Diff.",
"FD Central Diff.",
"FD Backward Diff.",
]
times = [0.00456, 0.00847, 0.0110, 0.0213, 0.011]
nd = 4

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

header = [rw(), rw()]
n = 15 # number of bars to create
labels = [rw() for i in range(n)]
times = [random.random() * random.randint(0, 1000) for i in range(n)]
nd = 1

except FileNotFoundError: # noqa: E722 if user is not on a *nix system
header = ["Method", "Time (sec)"]
labels = [
"Analytic Forward",
"Analytic Adjoint",
"FD Forward Diff.",
"FD Central Diff.",
"FD Backward Diff.",
]
times = [0.00456, 0.00847, 0.0110, 0.0213, 0.011]
nd = 4

niceplots.horiz_bar(labels, times, header, nd=nd, size=[7, 0.65])

plt.savefig("bar_chart.pdf", bbox_inches="tight")
plt.savefig("bar_chart.png", dpi=400, bbox_inches="tight")
plt.savefig("bar_chart.png")
plt.savefig("bar_chart.svg")
Loading

0 comments on commit 4b669c3

Please sign in to comment.