[Data processing] python Matplotlib partially enlarges the figure; marks the local enlarged subfigure of interest

Foreword

In data visualization, it is often necessary to partially enlarge the data in a certain interval to obtain a higher contrast visualization effect. The following uses the Matplotlib library of the Python language to implement a simple partial magnification effect.

Dependent libraries

matplotlib: plotting library
numpy: an extended library that supports a large number of dimensional arrays, matrix operations, and mathematical functions

Steps

  1. Import dependent libraries
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
  1. Prepare data
x = np.linspace(-0.1*np.pi, 2*np.pi, 30)
y_1 = np.sinc(x) + 0.7
y_2 = np.tanh(x)
y_3 = np.exp(-np.sinc(x))
  1. Drawing
fig, ax = plt.subplots(1, 1, figsize=(6, 4))
ax.plot(x, y_1, color='k', linestyle=':', linewidth=1,
        marker='o', markersize=5,
        markeredgecolor='black', markerfacecolor='C0')

ax.plot(x, y_2, color='k', linestyle=':', linewidth=1,
        marker='o', markersize=5,
        markeredgecolor='black', markerfacecolor='C3')

ax.plot(x, y_3, color='k', linestyle=':', linewidth=1,
        marker='o', markersize=5,
        markeredgecolor='black', markerfacecolor='C2')

ax.legend(labels=["y_1", "y_2","y_3"], ncol=3)

The renderings are as follows:

  1. Embed the coordinate system for drawing the local enlargement
axins = inset_axes(ax, width="40%", height="30%", loc='lower left',
                   bbox_to_anchor=(0.1, 0.1, 1, 1),
                   bbox_transform=ax.transAxes)

Parameter Description

ax: Parent coordinate system
width, height: The width and height of the sub-coordinate system (in percentage form or floating point number)
loc: The position of the child coordinate system
bbox_to_anchor: bounding box, quad array (x0, y0, width, height)
bbox_transform: Geometric mapping from parent coordinate system to child coordinate system
axins: sub-coordinate system
Fixed the width and height of the coordinate system and the bounding box, and set loc to the upper left, lower left, upper right (default), lower right and middle respectively. The effect is as follows:

For detailed usage instructions on mpl_toolkits.axes_grid1.inset_locator.inset_axes, please refer to the official documentation

https://matplotlib.org/3.2.1/api/_as_gen/mpl_toolkits.axes_grid1.inset_locator.inset_axes.html

In this example, embed the subcoordinate system at the appropriate location:

axins = inset_axes(ax, width="40%", height="30%", loc='lower left',
                   bbox_to_anchor=(0.5, 0.1, 1, 1),
                   bbox_transform=ax.transAxes)

The renderings are as follows:

There is also a more concise method of embedding sub-coordinate systems:–Recommended

axins = ax.inset_axes((0.2, 0.2, 0.4, 0.3))

ax is the parent coordinate system, and the following four parameters are also (x0, y0, width, height). The meaning of the above code is: x0=0.2x, y0=0.2y in the parent coordinate system As the starting point of the lower left corner, embed a child coordinate system with a width of 0.4x and a height of 0.3y, where x and y are the coordinate axis ranges of the parent coordinate system respectively. Results as shown below:

  1. Plot original data in subcoordinate system
axins.plot(x, y_1, color='k', linestyle=':', linewidth=1,
            marker='o', markersize=5,
            markeredgecolor='black', markerfacecolor='C0')

axins.plot(x, y_2, color='k', linestyle=':', linewidth=1,
            marker='o', markersize=5,
            markeredgecolor='black', markerfacecolor='C3')

axins.plot(x, y_3, color='k', linestyle=':', linewidth=1,
            marker='o', markersize=5,
            markeredgecolor='black', markerfacecolor='C2')

The rendering is as follows:

  1. Set the magnification interval and adjust the display range of the sub-coordinate system
# Set the zoom interval
zone_left = 11
zone_right = 12

# The expansion ratio of the coordinate axis (adjusted based on actual data)
x_ratio = 0.5 # The expansion ratio of the x-axis display range
y_ratio = 0.5 # The expansion ratio of the y-axis display range

# Display range of X axis
xlim0 = x[zone_left]-(x[zone_right]-x[zone_left])*x_ratio
xlim1 = x[zone_right] + (x[zone_right]-x[zone_left])*x_ratio

