Giter VIP home page Giter VIP logo

aquarel's Introduction

Aquarel 🎨

PyPi License Documentation Status

Aquarel is a lightweight templating engine and wrapper around Matplotlibs' rcparams to make styling plots simple. Aquarel templates can be defined programmatically and be serialized and shared in a JSON format.

Full documentation is available at aquarel.readthedocs.io.

Installation

Install via pip:

python -m pip install aquarel

Usage

Applying a style

Styles can be either applied globally

from aquarel import load_theme

theme = load_theme("arctic_light")
theme.apply()
# ... plotting code here
theme.apply_transforms()

...or with a context manager:

from aquarel import load_theme

with load_theme("arctic_light"):
    figure = # ... plotting code here
Transforms

Themes may specify transforms. Transforms are functions applied on the finished plot to achieve aesthetics that are not possibly by means of rcparams only. For example, to trim the axes, one could apply the trim transform:

from aquarel import load_theme

with load_theme("arctic_light").set_transforms(trim=True):
    figure = # ... plotting code here

# plt.show() or savefig() have to be called outside the context manager to have the transforms correctly applied.
figure.savefig()

However, there is one important thing to keep in mind: since transforms require the matplotlib figure/axes object to be present and finished, they have to be applied after the plotting code. When using a theme with a context manager, this is automatically done in the __exit__ call. If global usage is desired, Theme.apply_transforms() has to be called after every figure. This also means that calls that make use of the finished figure, i.e. plt.show or plt.savefig have to commence after transform application, so outside the context manager.

Customization & Theme Creation

Besides loading a predefined theme, you can create a new theme

from aquarel import Theme

theme = (
    Theme(name="demo", description="A demo theme.")
    .set_grid(draw=True, width=0.5)
    .set_font(family="monospace")
    .set_color(grid_color="blue")
)

...modify an existing one

from aquarel import load_theme

theme = (
    load_theme("arctic_light")
    .set_grid(width=2)
)

...and write and load your custom styles to and from disk:

from aquarel import Theme

theme = Theme.from_file("custom.json")
theme.save("custom.json")

If the simplified API of aquarel is not sufficient for your use-case, you can also directly modify the underlying rcparams with overrides:

from aquarel import load_theme

theme = load_theme("arctic_light").set_overrides({
    "ytick.minor.visible": False,
    "xtick.minor.visible": True
})

Themes

aquarel ships with several pre-defined themes that are designed to showcase its templating capabilities. Add your own with a pull request!

