0

I would like to plot on top of a picture of a graph from a paper. I plot the picture with a simple imshow:

import matplotlib.pyplot as plt
import matplotlib.image as mpimg    
img = mpimg.imread('screenshot.png')
plt.imshow(img)

Now, is there a way to align the axes so that I can plot my own data of the electron density and compare with the data in the figure? I tried to use a scaling factor as suggested by Chat GPT, but I can't make it work. Here is what it suggested:

# Data point in the picture
x_picture = 0.01

# Corresponding data point on the Python plot
x_python_plot = 80

# Calculate the scaling factor
scaling_factor = x_python_plot / x_picture

# Apply the scaling factor to your data for plotting
x_data_scaled = [x * scaling_factor for x in x_data]

# Plot your data on the new axes
ax.plot(x_data_scaled, y_data, color='red', linewidth=2)

(and the same for y, but for x alone it already doesn't work). I think plt.imshow(img, extent=[x1, x2, y1, y2]) could work if I could determine the x's and y's somehow, but even then, there's the issue of the log scale on the x-axis. I know I could crop the image so the axes coincide with the axes of the plot, but I would rather not do it like that and keep the layout of the figure.

Your ideas are appreciated!

Below are the picture loaded with imshow and the raw picture if you want to try it out. imshow rawimage

theWrongAlice
  • 99
  • 2
  • 10

1 Answers1

1

Since your image is only available in a limited resolution, the precision of your overlayed graph will be limited as well.

That bing said, you can define conversion factor and offset for both axes by writing down the positions (coordinates) of the picture's axes limits. I found that:

y=426 at the bottom (image value 30)
y=18 at the top (image value 100)

It results in the following equation system:

30a + b = 426
100a + b = 18

This gives us a conversion a=-5.83 and b=601 for the y-axis.

Similarly, after playing with the values a bit, I found that x_scaled = 70*log(x) + 230 works well in your case.

For a cleaner representation remove everything around the image like shown here:

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from math import log

img = mpimg.imread('screenshot.png')

fig, ax = plt.subplots()
ax.imshow(img)
fig.subplots_adjust(left=0, bottom=0, right=1, top=1)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.set_xticks([])
ax.set_yticks([])

def scale_x(x):
    return 70*log(x, 10) + 230

def scale_y(y):
    return -5.83*y + 601

def scale_plot(x_arr, y_arr, ax=plt.gca()):
    x_arr_scaled = [scale_x(x) for x in x_arr]
    y_arr_scaled = [scale_y(y) for y in y_arr]
    ax.scatter(x_arr_scaled, y_arr_scaled) # feel free to use plot() instead

scale_plot([0.1, 1000, 10000], [60, 90, 50], ax)

plt.show()

Output for points (0.1, 60), (1000, 90) and (10000, 50):

enter image description here

Tranbi
  • 11,407
  • 6
  • 16
  • 33