def curvelinear_test1(fig):
    """
    grid for custom transform.
    """

    def tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y - x

    def inv_tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y + x

    grid_helper = GridHelperCurveLinear((tr, inv_tr))

    ax1 = Subplot(fig, 1, 2, 1, grid_helper=grid_helper)
    # ax1 will have a ticks and gridlines defined by the given
    # transform (+ transData of the Axes). Note that the transform of
    # the Axes itself (i.e., transData) is not affected by the given
    # transform.

    fig.add_subplot(ax1)

    xx, yy = tr([3, 6], [5.0, 10.])
    ax1.plot(xx, yy, linewidth=2.0)

    ax1.set_aspect(1.)
    ax1.set_xlim(0, 10.)
    ax1.set_ylim(0, 10.)

    ax1.axis["t"] = ax1.new_floating_axis(0, 3.)
    ax1.axis["t2"] = ax1.new_floating_axis(1, 7.)
    ax1.grid(True, zorder=0)
Exemplo n.º 2
0
    def __spacetime_diagram_o_frame(self):
        # from (x',t') to (x,t)
        def tr(x_prime, t_prime):
            x_prime, t_prime = np.asarray(x_prime), np.asarray(t_prime)
            return self.lorentz_transformations.transform(
                x_prime, t_prime, -self.velocity)

        # form (x,t) to (x',t')
        def inv_tr(x, t):
            x, t = np.asarray(x), np.asarray(t)
            return self.lorentz_transformations.transform(x, t, self.velocity)

        grid_helper = GridHelperCurveLinear((tr, inv_tr))
        ax = Subplot(self.fig, 1, 2, 1, grid_helper=grid_helper) if self.showOPrime \
            else Subplot(self.fig, 1, 1, 1, grid_helper=grid_helper)
        self.fig.add_subplot(ax)

        ax.set_xlabel("x", loc="center")
        ax.set_ylabel("t", loc="center")

        # O' x axis
        ax.axis["x1"] = x1 = ax.new_floating_axis(1, 0)
        x1.label.set_text("x'")

        # O' t axis
        ax.axis["t1"] = t1 = ax.new_floating_axis(0, 0)
        t1.label.set_text("t'")

        self.__add_x_and_y_axis(ax)
        ax.format_coord = self.__format_coord_o_frame

        self.__remove_ticks(ax, x1, t1)

        self.world_lines_plotter.plot(plt, ax, self.velocity)
Exemplo n.º 3
0
def curvelinear_test1(fig):
    """
    grid for custom transform.
    """
    def tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y - x

    def inv_tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y + x

    grid_helper = GridHelperCurveLinear((tr, inv_tr))

    ax1 = Subplot(fig, 1, 2, 1, grid_helper=grid_helper)
    # ax1 will have a ticks and gridlines defined by the given
    # transform (+ transData of the Axes). Note that the transform of
    # the Axes itself (i.e., transData) is not affected by the given
    # transform.

    fig.add_subplot(ax1)

    xx, yy = tr([3, 6], [5.0, 10.])
    ax1.plot(xx, yy, linewidth=2.0)

    ax1.set_aspect(1.)
    ax1.set_xlim(0, 10.)
    ax1.set_ylim(0, 10.)

    ax1.axis["t"] = ax1.new_floating_axis(0, 3.)
    ax1.axis["t2"] = ax1.new_floating_axis(1, 7.)
    ax1.grid(True, zorder=0)
Exemplo n.º 4
0
def plotCorrelation(tauArray,kappaMatrix,kappaLower=None,kappaUpper=None,CI=None,amplify=1):
    
    """Plots Pearson Correlation Coefficient K(t,tau) with rotated
    axis to indicate absolute t, and relative time shift tau, between
    two signals x(t),y(t).
    
    Specified matrix has to be square with values -1 < p < +1
    with corresponding time array giving the absolute time, t
    of the centers of each correlated window."""

    # defining tranformation for relative time shifts
    def R(x, y):
        x, y = asarray(x), asarray(y)
        #return x,y
        return (2*x - y)/2, (y + 2*x)/2

    def Rt(x, y):
        x, y = asarray(x), asarray(y)
        #return x,y
        return x + y, x - y

    # create figure with rotated axes
    fig = figure(figsize=(10, 10),frameon=False)
    grid_locator = angle_helper.LocatorDMS(20)
    grid_helper = GridHelperCurveLinear((R, Rt),
                  grid_locator1=grid_locator,
                  grid_locator2=grid_locator)
    
    ax = Subplot(fig, 1, 1, 1, grid_helper=grid_helper)
    fig.add_subplot(ax);ax.axis('off');
    
    # copying over matrix
    K = array(kappaMatrix)
    
    # zero out correlations if confidence intervals overlap zero
    if all(kappaLower != None) and all(kappaUpper != None) :
        K[ (kappaLower<0) * (0<kappaUpper) ] = 0
        
    # zero out statistically insignificant correlations
    if all(CI != None) :
        K[ abs(kappaMatrix) < CI ] = 0
    
    # display pearson correlation matrix with +ive in red and -ive in blue
    ax.imshow(K,cmap="RdBu_r",interpolation="none",origin="bottom",
              extent = (tauArray[0],tauArray[-1],tauArray[0],tauArray[-1]),vmin=-1.0/amplify,vmax=1.0/amplify)

    # display rotated axes time,t and time delay,tau
    ax.axis["tau"] = tau = ax.new_floating_axis(0,0)
    ax.axis["t"] = t = ax.new_floating_axis(1,0)
    
    # setting axes options
    ax.set_xlim(tauArray[0],tauArray[-1])
    ax.set_ylim(tauArray[0],tauArray[-1])
    ax.grid(which="both")
    ax.set_aspect(1)
    
    return fig
