2025, Nov 19 11:00
How to prevent divide-by-zero warnings in Matplotlib secondary_xaxis for 1/x frequency-to-period mappings
Learn why Matplotlib’s secondary_xaxis causes divide-by-zero warnings with 1/x frequency-to-period transforms, and fix it using a zero-safe reciprocal function.
When adding a secondary x-axis in Matplotlib and mapping frequency to period with a simple 1/x transform, you may hit a “division by zero” warning even if your data never touches zero. This looks puzzling at first glance because all x values on the plot are positive and well-behaved.
Reproducing the issue
The example below uses a log-scaled x-axis with a top secondary axis defined via a reciprocal transform. The figure renders, but a divide-by-zero warning appears during execution.
import matplotlib.pyplot as plt
fig_plot, axes_main = plt.subplots(figsize=(10, 10))
freq_vals = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.6, 1.8, 2.0]
amp_vals = [0.0, 0.0, 0.0, 0.0, 0.0, 0.012, 0.031, 0.074, 0.082, 0.084, 0.080, 0.078, 0.072, 0.059, 0.039, 0.019, 0.010]
axes_main.semilogx(freq_vals, amp_vals, marker='s', color='purple')
plt.xlim(0.1, 10)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Crest Loss (ft)')
axes_main.set(title='Fundamental Frequency')
axes_main.grid()
axes_main.grid(which="minor", color="0.9")
def tx_forward(x):
return 1 / x
def tx_inverse(x):
return 1 / x
axes_top = axes_main.secondary_xaxis('top', functions=(tx_forward, tx_inverse))
axes_top.set_xlabel('Period (s)')
plt.show()Why the warning appears
This behavior stems from how the secondary axis machinery evaluates the transformation functions you pass in. The official Matplotlib example explicitly guards 1/x against zero to avoid divide-by-zero warnings. In other words, the issue is not about your plotted dataset; it’s about ensuring the transformation you provide is safe for the values it may be asked to evaluate. The documentation’s third example demonstrates a protective implementation and is available at https://matplotlib.org/stable/gallery/subplots_axes_and_figures/secondary_axis.html#secondary-axis; a companion example on the secondary_axis docs page does the same.
Solution: a zero-safe reciprocal
Mirror the approach from the docs and wrap the reciprocal in a function that treats zero specially. Below is a drop-in version for the example above that preserves behavior while preventing the warning.
import matplotlib.pyplot as plt
import numpy as np
fig_plot, axes_main = plt.subplots(figsize=(10, 10))
freq_vals = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.6, 1.8, 2.0]
amp_vals = [0.0, 0.0, 0.0, 0.0, 0.0, 0.012, 0.031, 0.074, 0.082, 0.084, 0.080, 0.078, 0.072, 0.059, 0.039, 0.019, 0.010]
axes_main.semilogx(freq_vals, amp_vals, marker='s', color='purple')
plt.xlim(0.1, 10)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Crest Loss (ft)')
axes_main.set(title='Fundamental Frequency')
axes_main.grid()
axes_main.grid(which="minor", color="0.9")
def safe_reciprocal(x):
x_arr = np.array(x, float)
zmask = np.isclose(x_arr, 0)
x_arr[zmask] = np.inf
x_arr[~zmask] = 1 / x_arr[~zmask]
return x_arr
inv_safe_reciprocal = safe_reciprocal
axes_top = axes_main.secondary_xaxis('top', functions=(safe_reciprocal, inv_safe_reciprocal))
axes_top.set_xlabel('Period (s)')
plt.show()This is functionally identical for valid inputs and simply avoids the divide-by-zero case. As reported by practitioners, adding this check removes the warning.
Why this matters
Secondary axes are convenient for showing related units—like frequency and period—but they rely on user-supplied transforms that must be robust in their entire evaluation domain. If a transformation has known singularities, accounting for them prevents runtime warnings and keeps plots predictable.
Conclusion
When using Matplotlib’s secondary_xaxis with a reciprocal mapping, defend against zero explicitly, as demonstrated in the official examples. If you do run into unexpected warnings, verify what the transformation receives and share the full traceback when debugging; both steps make the root cause and the fix much clearer.