Skip to content

Enhanced plotting option (latex backend and/or unit change) #4414

Closed
@sdat2

Description

@sdat2

One problem with xarray's default plotting functionality is that the plots look quite mediocre, and so if you want to present your results, then you may have to go in and change all the defaults, and relabel the graphs. This seems like wasted effort.

xarray could support pdflatex backend usage by matplotlib by sanitizing the labels.

It could also change units from degrees_north to the more presentable$^{\circ}$N.

An example of doing this is shown below:

import numpy as np
import re
import datetime
import matplotlib
import matplotlib.pyplot as plt
import xarray as xr

def mpl_params(quality='high'):
    """
    Apply my plotting style to produce nice looking figures.
    Call this at the start of a script which uses matplotlib,
    and choose the correct setting.
    :return:
    """
    if quality == 'high':
        matplotlib.style.use('seaborn-colorblind')
        param_set = {"pgf.texsystem": "pdflatex",
                     "text.usetex": True,
                     "font.family": "serif",
                     "font.serif": [],
                     "font.sans-serif": ["DejaVu Sans"],
                     "font.monospace": [],
                     "lines.linewidth": 0.75,
                     "pgf.preamble": [r"\usepackage[utf8x]{inputenc} \usepackage[T1]{fontenc}"]
                     }
    else:
        matplotlib.style.use('seaborn-colorblind')
        param_set = {"text.usetex": False,
                     "lines.linewidth": 0.75,
                    "font.family": "sans-serif",
                     "font.serif": [],
                     "font.sans-serif": ["DejaVu Sans"],
                     }

    matplotlib.rcParams.update(param_set)

def tex_escape(text):
    """
    It is better to plot in TeX, but this involves escaping strings.
    from:
        https://stackoverflow.com/questions/16259923/
        how-can-i-escape-latex-special-characters-inside-django-templates
        :param text: a plain text message
        :return: the message escaped to appear correctly in LaTeX
    # removed unicode(key) from re.escape because this seemed an unnecessary,
      and was throwing an error.
    """
    conv = {
            '&': r'\&',
            '%': r'\%',
            '$': r'\$',
            '#': r'\#',
            '_': r'\_',
            '{': r'\{',
            '}': r'\}',
            '~': r'\textasciitilde{}',
            '^': r'\^{}',
            '\\': r'\textbackslash{}',
            '<': r'\textless{}',
            '>': r'\textgreater{}',
            }
    regex = re.compile('|'.join(re.escape(key) for key in sorted(conv.keys(), key=lambda item: - len(item))))
    return regex.sub(lambda match: conv[match.group()], text)

def proper_units(text):
    conv = {
            'degC': r'$^{\circ}$C',
            'degrees\_celsius': r'$^{\circ}$C',
            'degrees\_north': r'$^{\circ}$N',
            'degrees\_east': r'$^{\circ}$E',
            }
    regex = re.compile('|'.join(re.escape(key) for key in sorted(conv.keys(), key=lambda item: - len(item))))
    return regex.sub(lambda match: conv[match.group()], text)
    
mpl_params(quality='high')
ds = xr.tutorial.load_dataset('air_temperature')
plot_data = ds.air.isel(time=120)
plot = plot_data.plot(center=273.15, cbar_kwargs={'label': 'K'})
plt.title(tex_escape('time = '+ np.datetime_as_string(plot_data.coords['time'].data, unit='D')))
plt.xlabel(proper_units(tex_escape(ds.coords['lon'].long_name + ' [' + ds.coords['lon'].units + ']')))
plt.ylabel(proper_units(tex_escape(ds.coords['lat'].long_name + ' ['+ ds.coords['lat'].units + ']')))
plt.show()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions