1

As this answer https://stackoverflow.com/a/47850534 points out, np.log(x) is not the same as plotting x on a log scale.

Given (the same) array of data:

x = [2, 1, 76, 140, 286, 267, 60, 271, 5, 13, 9, 76, 77, 6, 2, 27, 22, 1, 12, 7, 19, 81, 11, 173, 13, 7, 16, 19, 23, 197, 167, 1]

Plotting the data directly has a chart like so:

plt.plot(x)
plt.show()

enter image description here

Using the 'log' scale looks like:

plt.plot(x)
plt.xscale('log')
plt.show()

enter image description here

Plotting np.log(x) does something entirely different:

plt.plot(np.log(x))
plt.show()

enter image description here

Is there a function that rescales the array values in logspace, or would this require something like interpolation?

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
001001
  • 530
  • 1
  • 4
  • 13
  • Don't you want `plt.yscale('log')` in the second example instead of `plt.xscale('log')`? – samgiz Jul 21 '21 at 00:14
  • @samgiz well either/both would be helpful answers. The issue is not in making matplotlib scale the axis, its transforming the data itself. – 001001 Jul 21 '21 at 02:05

2 Answers2

2

The confusion arises from how you are plotting x. First of all, let's call the array y, since it's y-values:

y = [2, 1, 76, 140, 286, 267, 60, 271, 5, 13, 9, 76, 77, 6, 2, 27, 22, 1, 12, 7, 19, 81, 11, 173, 13, 7, 16, 19, 23, 197, 167, 1]

plt.plot(y) is equivalent to

x = np.arange(len(y))
plt.plot(x, y)

Hopefully you can see where this is going. If you want to log-scale the x-axis, you can log-scale the values in x. Similarly for the y-values, or even both directions at once:

fig, ax = plt.subplots(2, 3, constrained_layout=True)

ax[0, 0].semilogx(x, y)
ax[1, 0].plot(np.log(x), y)
ax[0, 1].semilogy(x, y)
ax[1, 1].plot(x, np.log(y))
ax[0, 2].loglog(x, y)
ax[1, 2].plot(np.log(x), np.log(y))

ax[0, 0].set_ylabel('Scaled Axes')
ax[1, 0].set_ylabel('Scaled Data')
ax[0, 0].set_title('X')
ax[0, 1].set_title('Y')
ax[0, 2].set_title('Both')

enter image description here

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • okay thanks. I this was kind of doing the same thing I wanted to get around; using matplotlib to scale the data. I can call it x or y, its a single array of data that should correspond to 'equal' spacing (where equal is either linear or... log). So making a new log of linear x data points that matplotlib does the conversion for me doesn't solve it. I was looking for a mapping e.g., for each point in the series, what would the new y value be in log space. – 001001 Jul 21 '21 at 11:52
  • * I still think this answer is really helpful though, and to others – 001001 Jul 21 '21 at 11:53
  • @001001. I literally answered your question. The logarithm is exactly how you map to log space. There is no catch here. – Mad Physicist Jul 21 '21 at 12:06
  • Sorry if I am not explaining well, or if I am missing the obvious next step to get the array. What I am trying to say is, the reason I was plotting only 'x' was because the data is some array of evenly spaced y values, so there is no need to set a custom 'x' labels with 'y' values. meaning, `plt.plot(x)` will use the indices as the 'step' in x, with the value as the 'y' axis. I want to transform the data of the array, so that `plt.plot(x')` plots to be the same graph as if I was to use the log axis scale, whereas (as I understand) your answer uses a secondary array to map? – 001001 Jul 21 '21 at 13:00
  • @001001. Whether you pass it in or not, the x-axis is going to be `np.arange(len(y))`. If you want to log scale the x-position, you have to map *that* array to log space, not `y`. – Mad Physicist Jul 21 '21 at 13:41
-2

Even though your variable is named x, when you plot it, it is plotted as the y-coordinate. Try doing plt.yscale('log')

Martí
  • 571
  • 6
  • 17