3

how can a logscale be set for values that are already logged but too large to be exponentiated back to linear scale? example:

import matplotlib.pylab as plt
import numpy as np

def f_returns_verylarge_logs():
    # some computation here that returns very small numbers on a log scale
    # (meaning large negative numbers in log units)
    log10_y = [3000, 3100, 3200]
    return log10_y

ax1 = plt.subplot(2, 1, 1)
x = [1, 2, 3]
# y values are small, so it is no problem to keep them
# around in LINEAR scale
y = [50, 100, 200]
plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y")
ax1.set(yscale="log")
ax2 = plt.subplot(2, 1, 2)
x = [1, 2, 3]
log_y = f_returns_verylarge_logs()
y = np.power(10., log_y) 
plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y")
ax2.set(yscale="log")
plt.show()

this gives overflow error:

RuntimeWarning: overflow encountered in power
  y = np.power(10., log_y)

the goal is to make the bottom plot work and look (in terms of yticks/labels) like the top without unlogging log_y since it causes overflow.

a bad solution is to scale down the log values and then unlog them as in:

plt.figure()
scaled_log_y = np.array(log_y) / 100.
scaled_unlog_y = np.power(10., scaled_log_y)
plt.plot(x, scaled_unlog_y)
plt.gca().set(yscale="log")
plt.ylabel("y (units are wrong)")
plt.xlabel("x")
plt.show()

but this gives wrong units: for 3000, it says 10^30 instead of 10^3000.

  • 2
    Why do you want to turn on the logarithmic scale if the values are already logarithmic? – mkrieger1 Jun 13 '19 at 13:27
  • @mkrieger1: to get all the nice axis formatting - labels like 10^x, the minor ticks that come with that, etc. –  Jun 13 '19 at 13:31
  • It would be super helpful if the reader is spared of doing all the math and comprehending what you mean, and you include some example of what the final figure should look like, providing a sample case of the transformation/rescaling you are talking about. – Sheldore Jun 13 '19 at 13:49
  • Ticks and scale are two different pair of shoes. But to me it doesn't make sense to have logarithmically scaled ticks on a linear axis. Hence I think this question needs a bit more explanation about the problem and a clear description of the desired outcome. Pay attention not to make this an xyproblem. – ImportanceOfBeingErnest Jun 13 '19 at 14:23
  • @ImportanceOfBeingErnest: see edits. the yaxis here is not linear. –  Jun 13 '19 at 14:41
  • Still not clear, sorry. Maybe someone else will understand it. – ImportanceOfBeingErnest Jun 13 '19 at 14:58
  • @ImportanceOfBeingErnest: added another edit. don't understand what's unclear. The point 3000 should appear as 10^-3000, ... –  Jun 13 '19 at 15:21

1 Answers1

2

Possibly you want something like the following, where simply each tick at position n is labelled by "10^n".

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker

x = [1, 2, 3]
y1 = [50, 100, 200]
y2 = [3000, 3100, 3200]

ax1 = plt.subplot(2, 1, 1)
ax1.plot(x, y1)
ax1.set_xlabel("x")
ax1.set_ylabel("y")
ax1.set(yscale="log")

ax2 = plt.subplot(2, 1, 2)

ax2.plot(x, y2)
ax2.set_xlabel("x")
ax2.set_ylabel("y")
ax2.yaxis.set_major_formatter(mticker.FuncFormatter(lambda x,_: f"$10^{{{int(x)}}}$"))

plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • 1
    yes, exactly, but I also want the minor ticks with logspacing like you have in the top subplot –  Jun 13 '19 at 21:09
  • @user248237, For adding minor ticks, try this: https://stackoverflow.com/a/64840431/1265409 – Moot Nov 08 '22 at 21:13