Exemplo n.º 5
0
def curvelinear_test1(fig):
    """
    grid for custom transform.
    """
    def tr(x, y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y-x
    def inv_tr(x,y):
        x, y = np.asarray(x), np.asarray(y)
        return x, y+x
    grid_helper = GridHelperCurveLinear((tr, inv_tr))
    ax1 = Subplot(fig, 1, 2, 1, grid_helper=grid_helper)
    fig.add_subplot(ax1)
    xx, yy = tr([3, 6], [5.0, 10.])
    ax1.plot(xx, yy)
    ax1.set_aspect(1.)
    ax1.set_xlim(0, 10.)
    ax1.set_ylim(0, 10.)
    ax1.axis["t"]=ax1.new_floating_axis(0, 3.)
    ax1.axis["t2"]=ax1.new_floating_axis(1, 7.)
    ax1.grid(True)
Exemplo n.º 6
0
def curvelinear_test1(fig):
    """
    Grid for custom transform.
    """
    def tr(x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        return x, y - (2 * x)  # return x + (5 * y), (7 * y) + (3 * x)

    def inv_tr(x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        return x, y + (2 * x)

    grid_helper = GridHelperCurveLinear((tr, inv_tr))

    ax1 = Subplot(fig, 1, 1, 1, grid_helper=grid_helper)
    # ax1 will have a ticks and gridlines defined by the given
    # transform (+ transData of the Axes). Note that the transform of
    # the Axes itself (i.e., transData) is not affected by the given
    # transform.

    fig.add_subplot(ax1)

    xx, yy = tr([0, 1], [0, 2])
    ax1.plot(xx, yy, linewidth=2.0)

    ax1.set_aspect(1)
    ax1.set_xlim(-3, 3)
    ax1.set_ylim(-3, 3)

    ax1.axis["t"] = ax1.new_floating_axis(
        0, 0
    )  # first argument appears to be slope, second argument appears to be starting point on vertical
    ax1.axis["t2"] = ax1.new_floating_axis(1, 0)
    ax1.axhline(y=0, color='r')
    ax1.axvline(x=0, color='r')
    ax1.grid(True, zorder=0)
Exemplo n.º 7
0
    from mpl_toolkits.axisartist import Subplot
    from mpl_toolkits.axisartist.grid_helper_curvelinear import \
        GridHelperCurveLinear

    def tr(x, y):  # source (data) to target (rectilinear plot) coordinates
        x, y = numpy.asarray(x), numpy.asarray(y)
        return x + 0.2 * y, y - x

    def inv_tr(x, y):
        x, y = numpy.asarray(x), numpy.asarray(y)
        return x - 0.2 * y, y + x

    grid_helper = GridHelperCurveLinear((tr, inv_tr))

    ax6 = Subplot(fig, nrow, ncol, 6, grid_helper=grid_helper)
    fig.add_subplot(ax6)
    ax6.set_title('non-ortho axes')

    xx, yy = tr([3, 6], [5.0, 10.])
    ax6.plot(xx, yy)

    ax6.set_aspect(1.)
    ax6.set_xlim(0, 10.)
    ax6.set_ylim(0, 10.)

    ax6.axis["t"] = ax6.new_floating_axis(0, 3.)
    ax6.axis["t2"] = ax6.new_floating_axis(1, 7.)
    ax6.grid(True)

    plt.show()
Exemplo n.º 8
0
class Tephigram:
    """
    Generate a tephigram of one or more pressure and temperature data sets.

    """
    def __init__(
        self,
        figure=None,
        isotherm_locator=None,
        dry_adiabat_locator=None,
        anchor=None,
    ):
        """
        Initialise the tephigram transformation and plot axes.

        Kwargs:

        * figure:
            An existing :class:`matplotlib.figure.Figure` instance for the
            tephigram plot. If a figure is not provided, a new figure will
            be created by default.
        * isotherm_locator:
            A :class:`tephi.Locator` instance or a numeric step size
            for the isotherm lines.
        * dry_adiabat_locator:
            A :class:`tephi.Locator` instance or a numeric step size
            for the dry adiabat lines.
        * anchor:
            A sequence of two pressure, temperature pairs specifying the extent
            of the tephigram plot in terms of the bottom left hand corner and
            the top right hand corner. Pressure data points must be in units of
            mb or hPa, and temperature data points must be in units of degC.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            from numpy import column_stack
            import os.path
            import tephi
            from tephi import Tephigram

            dew_point = os.path.join(tephi.DATA_DIR, 'dews.txt')
            dry_bulb = os.path.join(tephi.DATA_DIR, 'temps.txt')
            dew_data, temp_data = tephi.loadtxt(dew_point, dry_bulb)
            dews = column_stack((dew_data.pressure, dew_data.temperature))
            temps = column_stack((temp_data.pressure, temp_data.temperature))
            tpg = Tephigram()
            tpg.plot(dews, label='Dew-point', color='blue', linewidth=2)
            tpg.plot(temps, label='Dry-bulb', color='red', linewidth=2)
            plt.show()

        """
        if not figure:
            # Create a default figure.
            self.figure = plt.figure(0, figsize=(9, 9))
        else:
            self.figure = figure

        # Configure the locators.
        if isotherm_locator and not isinstance(isotherm_locator, Locator):
            if not isinstance(isotherm_locator, numbers.Number):
                raise ValueError("Invalid isotherm locator")
            locator_isotherm = Locator(isotherm_locator)
        else:
            locator_isotherm = isotherm_locator

        if dry_adiabat_locator and not isinstance(dry_adiabat_locator,
                                                  Locator):
            if not isinstance(dry_adiabat_locator, numbers.Number):
                raise ValueError("Invalid dry adiabat locator")
            locator_theta = Locator(dry_adiabat_locator)
        else:
            locator_theta = dry_adiabat_locator

        # Define the tephigram coordinate-system transformation.
        self.tephi_transform = transforms.TephiTransform()
        ghelper = GridHelperCurveLinear(
            self.tephi_transform,
            tick_formatter1=_FormatterIsotherm(),
            grid_locator1=locator_isotherm,
            tick_formatter2=_FormatterTheta(),
            grid_locator2=locator_theta,
        )
        self.axes = Subplot(self.figure, 1, 1, 1, grid_helper=ghelper)
        self.transform = self.tephi_transform + self.axes.transData
        self.axes.axis["isotherm"] = self.axes.new_floating_axis(1, 0)
        self.axes.axis["theta"] = self.axes.new_floating_axis(0, 0)
        self.axes.axis["left"].get_helper().nth_coord_ticks = 0
        self.axes.axis["left"].toggle(all=True)
        self.axes.axis["bottom"].get_helper().nth_coord_ticks = 1
        self.axes.axis["bottom"].toggle(all=True)
        self.axes.axis["top"].get_helper().nth_coord_ticks = 0
        self.axes.axis["top"].toggle(all=False)
        self.axes.axis["right"].get_helper().nth_coord_ticks = 1
        self.axes.axis["right"].toggle(all=True)
        self.axes.gridlines.set_linestyle("solid")

        self.figure.add_subplot(self.axes)

        # Configure default axes.
        axis = self.axes.axis["left"]
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("baseline")
        axis.major_ticklabels.set_rotation(135)
        axis = self.axes.axis["right"]
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("baseline")
        axis.major_ticklabels.set_rotation(-135)
        self.axes.axis["top"].major_ticklabels.set_fontsize(10)
        axis = self.axes.axis["bottom"]
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_ha("left")
        axis.major_ticklabels.set_va("top")
        axis.major_ticklabels.set_rotation(-45)

        # Isotherms: lines of constant temperature (degC).
        axis = self.axes.axis["isotherm"]
        axis.set_axis_direction("right")
        axis.set_axislabel_direction("-")
        axis.major_ticklabels.set_rotation(90)
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("bottom")
        axis.major_ticklabels.set_color("grey")
        axis.major_ticklabels.set_visible(False)  # turned-off

        # Dry adiabats: lines of constant potential temperature (degC).
        axis = self.axes.axis["theta"]
        axis.set_axis_direction("right")
        axis.set_axislabel_direction("+")
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va("bottom")
        axis.major_ticklabels.set_color("grey")
        axis.major_ticklabels.set_visible(False)  # turned-off
        axis.line.set_linewidth(3)
        axis.line.set_linestyle("--")

        # Lock down the aspect ratio.
        self.axes.set_aspect(1.0)
        self.axes.grid(True)

        # Initialise the text formatter for the navigation status bar.
        self.axes.format_coord = self._status_bar

        # Factor in the tephigram transform.
        ISOBAR_TEXT["transform"] = self.transform
        WET_ADIABAT_TEXT["transform"] = self.transform
        MIXING_RATIO_TEXT["transform"] = self.transform

        # Create plot collections for the tephigram isopleths.
        func = partial(
            isopleths.isobar,
            MIN_THETA,
            MAX_THETA,
            self.axes,
            self.transform,
            ISOBAR_LINE,
        )
        self._isobars = _PlotCollection(
            self.axes,
            ISOBAR_SPEC,
            MAX_PRESSURE,
            func,
            ISOBAR_TEXT,
            fixed=ISOBAR_FIXED,
            minimum=MIN_PRESSURE,
        )

        func = partial(
            isopleths.wet_adiabat,
            MAX_PRESSURE,
            MIN_TEMPERATURE,
            self.axes,
            self.transform,
            WET_ADIABAT_LINE,
        )
        self._wet_adiabats = _PlotCollection(
            self.axes,
            WET_ADIABAT_SPEC,
            MAX_WET_ADIABAT,
            func,
            WET_ADIABAT_TEXT,
            fixed=WET_ADIABAT_FIXED,
            minimum=MIN_WET_ADIABAT,
            xfocus=True,
        )

        func = partial(
            isopleths.mixing_ratio,
            MIN_PRESSURE,
            MAX_PRESSURE,
            self.axes,
            self.transform,
            MIXING_RATIO_LINE,
        )
        self._mixing_ratios = _PlotCollection(
            self.axes,
            MIXING_RATIO_SPEC,
            MIXING_RATIOS,
            func,
            MIXING_RATIO_TEXT,
            fixed=MIXING_RATIO_FIXED,
        )

        # Initialise for the tephigram plot event handler.
        plt.connect("motion_notify_event", _handler)
        self.axes.tephigram = True
        self.axes.tephigram_original_delta_xlim = DEFAULT_WIDTH
        self.original_delta_xlim = DEFAULT_WIDTH
        self.axes.tephigram_transform = self.tephi_transform
        self.axes.tephigram_inverse = self.tephi_transform.inverted()
        self.axes.tephigram_isopleths = [
            self._isobars,
            self._wet_adiabats,
            self._mixing_ratios,
        ]

        # The tephigram profiles.
        self._profiles = []
        self.axes.tephigram_profiles = self._profiles

        # Center the plot around the anchor extent.
        self._anchor = anchor
        if self._anchor is not None:
            self._anchor = np.asarray(anchor)
            if (self._anchor.ndim != 2 or self._anchor.shape[-1] != 2
                    or len(self._anchor) != 2):
                msg = ("Invalid anchor, expecting [(bottom-left-pressure, "
                       "bottom-left-temperature), (top-right-pressure, "
                       "top-right-temperature)]")
                raise ValueError(msg)
            (
                (bottom_pressure, bottom_temp),
                (top_pressure, top_temp),
            ) = self._anchor

            if (bottom_pressure - top_pressure) < 0:
                raise ValueError("Invalid anchor pressure range")
            if (bottom_temp - top_temp) < 0:
                raise ValueError("Invalid anchor temperature range")

            self._anchor = isopleths.Profile(anchor, self.axes)
            self._anchor.plot(visible=False)
            xlim, ylim = self._calculate_extents()
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)

    def plot(self, data, **kwargs):
        """
        Plot the environmental lapse rate profile of the pressure and
        temperature data points.

        The pressure and temperature data points are transformed into
        potential temperature and temperature data points before plotting.

        By default, the tephigram will automatically center the plot around
        all profiles.

        .. warning::
            Pressure data points must be in units of mb or hPa, and temperature
            data points must be in units of degC.

        Args:

        * data: pressure and temperature pair data points.

        .. note::
            All keyword arguments are passed through to
            :func:`matplotlib.pyplot.plot`.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            from tephi import Tephigram

            tpg = Tephigram()
            data = [[1006, 26.4], [924, 20.3], [900, 19.8],
                    [850, 14.5], [800, 12.9], [755, 8.3]]
            profile = tpg.plot(data, color='red', linestyle='--',
                               linewidth=2, marker='o')
            barbs = [(10, 45, 900), (20, 60, 850), (25, 90, 800)]
            profile.barbs(barbs)
            plt.show()

        For associating wind barbs with an environmental lapse rate profile,
        see :meth:`~tephi.isopleths.Profile.barbs`.

        """
        profile = isopleths.Profile(data, self.axes)
        profile.plot(**kwargs)
        self._profiles.append(profile)

        # Center the tephigram plot around all the profiles.
        if self._anchor is None:
            xlim, ylim = self._calculate_extents(xfactor=0.25, yfactor=0.05)
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)

        # Refresh the tephigram plot isopleths.
        _refresh_isopleths(self.axes)

        # Show the plot legend.
        if "label" in kwargs:
            font_properties = FontProperties(size="x-small")
            plt.legend(
                loc="upper left",
                fancybox=True,
                shadow=True,
                prop=font_properties,
            )

        return profile

    def _status_bar(self, x_point, y_point):
        """Generate text for the interactive backend navigation status bar."""

        temperature, theta = transforms.convert_xy2Tt(x_point, y_point)
        pressure, _ = transforms.convert_Tt2pT(temperature, theta)
        xlim = self.axes.get_xlim()
        zoom = (xlim[1] - xlim[0]) / self.original_delta_xlim
        msg = "T:{:.2f}, theta:{:.2f}, phi:{:.2f} (zoom:{:.3f})"
        text = msg.format(float(temperature), float(theta), float(pressure),
                          zoom)

        return text

    def _calculate_extents(self, xfactor=None, yfactor=None):
        min_x = min_y = 1e10
        max_x = max_y = -1e-10
        profiles = self._profiles
        transform = self.tephi_transform.transform

        if self._anchor is not None:
            profiles = [self._anchor]

        for profile in profiles:
            temperature = profile.temperature.reshape(-1, 1)
            theta = profile.theta.reshape(-1, 1)
            xy_points = transform(np.concatenate((temperature, theta), axis=1))
            x_points = xy_points[:, 0]
            y_points = xy_points[:, 1]
            min_x = np.min([min_x, np.min(x_points)])
            min_y = np.min([min_y, np.min(y_points)])
            max_x = np.max([max_x, np.max(x_points)])
            max_y = np.max([max_y, np.max(y_points)])

        if xfactor is not None:
            delta_x = max_x - min_x
            min_x, max_x = min_x - xfactor * delta_x, max_x + xfactor * delta_x

        if yfactor is not None:
            delta_y = max_y - min_y
            min_y, max_y = min_y - yfactor * delta_y, max_y + yfactor * delta_y

        return ([min_x, max_x], [min_y, max_y])
Exemplo n.º 9
0
class Tephigram(object):
    """
    Generate a tephigram of one or more pressure and temperature data sets.

    """

    def __init__(self, figure=None, isotherm_locator=None,
                 dry_adiabat_locator=None, anchor=None):
        """
        Initialise the tephigram transformation and plot axes.

        Kwargs:

        * figure:
            An existing :class:`matplotlib.figure.Figure` instance for the
            tephigram plot. If a figure is not provided, a new figure will
            be created by default.
        * isotherm_locator:
            A :class:`edson.Locator` instance or a numeric step size
            for the isotherm lines.
        * dry_adiabat_locator:
            A :class:`edson.Locator` instance or a numeric step size
            for the dry adiabat lines.
        * anchor:
            A sequence of two pressure, temperature pairs specifying the extent
            of the tephigram plot in terms of the bottom left hand corner and
            the top right hand corner. Pressure data points must be in units of
            mb or hPa, and temperature data points must be in units of degC.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            import os.path
            import edson
            from edson import Tephigram

            dew_point = os.path.join(edson.RESOURCES_DIR, 'tephigram', 'dews.txt')
            dry_bulb = os.path.join(edson.RESOURCES_DIR, 'tephigram', 'temps.txt')
            dew_data, temp_data = edson.loadtxt(dew_point, dry_bulb)
            dews = zip(dew_data.pressure, dew_data.temperature)
            temps = zip(temp_data.pressure, temp_data.temperature)
            tephi = Tephigram()
            tephi.plot(dews, label='Dew-point', color='blue', linewidth=2, marker='s')
            tephi.plot(temps, label='Dry-bulb', color='red', linewidth=2, marker='o')
            plt.show()

        """
        if not figure:
            # Create a default figure.
            self.figure = plt.figure(0, figsize=(9, 9))
        else:
            self.figure = figure

        # Configure the locators.
        if isotherm_locator and not isinstance(isotherm_locator, Locator):
            if not isinstance(isotherm_locator, numbers.Number):
                raise ValueError('Invalid isotherm locator')
            locator_isotherm = Locator(isotherm_locator)
        else:
            locator_isotherm = isotherm_locator

        if dry_adiabat_locator and not isinstance(dry_adiabat_locator, Locator):
            if not isinstance(dry_adiabat_locator, numbers.Number):
                raise ValueError('Invalid dry adiabat locator')
            locator_theta = Locator(dry_adiabat_locator)
        else:
            locator_theta = dry_adiabat_locator

        # Define the tephigram coordinate-system transformation.
        self.tephi_transform = transforms.TephiTransform()
        grid_helper1 = GridHelperCurveLinear(self.tephi_transform,
                                             tick_formatter1=_FormatterIsotherm(),
                                             grid_locator1=locator_isotherm,
                                             tick_formatter2=_FormatterTheta(),
                                             grid_locator2=locator_theta)
        self.axes = Subplot(self.figure, 1, 1, 1, grid_helper=grid_helper1)
        self.transform = self.tephi_transform + self.axes.transData
        self.axes.axis['isotherm'] = self.axes.new_floating_axis(1, 0)
        self.axes.axis['theta'] = self.axes.new_floating_axis(0, 0)
        self.axes.axis['left'].get_helper().nth_coord_ticks = 0
        self.axes.axis['left'].toggle(all=True)
        self.axes.axis['bottom'].get_helper().nth_coord_ticks = 1
        self.axes.axis['bottom'].toggle(all=True)
        self.axes.axis['top'].get_helper().nth_coord_ticks = 0
        self.axes.axis['top'].toggle(all=False)
        self.axes.axis['right'].get_helper().nth_coord_ticks = 1
        self.axes.axis['right'].toggle(all=True)
        self.axes.gridlines.set_linestyle('solid')

        self.figure.add_subplot(self.axes)

        # Configure default axes.
        axis = self.axes.axis['left']
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('baseline')
        axis.major_ticklabels.set_rotation(135)
        axis = self.axes.axis['right']
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('baseline')
        axis.major_ticklabels.set_rotation(-135)
        self.axes.axis['top'].major_ticklabels.set_fontsize(10)
        axis = self.axes.axis['bottom']
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_ha('left')
        axis.major_ticklabels.set_va('top')
        axis.major_ticklabels.set_rotation(-45)

        # Isotherms: lines of constant temperature (degC).
        axis = self.axes.axis['isotherm']
        axis.set_axis_direction('right')
        axis.set_axislabel_direction('-')
        axis.major_ticklabels.set_rotation(90)
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('bottom')
        axis.major_ticklabels.set_color('grey')
        axis.major_ticklabels.set_visible(False)  # turned-off

        # Dry adiabats: lines of constant potential temperature (degC).
        axis = self.axes.axis['theta']
        axis.set_axis_direction('right')
        axis.set_axislabel_direction('+')
        axis.major_ticklabels.set_fontsize(10)
        axis.major_ticklabels.set_va('bottom')
        axis.major_ticklabels.set_color('grey')
        axis.major_ticklabels.set_visible(False)  # turned-off
        axis.line.set_linewidth(3)
        axis.line.set_linestyle('--')

        # Lock down the aspect ratio.
        self.axes.set_aspect(1.)
        self.axes.grid(True)

        # Initialise the text formatter for the navigation status bar.
        self.axes.format_coord = self._status_bar

        # Factor in the tephigram transform.
        ISOBAR_TEXT['transform'] = self.transform
        WET_ADIABAT_TEXT['transform'] = self.transform
        MIXING_RATIO_TEXT['transform'] = self.transform

        # Create plot collections for the tephigram isopleths.
        func = partial(isopleths.isobar, MIN_THETA, MAX_THETA, self.axes, self.transform, ISOBAR_LINE)
        self._isobars = _PlotCollection(self.axes, ISOBAR_SPEC, MAX_PRESSURE, func, ISOBAR_TEXT,
                                        fixed=ISOBAR_FIXED, minimum=MIN_PRESSURE)

        func = partial(isopleths.wet_adiabat, MAX_PRESSURE, MIN_TEMPERATURE, self.axes, self.transform, WET_ADIABAT_LINE)
        self._wet_adiabats = _PlotCollection(self.axes, WET_ADIABAT_SPEC, MAX_WET_ADIABAT, func, WET_ADIABAT_TEXT,
                                             fixed=WET_ADIABAT_FIXED, minimum=MIN_WET_ADIABAT, xfocus=True)

        func = partial(isopleths.mixing_ratio, MIN_PRESSURE, MAX_PRESSURE, self.axes, self.transform, MIXING_RATIO_LINE)
        self._mixing_ratios = _PlotCollection(self.axes, MIXING_RATIO_SPEC, MIXING_RATIOS, func, MIXING_RATIO_TEXT,
                                              fixed=MIXING_RATIO_FIXED)

        # Initialise for the tephigram plot event handler.
        plt.connect('motion_notify_event', _handler)
        self.axes.tephigram = True
        self.axes.tephigram_original_delta_xlim = self.original_delta_xlim = DEFAULT_WIDTH
        self.axes.tephigram_transform = self.tephi_transform
        self.axes.tephigram_inverse = self.tephi_transform.inverted()
        self.axes.tephigram_isopleths = [self._isobars, self._wet_adiabats, self._mixing_ratios]

       # The tephigram profiles.
        self._profiles = []
        self.axes.tephigram_profiles = self._profiles

        # Center the plot around the anchor extent.
        self._anchor = anchor
        if self._anchor is not None:
            self._anchor = np.asarray(anchor)
            if self._anchor.ndim != 2 or self._anchor.shape[-1] != 2 or \
              len(self._anchor) != 2:
                msg = 'Invalid anchor, expecting [(bottom-left-pressure, ' \
                'bottom-left-temperature), (top-right-pressure, ' \
                'top-right-temperature)]'
                raise ValueError(msg)
            (bottom_pressure, bottom_temp), \
              (top_pressure, top_temp) = self._anchor

            if (bottom_pressure - top_pressure) < 0:
                raise ValueError('Invalid anchor pressure range')
            if (bottom_temp - top_temp) < 0:
                raise ValueError('Invalid anchor temperature range')

            self._anchor = isopleths.Profile(anchor, self.axes)
            self._anchor.plot(visible=False)
            xlim, ylim = self._calculate_extents()
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)

    def plot(self, data, **kwargs):
        """
        Plot the environmental lapse rate profile of the pressure and
        temperature data points.

        The pressure and temperature data points are transformed into
        potential temperature and temperature data points before plotting.

        By default, the tephigram will automatically center the plot around
        all profiles.

        .. warning::
            Pressure data points must be in units of mb or hPa, and temperature
            data points must be in units of degC.

        Args:

        * data: pressure and temperature pair data points.

        .. note::
            All keyword arguments are passed through to
            :func:`matplotlib.pyplot.plot`.

        For example:

        .. plot::
            :include-source:

            import matplotlib.pyplot as plt
            from edson import Tephigram

            tephi = Tephigram()
            data = [[1006, 26.4], [924, 20.3], [900, 19.8],
                    [850, 14.5], [800, 12.9], [755, 8.3]]
            profile = tephi.plot(data, color='red', linestyle='--',
                                 linewidth=2, marker='o')
            barbs = [(10, 45, 900), (20, 60, 850), (25, 90, 800)]
            profile.barbs(barbs)
            plt.show()

        For associating wind barbs with an environmental lapse rate profile,
        see :meth:`~edson.isopleths.Profile.barbs`.

        """
        profile = isopleths.Profile(data, self.axes)
        profile.plot(**kwargs)
        self._profiles.append(profile)

        # Center the tephigram plot around all the profiles.
        if self._anchor is None:
            xlim, ylim = self._calculate_extents(xfactor=.25, yfactor=.05)
            self.axes.set_xlim(xlim)
            self.axes.set_ylim(ylim)

        # Refresh the tephigram plot isopleths.
        _refresh_isopleths(self.axes)

        # Show the plot legend.
        if 'label' in kwargs:
            font_properties = FontProperties(size='x-small')
            plt.legend(loc='upper left', fancybox=True, shadow=True, prop=font_properties)

        return profile

    def _status_bar(self, x_point, y_point):
        """Generate text for the interactive backend navigation status bar."""

        temperature, theta = transforms.xy_to_temperature_theta(x_point, y_point)
        pressure, _ = transforms.temperature_theta_to_pressure_temperature(temperature, theta)
        xlim = self.axes.get_xlim()
        zoom = (xlim[1] - xlim[0]) / self.original_delta_xlim
        text = "T:%.2f, theta:%.2f, phi:%.2f (zoom:%.3f)" % (float(temperature), float(theta), float(pressure), zoom)

        return text

    def _calculate_extents(self, xfactor=None, yfactor=None):
        min_x = min_y = 1e10
        max_x = max_y = -1e-10
        profiles = self._profiles

        if self._anchor is not None:
            profiles = [self._anchor]

        for profile in profiles:
            xy_points = self.tephi_transform.transform(np.concatenate((profile.temperature.reshape(-1, 1),
                                                                       profile.theta.reshape(-1, 1)),
                                                                       axis=1))
            x_points = xy_points[:, 0]
            y_points = xy_points[:, 1]
            min_x, min_y = np.min([min_x, np.min(x_points)]), np.min([min_y, np.min(y_points)])
            max_x, max_y = np.max([max_x, np.max(x_points)]), np.max([max_y, np.max(y_points)])

        if xfactor is not None:
            delta_x = max_x - min_x
            min_x, max_x = min_x - xfactor * delta_x, max_x + xfactor * delta_x

        if yfactor is not None:
            delta_y = max_y - min_y
            min_y, max_y = min_y - yfactor * delta_y, max_y + yfactor * delta_y

        return ([min_x, max_x], [min_y, max_y])