diff --git a/docs/source/customise.rst b/docs/source/customise.rst index 8430050..4e0ff16 100644 --- a/docs/source/customise.rst +++ b/docs/source/customise.rst @@ -10,53 +10,446 @@ This section discusses how finer control of the tephigram isobars, saturated adi import tephi from pprint import pprint -There are two main methods to customise tephigram lines: default values, and individual values. Default values apply to -ALL axes by default, whereas individual values affect only the axes you change them on. - -The default values of barbs, isobars, mixing ratios, isopleths and wet adiabats are stored in the -``constants.defaults`` dictionary. Changing these values will change the default behaviour of the tephigram. - -Individual values can only be changed for the three adjustable isopleths (isobars, humidity mixing ratios, and wet -adiabats. - -Barbs ------ -Barb defaults can be altered via the ``constants.defaults`` dictionary. - -from tephi.constants import defaults -defaults["barbs_gutter"] -defaults["barbs_length"] -defaults["barbs_linewidth"] -defaults["barbs_zorder"] - -Isopleths ---------- - -Defaults -^^^^^^^^ -.. note:: - "" can be replaced by any of "isobar", "mixing_ratio" and "wet_adiabat", to change the - respective isopleth defaults. - -from tephi.constants import defaults -defaults["_line"] -defaults["_nbins"] -defaults["_text"] -defaults["_ticks"] -defaults["_min_"] -defaults["_max_"] - -Individual -^^^^^^^^^^ - -If you wish to change the behaviour of the three additional gridlines (isobars, wet adiabats, humidity mixing ratios) -for a specific axes, you can edit the gridline artist properties. - -tephigram = TephiAxes() -tephigram.add_() -tephigram. - -.. note:: - Currently, the only directly editable values are nbins, ticks, and the max\_ and min\_ values for the respective. - isopleth. Other values can be changed through the ``_kwarg`` dictionary, although this should be improved - in the future. + +Isobar control +-------------- + +Isobar lines +^^^^^^^^^^^^ + +The default behaviour of the tephigram *isobar line* is controlled by the :data:`tephi.constants.default["isobar_line"]` +dictionary: + + >>> print(tephi.constants.default["isobar_line"]) + {'color': 'blue', 'linewidth': 0.5, 'clip_on': True} + +This is a dictionary of *key* and *value* pairs that are passed through as keyword arguments to :func:`matplotlib.pyplot.plot`. + +Updating the ``tephi.constants.default["isobar_line"]`` dictionary will subsequently change the default behaviour of +how the tephigram isobar lines are plotted. + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["isobar_line"].update({'color': 'purple', 'linewidth': 3, 'linestyle': '--'}) + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + default["isobar_line"] = {'color': 'blue', 'linewidth': 0.5, 'clip_on': True} + + +Isobar text +^^^^^^^^^^^ + +Similarly, the default behaviour of the tephigram *isobar text* is controlled by the +:data:`tephi.constants.default["isobar_text"]` dictionary: + + >>> pprint(tephi.constants.default["isobar_text"]) + {'clip_on': True, 'color': 'blue', 'ha': 'right', 'size': 8, 'va': 'bottom'} + +This is a dictionary of *key* and *value* pairs that are passed through as keyword arguments to :func:`matplotlib.pyplot.text`. + +Updating the ``tephi.constants.default["isobar_text"]`` dictionary will change the default behaviour of how the +tephigram isobar text is plotted. + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["isobar_text"].update({'color': 'purple', 'size': 12}) + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + default["isobar_text"] = {'color': 'blue', 'va': 'bottom', 'ha': 'right', 'clip_on': True, 'size': 8} + + +Isobar frequency +^^^^^^^^^^^^^^^^ + +The values at which isobars lines can be created is controlled by the +:data:`tephi.constants.default["isobar_ticks"]` value: + + >>> print(tephi.constants.default["isobar_ticks"]) + [1050, 1000, 950, 900, 850, 800, 700, 600, 500, 400, 300, 250, 200, 150, 100, 70, 50, 40, 30, 20, 10] + +The *frequency* at which isobar lines are plotted on the tephigram is controlled by the +:data:`tephi.constants.default["isobar_nbins"]` value: + + >>> print(tephi.constants.default["isobar_nbins"]) + None + +``nbins`` controls the maximum number of lines plotted at one time. It can either be an integer value, or a ``None`` +value, which means that a line will be shown for every tick in :data:`tephi.constants.default["isobar_ticks"]`. + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["isobar_ticks"] = [900, 875, 850] + default["isobar_nbins"] = 2 + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + default["isobar_ticks"] = [1050, 1000, 950, 900, 850, 800, 700, 600, 500, 400, 300, 250, 200, 150, 100, 70, 50, 40, 30, 20, 10] + default["isobar_nbins"] = None + + +Isobar line extent +^^^^^^^^^^^^^^^^^^ + +The extent of each tephigram *isobar line* is controlled by the :data:`tephi.constants.default["isobar_min_theta"]` and +:data:`tephi.constants.default["isobar_max_theta"]` variables: + + >>> print(tephi.constants.default["isobar_min_theta"]) + 0 + >>> print(tephi.constants.default["isobar_max_theta"]) + 250 + +For example, to change the isobar line extent behaviour to be between 15 :sup:`o`\ C and 60 :sup:`o`\ C, + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["isobar_min_theta"] = 15 + default["isobar_max_theta"] = 60 + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + default["isobar_min_theta"] = 0 + default["isobar_max_theta"] = 250 + + +Saturated adiabat control +------------------------- + +Saturated adiabat lines +^^^^^^^^^^^^^^^^^^^^^^^ + +The values at which pseudo saturated adiabat lines can be created is controlled by the +:data:`tephi.constants.default["wet_adiabat_line"]` dictionary: + + >>> print(tephi.constants.default["wet_adiabat_line"]) + {'color': 'orange', 'linewidth': 0.5, 'clip_on': True} + +This is a dictionary of *key* and *value* pairs that are passed through as keyword arguments to :func:`matplotlib.pyplot.plot`. + +Updating the ``default["wet_adiabat_line"]`` dictionary will change the default behaviour of **all** saturated adiabat line plotting. + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["wet_adiabat_line"].update({'color': 'purple', 'linewidth': 3, 'linestyle': '--'}) + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + default["wet_adiabat_line"] = {'color': 'orange', 'linewidth': 0.5, 'clip_on': True} + + +Saturated adiabat text +^^^^^^^^^^^^^^^^^^^^^^ + +The default behaviour of the tephigram *saturated adiabat text* is controlled by the +:data:`tephi.constants.default["wet_adiabat_text"]` dictionary: + + >>> pprint(tephi.constants.default["wet_adiabat_text"]) + {'clip_on': True, 'color': 'orange', 'ha': 'left', 'size': 8, 'va': 'top'} + +This is a dictionary of *key* and *value* pairs that are passed through as keyword arguments to :func:`matplotlib.pyplot.text`. + +Updating the ``default["wet_adiabat_text"]`` dictionary will change the default behaviour of how the text of associated saturated adiabat lines are plotted. + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["wet_adiabat_text"].update({'color': 'purple', 'size': 12}) + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + + default["wet_adiabat_text"] = {'color': 'orange', 'va': 'bottom', 'ha': 'left', 'clip_on': True, 'size': 8} + + +Saturated adiabat line frequency +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The values at which pseudo saturated adiabat lines can be created is controlled by the +:data:`tephi.constants.default["wet_adiabat_ticks"]` value: + + >>> print(tephi.constants.default["wet_adiabat_ticks"]) + range(1, 61) + +The *frequency* at which wet adiabat lines are plotted on the tephigram is controlled by the +:data:`tephi.constants.default["wet_adiabat_nbins"]` value: + + >>> print(tephi.constants.default["wet_adiabat_nbins"]) + 10 + +``nbins`` controls the maximum number of lines plotted at one time. It can either be an integer value, or a ``None`` +value, which means that a line will be shown for every tick in :data:`tephi.constants.default["wet_adiabat_ticks"]`. + +Saturated Adiabat Extents +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The extent of each tephigram *saturated adiabat line* is controlled by the +:data:`tephi.constants.default["wet_adiabat_min_temperature"]` and +:data:`tephi.constants.default["wet_adiabat_max_pressure"]` variables: + + >>> print(tephi.constants.default["wet_adiabat_min_temperature"]) + -50 + >>> print(tephi.constants.default["wet_adiabat_max_pressure"]) + 1000.0 + +For example, to change the wet adiabat line extent behaviour to be between -10 :sup:`o`\ C and 900 mbar, + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["wet_adiabat_min_temperature"] = -10 + default["wet_adiabat_max_pressure"] = 900 + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + default["wet_adiabat_min_temperature"] = -10 + default["wet_adiabat_max_pressure"] = 900 + + +Humidity mixing ratio control +----------------------------- + +Humidity mixing ratio lines +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The default behaviour of the tephigram *humidity mixing ratio line* is controlled by the +:data:`tephi.constants.default["mixing_ratio_line"]` dictionary: + + >>> print(tephi.constants.default["mixing_ratio_line"]) + {'color': 'green', 'linewidth': 0.5, 'clip_on': True} + +This is a dictionary of *key* and *value* pairs that are passed through as keyword arguments to :func:`matplotlib.pyplot.plot`. + +Updating the ``default["mixing_ratio_line"]`` dictionary will change the default behaviour of **all** humidity mixing ratio line plotting. + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["mixing_ratio_line"].update({'color': 'purple', 'linewidth': 3, 'linestyle': '--'}) + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + default["mixing_ratio_line"] = {'color': 'green', 'linewidth': 0.5, 'clip_on': True} + + +Humidity mixing ratio text +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The default behaviour of the tephigram *humidity mixing ratio text* is controlled by the +:data:`tephi.constants.default["mixing_ratio_text"]` dictionary: + + >>> pprint(tephi.constants.default["mixing_ratio_text"]) + {'clip_on': True, 'color': 'green', 'ha': 'right', 'size': 8, 'va': 'bottom'} + +This is a dictionary of *key* and *value* pairs that are passed through as keyword arguments to :func:`matplotlib.pyplot.text`. + +Updating the ``default["mixing_ratio_text"]`` dictionary will change the default behaviour of how the text of associated +humidity mixing ratio lines are plotted. + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["mixing_ratio_text"].update({'color': 'purple', 'size': 12}) + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + default["mixing_ratio_text"] = {'color': 'green', 'va': 'bottom', 'ha': 'right', 'clip_on': True, 'size': 8} + + +Mixing Ratio line frequency +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The values at which mixing ratio lines can be created is controlled by the +:data:`tephi.constants.default["mixing_ratio_ticks"]` value: + + >>> print(tephi.constants.default["mixing_ratio_ticks"]) + [0.001, 0.002, 0.005, 0.01, 0.02, 0.03, 0.05, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0, 24.0, 28.0, 32.0, 36.0, 40.0, 44.0, 48.0, 52.0, 56.0, 60.0, 68.0, 80.0] + +The *frequency* at which mixing ratio lines are plotted on the tephigram is controlled by the +:data:`tephi.constants.default["mixing_ratio_nbins"]` value: + + >>> print(tephi.constants.default["mixing_ratio_nbins"]) + 10 + +``nbins`` controls the maximum number of lines plotted at one time. It can either be an integer value, or a ``None`` +value, which means that a line will be shown for every tick in :data:`tephi.constants.default["mixing_ratio_ticks"]`. + +Mixing Ratio Extents +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The extent of each tephigram *mixing ratio line* is controlled by the +:data:`tephi.constants.default["mixing_ratio_min_pressure"]` and +:data:`tephi.constants.default["mixing_ratio_max_pressure"]` variables: + + >>> print(tephi.constants.default["mixing_ratio_min_pressure"]) + 10 + >>> print(tephi.constants.default["mixing_ratio_max_pressure"]) + 1000.0 + +For example, to change the wet adiabat line extent behaviour to be between 100 mbar and 500 mbar, + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import os.path + + import tephi + from tephi.constants import default + + dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt') + dew_data = tephi.loadtxt(dew_point, column_titles=('pressure', 'dewpoint')) + dews = zip(dew_data.pressure, dew_data.dewpoint) + default["mixing_ratio_min_pressure"] = 100 + default["mixing_ratio_max_pressure"] = 500 + tpg = tephi.TephiAxes() + tpg.plot(dews) + plt.show() + +.. plot:: + + import tephi + from tephi.constants import default + default["mixing_ratio_min_temperature"] = -10 + default["mixing_ratio_max_pressure"] = 900 diff --git a/tephi/__init__.py b/tephi/__init__.py index 076dbcf..c6f602f 100644 --- a/tephi/__init__.py +++ b/tephi/__init__.py @@ -169,7 +169,7 @@ class _FormatterTheta(object): """ def __call__(self, direction, factor, values): - return [r"$\theta={}$".format(value) for value in values] + return [r"$\theta={:.1f}$".format(value) for value in values] class _FormatterIsotherm(object): @@ -179,7 +179,7 @@ class _FormatterIsotherm(object): """ def __call__(self, direction, factor, values): - return [r"$T={}$".format(value) for value in values] + return [r"$T={:.1f}$".format(value) for value in values] class Locator(object): diff --git a/tephi/artists.py b/tephi/artists.py index 2759cf2..20d9e1f 100644 --- a/tephi/artists.py +++ b/tephi/artists.py @@ -146,7 +146,7 @@ def __init__( self.max_pressure = max_pressure if nbins is None: nbins = default.get("wet_adiabat_nbins") - if nbins < 2 or isinstance(nbins, str): + if nbins is None or (nbins < 2 or isinstance(nbins, str)): nbins = None self.nbins = nbins @@ -241,7 +241,7 @@ def __init__( self.max_pressure = max_pressure if nbins is None: nbins = default.get("mixing_ratio_nbins") - if nbins < 2 or isinstance(nbins, str): + if nbins is None or (nbins < 2 or isinstance(nbins, str)): nbins = None self.nbins = nbins diff --git a/tephi/isopleths.py b/tephi/isopleths.py index b5807b0..5543f50 100644 --- a/tephi/isopleths.py +++ b/tephi/isopleths.py @@ -14,6 +14,7 @@ from collections import namedtuple import math import matplotlib.artist +from matplotlib.text import Text from matplotlib.collections import PathCollection from matplotlib.path import Path import matplotlib.pyplot as plt @@ -275,13 +276,12 @@ def text(self, temperature, theta, text, **kwargs): kwargs["zorder"] = default.get("isopleth_zorder", 10) + 1 text_kwargs = dict(self._kwargs["text"]) text_kwargs.update(kwargs) - if self.label is not None and self.label in self.axes.texts: - self.axes.lines.remove(self.label) - self.label = self.axes.text( + self.label = Text( temperature, theta, str(text), transform=self._transform, + figure=self.axes.figure, **text_kwargs, ) self.label.set_bbox( @@ -297,17 +297,7 @@ def text(self, temperature, theta, text, **kwargs): return self.label def refresh(self, temperature, theta, renderer=None, **kwargs): - if self.label is None: - self.text(temperature, theta, self.data, **kwargs) - if renderer is not None: - try: - self.axes.tests = tuple( - list(self.axes.texts).remove(self.label) - ) - except TypeError: - self.axes.tests = None - else: - self.label.set_position((temperature, theta)) + self.text(temperature, theta, self.data, **kwargs) if renderer is not None: self.label.draw(renderer) diff --git a/tephi/tests/results/imagerepo.json b/tephi/tests/results/imagerepo.json index f42efa6..54fcfc3 100644 --- a/tephi/tests/results/imagerepo.json +++ b/tephi/tests/results/imagerepo.json @@ -16,7 +16,8 @@ ], "test_tephigram.TestTephigramAxes.test_plot_dews_locator_adiabat_object.0": [ "https://scitools.github.io/test-tephi-imagehash/images/ea5a9f0d91e32639c5a5198d96729cc6cbb462619f9e3f1398646d093c736326.png", - "https://scitools.github.io/test-tephi-imagehash/images/ea5a9f0d91e46639c5a5398996759cc6cbb462619f8b3f1298646bcc3c736216.png" + "https://scitools.github.io/test-tephi-imagehash/images/ea5a9f0d91e46639c5a5398996759cc6cbb462619f8b3f1298646bcc3c736216.png", + "https://scitools.github.io/test-tephi-imagehash/images/ea5e9f0991e42639c5a51989967d98d6cbb462619f8b3f1298666bcc3c736216.png" ], "test_tephigram.TestTephigramAxes.test_plot_dews_locator_isotherm_numeric.0": [ "https://scitools.github.io/test-tephi-imagehash/images/ea5a8f6d91e16630c5ed392c86599cc6cbb46a6196986a929d66ed893e23343e.png" @@ -30,7 +31,8 @@ ], "test_tephigram.TestTephigramAxes.test_plot_dews_locator_object.0": [ "https://scitools.github.io/test-tephi-imagehash/images/ea5a8f2d91e36639c5e5198d86521cc7cb946e639adc273398646d09347961f6.png", - "https://scitools.github.io/test-tephi-imagehash/images/ea5a8f4d91e46639c5a5398996751cd6cbbc6a61929863b29c664bc93e137616.png" + "https://scitools.github.io/test-tephi-imagehash/images/ea5a8f4d91e46639c5a5398996751cd6cbbc6a61929863b29c664bc93e137616.png", + "https://scitools.github.io/test-tephi-imagehash/images/ea5e8f4991e42639c5a51989866d9cd6cbbc6a61929863b29c666bc93e1b721e.png" ], "test_tephigram.TestTephigramAxes.test_plot_xylim.0": [ "https://scitools.github.io/test-tephi-imagehash/images/bfe8e15ee0451c03911a63e0063a6c6e79c09b9be335f073944f2ecc55f87ca3.png"