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
- 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
- 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)
The renderings are as follows:
- 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:
- 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:
- 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:
- 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()