0

When plotting data, vertical line gets incorrectly transformed by matplotlib. With linear x axis, my curve and the vertical line pointing to a specific location on the curve match perfectly. Vertical line touching curve as expected After plt.xscale('log') the end point of the vertical line is not on my curve anymore. Second screenshot after log transform

import numpy as np
import matplotlib.pyplot as plt

# Generate example data: x values from 1 to 16 (log scale)
x = np.array([1, 2, 4, 8, 16])
y = np.array([0.1, 0.2, 0.3, 0.6, 0.9])

# Perform linear interpolation to find where y crosses 0.5
crossings = np.where(np.diff(np.sign(y - 0.5)))[0]

if len(crossings) > 0:
    crossing_index = crossings[0]
    x1, x2 = x[crossing_index], x[crossing_index + 1]
    y1, y2 = y[crossing_index], y[crossing_index + 1]
    
    # Linear interpolation to find exact x for y = 0.5
    x_nd50 = x1 + (0.5 - y1) * (x2 - x1) / (y2 - y1)
    
    print(f"Interpolated x (ND50) = {x_nd50}")

# Plot the data with a logarithmic x scale
plt.plot(x, y, label="Data", color="blue")

# Plot the vertical line at the interpolated ND50 value
plt.plot([x_nd50, x_nd50], [0, 0.5], color='red', linestyle="--", alpha=0.7)
plt.scatter(x_nd50, 0.5, color='red', marker='x', alpha=0.7)

# First screenshot taken at this point!

# Set x-axis to log scale (log2)
plt.xscale('log')

# Second screenshot taken at this point!

# Show the plot
plt.xlabel('Log-scaled X')
plt.ylabel('Y')
plt.legend()
plt.show()

2
  • 2
    The straight, linearly interpolated (by Matplotlib) lines in the first plot would become curved lines in the log plot. But Matplotlib can't plot that, because it doesn't have enough information about the curve; hence it shows straight lines in the log plot, which would be curved lines in the linear plot. That causes an interpolated point (which your 'x' is) to not match up with the blue curve anymore. Commented Dec 3, 2024 at 12:21
  • 1
    To solve this, you should calculate the y-value of the 'x' in x-logspace. I'm not directly sure how to go about that; if it were the y-axis that was logarithmic, it would be a tad easier to calculate. Commented Dec 3, 2024 at 12:23

1 Answer 1

2

You calculate the x-position using linear interpolation. But on a log-plot, linear interpolation doesn't work.

In fact, Matplotlib shows straight lines on the log-plot, but these are not the same straight lines as on the linear-plot: they would be curved if they were the same, and vice versa. Matplotlib just tries its best, having no extra information about the curve shape between the points. (And it assumes you picked log-space so that curves would show as straight lines, so it defaults to straight lines between the points.)

Hence you need to calculate the x-position using logarithm x-data. You can solve it as follows:

[...]

xlog = True
# Perform linear interpolation to find where y crosses 0.5
crossings = np.where(np.diff(np.sign(y - 0.5)))[0]

if len(crossings) > 0:
    crossing_index = crossings[0]
    x1, x2 = x[crossing_index], x[crossing_index + 1]
    y1, y2 = y[crossing_index], y[crossing_index + 1]

    if xlog:
        x1 = np.log10(x1)
        x2 = np.log10(x2)
    # Linear interpolation to find exact x for y = 0.5
    x_nd50 = x1 + (0.5 - y1) * (x2 - x1) / (y2 - y1)
    if xlog:
        x_nd50 = 10**x_nd50
    print(f"Interpolated x (ND50) = {x_nd50}")

[...]

# Set x-axis to log scale (log2)
if xlog:
    plt.xscale('log')

[...]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.