Name Description Preview
ambivalent Transparent backgrounds with grey text $\textcolor{#838383}{\blacksquare}$ that are accessible / legible and {light, dark}-mode independent
arctic_dark Frosty dark theme based on the nord color scheme
arctic_light Frosty dark theme based on the nord color scheme
boxy_dark Dark theme with enclosing box and grid
boxy_light Light theme with enclosing box and grid
gruvbox_dark Dark theme with pastel retro groove colors
gruvbox_light Light theme with pastel retro groove colors
minimal_dark Dark theme with minimal visual elements
minimal_light Light theme with minimal visual elements
scientific Space-efficient and color-blind friendly theme for printing on paper
umbra_dark Balanced dark theme based on the penumbra color scheme
umbra_light Balanced light theme based on the penumbra color scheme

FAQ

How is this different from matplotlib style sheets?

aquarel is a wrapper around the stylesheets, so everything you can do with stylesheets can be achieved with aquarel. However there are some notable shortcomings of stylesheets that aquarel adresses:

  1. On-the-fly templating – the stylesheets are applied once and are then used for every plot in the current plotting context (py-file, notebook, ipython session, ...). aquarel takes a different approach here and aims to provide per-plot styling with optional temporary changes. The style aquarel applies lasts throughout the context manager (with aquarel.Theme:), and switches back to whatever is the global default style outside of it. This allows you to do plot-level temporary changes. You have one plot in your notebook that needs no minor ticks? just with theme.set_ticks(): for this plot only.
  2. Simplified templating: matplotlib stylesheets have a lot of redundant keys for most applications. For example, you rarely want to have different colors for both axes; while possible with a stylefile, its cumbersome to change all the different keys to achieve a uniform look. aquarel simplifies this with e.x. a single set_color(ticks="#eee") call, which changes all related and relevant keys for ticks. Note that this simplifies the API, but does not restrict capabilities: the set_overrides method accepts every possible stylefile key if you want to access low-level styling.
  3. Transforms: some style elements, like trimmed axes, are not achievable with stylesheets alone (see README for more informations). aquarel defines a few of these transforms (and hopefully many more in the future), and makes them persistable and shareable through aquarel themes. Instead of having to apply a seaborn despine after every plot, you can have a global style that specifies a trim, and have consistent styling throughout with minimal code repetition.

aquarel's People

Contributors

frostime avatar hasan-alper avatar kianmeng avatar lgienapp avatar lucianosrp avatar saforem2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

aquarel's Issues

Pandas plots do not have a modified style applied

When using

with load_theme("umbra_light"):
    pd.Series({"ROOTS":1.6, "OPT":1.02, "GPT3":1.63, "The Pile":0.89}).sort_values().plot.bar()

the style is applied as expected. However, any set_ calls on the style are not. Instead using seaborn to plot instead of pandas fixes it. Why?

Add FAQ to README

Possible Questions:

  • How is this different from style sheets? (#15)
  • Why can't I change an elements color in its corresponding set call directly?

No themes available.

I just did a pip install.

from aquarel import list_themes
list_themes()

returns

[]

and load_theme("arctic_light")

raises

 ValueError: No theme named 'arctic_light' found.

Windows 11, Anaconda Python 3.9 installation.

I stepped into the code, it is globbing 'C:\anaconda3\lib\site-packages\aquarel\themes\*.json', but there is no
themes subdirectory in 'C:\anaconda3\lib\site-packages\aquarel, and a search of my drive confirms that arctic_light.json is not anywhere on my drive.

As an aside, I recommend using os.path.join to create the filepath, you have hardcoded in unix style with f"{loc}/themes/*.json"

os.path.join(loc, 'themes', '*.json')

Add unit tests

Each set_ method should have an associated unit test that checks if the underlying matplotlib.rcparams are updated successfully and correctly.

Grid alpha value throws type error

with load_theme("arctic_light").set_grid(axis="x"):
    pd.Series(sizes).sort_values().plot.bar()

produces

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_16842/1244744067.py in <module>
----> 1 with load_theme("arctic_light").set_grid(axis="x"):
      2     pd.Series(sizes).sort_values().plot.bar()

/media/ssd/BIGSCIENCE/env/lib/python3.7/site-packages/aquarel/theme.py in set_grid(self, draw, axis, ticks, alpha, style, width)
    432                 "axis": axis if axis in self._axis_options else None,
    433                 "ticks": ticks if ticks in self._tick_options else None,
--> 434                 "alpha": alpha if 0 <= alpha <= 1 else None,
    435                 "style": style if style in self._line_style_options else None,
    436                 "width": width,

TypeError: '<=' not supported between instances of 'int' and 'NoneType'

Add legend styling options

Introduce a set_legend option to style the legend.
Maybe also legend-specific transforms, for example location?

set_tick_labels location parameter produces a value error

theme = load_theme("arctic_dark").set_tick_labels(location="top")
theme.apply()

produces

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In [2], line 2
      1 theme = load_theme("arctic_dark").set_tick_labels(location="top")
----> 2 theme.apply()

File ~/Documents/aquarel/aquarel/theme.py:325, in Theme.apply(self)
    323         if mapped_key == "axes.prop_cycle":
    324             value = cycler("color", value)
--> 325         mpl.rcParams.update({sub_key: value})
    326 else:
    327     # Special treatment for color palette, as this is otherwise not JSON serializable
    328     if mapped_key == "axes.prop_cycle":

File /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/_collections_abc.py:940, in MutableMapping.update(self, other, **kwds)
    938 if isinstance(other, Mapping):
    939     for key in other:
--> 940         self[key] = other[key]
    941 elif hasattr(other, "keys"):
    942     for key in other.keys():

File ~/Documents/aquarel/venv/lib/python3.9/site-packages/matplotlib/__init__.py:648, in RcParams.__setitem__(self, key, val)
    646         cval = self.validate[key](val)
    647     except ValueError as ve:
--> 648         raise ValueError(f"Key {key}: {ve}") from None
    649     dict.__setitem__(self, key, cval)
    650 except KeyError as err:

ValueError: Key xaxis.labellocation: 'top' is not a valid value for xaxis.labellocation; supported values are ['left', 'center', 'right']

If location is left

ValueError: Key yaxis.labellocation: 'left' is not a valid value for yaxis.labellocation; supported values are ['bottom', 'center', 'top']

In the docs, valid options are given as this:

location (Optional[str]) – location of the tick labels, can be {“left”, “right”, “bottom”, “top”, “center”}, default: center

Conda package

Hi,

awesome package you provide here. I wonder if you also provide a conda package?

Thanks and best,

Joachim

Can not display in jupyter lab

I'm trying aquarel in jupyter lab, but it's doesn't work sometimes (can't display in jupyter lab page).

You may try this code:

import numpy as np
import matplotlib.pyplot as plt
from aquarel import load_theme

x = np.linspace(0, 10, 1000)
sinx = np.sin(x)
cosx = np.cos(x)

with load_theme('boxy_light'):
    plt.subplot(2, 1, 1)
    plt.plot(x, sinx)
    plt.plot(x, cosx)
    
    plt.subplot(2, 1, 2)
    plt.plot(x, cosx)
    plt.show()

My environment:

python: 3.10.8
aquarel: 0.0.5
matplotlib: 3.5.2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.