Adding a shadow to the chart line

To be able to distinguish one particular plot line in the figure or just to fit in the overall style of the output our figure is in, we sometimes need to add a shadow effect to the chart line (or histogram, for that matter). In this recipe, you will be learning how to add a shadow effect to the plot's chart lines.

Getting ready

To add shadows to the lines or rectangles in our charts, we need to use the transformation framework built in matplotlib and located in matplotlib.transforms.

To understand how it all works, we need to explain what transformations are available in matplotlib and how they work.

Transformations know how to convert the given coordinates from their coordinate system into display. They also know how to convert them from display coordinates into their own coordinate system.

The following table summarizes the existing coordinate systems and what they represent:

Coordinate system

Transformation object

Description

Data

Axes.transData

Represents the user's data coordinate system.

Axes

Axes.transAxes

Represents the Axes coordinate system, where (0,0) represents the bottom-left end of the axes and (1,1) represents the upper-right end of the axes.

Figure

Figure.transFigure

This is the Figure coordinate system, where (0,0) represents the bottom-left end of the figure and (1,1) represents the upper-right end of the figure.

Display

None

Represents the pixel coordinate system of the user display, where (0,0) represents the bottom-left of the display, and tuple (width, height) represents the upper-right of the display, where width and height are in pixels.

Note how the display does not have a value in the column. This is because the default coordinate system is Display, so coordinates are always in pixels relative to your display coordinate systems. This is not very useful, and most often we want them normalized into Figure or Axes or a Data coordinate system.

This framework enables us to transform the current object into an offset object, that is, to place that object shifted a certain distance from the original object.

We will use this framework to create our desired effect on the plotted sine wave.

How to do it...

Here is the code recipe to add shadowing to the plotted chart. The code is explained in the section that follows.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms

def setup(layout=None):
    assert layout is not None

    fig = plt.figure()
    ax = fig.add_subplot(layout)
    return fig, ax

def get_signal():
    t = np.arange(0., 2.5, 0.01)
    s = np.sin(5 * np.pi * t)
    return t, s

def plot_signal(t, s):
    line, = axes.plot(t, s, linewidth=5, color='magenta')
    return line

def make_shadow(fig, axes, line, t, s):
    delta = 2 / 72.  # how many points to move the shadow
    offset = transforms.ScaledTranslation(delta, -delta, fig.dpi_scale_trans)
    offset_transform = axes.transData + offset

    # We plot the same data, but now using offset transform
    # zorder -- to render it below the line
    axes.plot(t, s, linewidth=5, color='gray',
              transform=offset_transform,
              zorder=0.5 * line.get_zorder())

if __name__ == "__main__":
    fig, axes = setup(111)
    t, s = get_signal()
    line = plot_signal(t, s)

    make_shadow(fig, axes, line, t, s)

    axes.set_title('Shadow effect using an offset transform')
    plt.show()

How it works...

We start reading the code from the bottom, after the if __name__ check. First, we create the figure and axes in setup(); after that, we obtain a signal (or generate data—sine wave). We plot the basic signal in plot_signal(). Then, we make the shadow transformation and plot the shadow in make_shadow().

We use the offset effect to create an offset object underneath and just a few points away from the original object.

The original object is a simple sine wave that we plot using the standard function plot().

To add to this offset transformation, matplotlib contains helper transformation—matplotlib.transforms.ScaledTranslation.

The values for dx and dy are defined in points, and as the point is 1/72 inches, we move the offset object 2 pt right and 2pt down.

Tip

If you want to learn more about how we converted the point to 1/72 inches, read more in this Wikipedia article: http://en.wikipedia.org/wiki/Point_%28typography%29.

We can use matplotlib.transforms.ScaledTransformation(xtr, ytr, scaletr); here, xtr and ytr are translation offsets and scaletr is a transformation callable to scale xtr and ytr at transformation time and before display. The most common use case for this is transforming from points to display space—for example—to DPI so that the offset always stays at the same place no matter what the actual output—be it the monitor or printed material. The callable we use for this is already built in, and is available at Figure.dpi_scale_trans.

We then plot the same data with the applied transformation.

There's more...

Using transforms to add shadows is just one and not the most popular use case of this framework. To be able to do more with the transformation framework, you will need to learn the details of how the transformation pipeline works and what the extension points are (what classes to inherit and how). This easy enough because matplotlib is open source, and even if some code is not well documented, there is a source you can read from and use or change, thus contributing to the overall quality and usefulness of matplotlib.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.186.79