#Y-axis display range
y = np.hstack((y_1[zone_left:zone_right], y_2[zone_left:zone_right], y_3[zone_left:zone_right]))
ylim0 = np.min(y)-(np.max(y)-np.min(y))*y_ratio
ylim1 = np.max(y) + (np.max(y)-np.min(y))*y_ratio

#Adjust the display range of the sub-coordinate system
axins.set_xlim(xlim0, xlim1)
axins.set_ylim(ylim0, ylim1)

The renderings are as follows:

  1. Establish a connection line between the parent coordinate system and the child coordinate system
# loc1 loc2: four corners of the coordinate system
# 1 (upper right) 2 (upper left) 3 (lower left) 4 (lower right)
mark_inset(ax, axins, loc1=3, loc2=1, fc="none", ec='k', lw=1)

loc1 and loc2 are the four corners of the parent coordinate system and the child coordinate system respectively, and their values are 1, 2, 3, and 4. The corresponding four corners are: upper right, upper left, lower left, and lower right. Taking loc1=3, loc2=1 as an example, the implemented function is: the lower left corner of the parent coordinate system is connected to the lower left corner of the child coordinate system, and the upper right corner of the parent coordinate system is connected to the upper right corner of the child coordinate system. The renderings are as follows:


The above is an example of using Matplotlib to implement the local enlargement drawing method. The key lies in the setting of the bbox_to_anchor parameter. Using this parameter, the coordinate system embedding at any position can be achieved.

The complete code is as follows:

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
from mpl_toolkits.axes_grid1.inset_locator import inset_axes

# Prepare data
x = np.linspace(-0.1*np.pi, 2*np.pi, 30)
y_1 = np.sinc(x) + 0.7
y_2 = np.tanh(x)
y_3 = np.exp(-np.sinc(x))


# drawing
fig, ax = plt.subplots(1, 1, figsize=(6, 4))
ax.plot(x, y_1, color='k', linestyle=':', linewidth=1,
        marker='o', markersize=5,
        markeredgecolor='black', markerfacecolor='C0')

ax.plot(x, y_2, color='k', linestyle=':', linewidth=1,
        marker='o', markersize=5,
        markeredgecolor='black', markerfacecolor='C3')

ax.plot(x, y_3, color='k', linestyle=':', linewidth=1,
        marker='o', markersize=5,
        markeredgecolor='black', markerfacecolor='C2')

ax.legend(labels=["y_1", "y_2","y_3"], ncol=3)

# Embed the coordinate system for drawing the local enlargement map
axins = inset_axes(ax, width="40%", height="30%",loc='lower left',
                   bbox_to_anchor=(0.5, 0.1, 1, 1),
                   bbox_transform=ax.transAxes)

# Draw the original data in the sub-coordinate system
axins.plot(x, y_1, color='k', linestyle=':', linewidth=1,
            marker='o', markersize=5,
            markeredgecolor='black', markerfacecolor='C0')

axins.plot(x, y_2, color='k', linestyle=':', linewidth=1,
            marker='o', markersize=5,
            markeredgecolor='black', markerfacecolor='C3')

axins.plot(x, y_3, color='k', linestyle=':', linewidth=1,
            marker='o', markersize=5,
            markeredgecolor='black', markerfacecolor='C2')

# Set the zoom interval
zone_left = 11
zone_right = 12

# The expansion ratio of the coordinate axis (adjusted based on actual data)
x_ratio = 0.5 # The expansion ratio of the x-axis display range
y_ratio = 0.5 # The expansion ratio of the y-axis display range

# Display range of X axis
xlim0 = x[zone_left]-(x[zone_right]-x[zone_left])*x_ratio
xlim1 = x[zone_right] + (x[zone_right]-x[zone_left])*x_ratio

#Y-axis display range
y = np.hstack((y_1[zone_left:zone_right], y_2[zone_left:zone_right], y_3[zone_left:zone_right]))
ylim0 = np.min(y)-(np.max(y)-np.min(y))*y_ratio
ylim1 = np.max(y) + (np.max(y)-np.min(y))*y_ratio

#Adjust the display range of the sub-coordinate system
axins.set_xlim(xlim0, xlim1)
axins.set_ylim(ylim0, ylim1)

# Establish the connection line between the parent coordinate system and the child coordinate system
# loc1 loc2: four corners of the coordinate system
# 1 (upper right) 2 (upper left) 3 (lower left) 4 (lower right)
mark_inset(ax, axins, loc1=3, loc2=1, fc="none", ec='k', lw=1)

# show
plt.show()