1

I need to get a x,y plot with a logarithmic scale on the x-axes. When I zoom in the x-axes should autoscale as the (not logarithmic) y-axes.

plt.xscale('log')
plt.grid(True)
plt.autoscale(True,True,True)
plt.legend(loc='best')
plt.show()

Normal print

Zoomed in print

As you can see there is no working autoscale function on the x-axes. How can I get this to display properly?

3 Answers 3

3

The solution by @hashcode55 does not work as it is what I was attempting before I found this thread.

It seems to me that there is simply a "bug" in that:

plt.yscale('log')
plt.autoscale(enable=True, axis='y')

are not compatible.

Here is my sample code:

import matplotlib.pyplot as plt
import matplotlib
import random
import numpy as np

# generate some random data and add it to the plot
x = np.array(range(1,100))
y = np.maximum(np.ones(99), np.random.randn(99))
plt.plot(x, y, markersize=4, marker='.', color='red')

# format
ax = plt.gca()
plt.ylabel('LOGARITHMIC SCALE')
plt.yscale('log')
plt.minorticks_on
ax.yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
plt.autoscale(enable=True, axis='y')

#ax.set_ylim([np.min(y), np.max(y)])

#plot
plt.show()

which produces:

enter image description here

log scale, but clearly not autoscale

if I remove the comments from this line:

ax.set_ylim([np.min(y), np.max(y)])

Then it actually plots as would be expected with autoscale:

enter image description here

Nice, but what if I've lost reference to my y values on the plot?

while this solution/answer is a good "hack" to this sample problem, it its not a solid solution for my situation as my chart is a) live; continually updating every minute b) contains MANY plots c) is dropping off data older than past 24 hours; so such a solution would get really hacky if implemented every time something was added or removed from the plot in live session.

I would be interested in a true built-in "autoscale" solution, if such exists, that works with log y scale and I can auto update using plt.ion()

until then, what about this:

h/t @David Z How to extract data from matplotlib plot

#if you do need to get data out of a plot, I think this should do it

gca().get_lines()[n].get_xydata()

#Alternatively you can get the x and y data sets separately:

line = gca().get_lines()[n]
xd = line.get_xdata()
yd = line.get_ydata()

implemented in our situation at hand (with an extra blue line to test multiple lines) as:

import matplotlib.pyplot as plt
import matplotlib
import random
import numpy as np

# generate some random data and add it to the plot
x = np.array(range(1,100))
y = np.maximum(np.ones(99), np.random.randn(99))
plt.plot(x, y, markersize=4, marker='.', color='red')

# test for compatibility with multilpes lines
x = np.array(range(1,100))
y = np.maximum(np.ones(99), 1.5*np.random.randn(99))
plt.plot(x, y, markersize=4, marker='.', color='blue')

# format
ax = plt.gca()
plt.ylabel('LOGARITHMIC SCALE')
plt.yscale('log')
plt.minorticks_on
ax.yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
#plt.autoscale(enable=True, axis='y')

#####################################################
#force 'autoscale'
#####################################################
yd = [] #matrix of y values from all lines on plot
for n in range(len(plt.gca().get_lines())):
        line = plt.gca().get_lines()[n]
        yd.append(line.get_ydata())
ax.set_ylim([0.9*np.min(yd), 1.1*np.max(yd)])
#####################################################  

#plot
plt.show()

which, in essence, is pulling all y data from all lines on the plot, finding the max and min; then implementing them via set_ylim; "forcing" autoscale

yields:

enter image description here

voila!

for my situation I had somewhat more complicated plots in the format:

plt.plot((x1,x2), (y1,y2))

creating a matrix in matrix situation producing a 'Value Error'

for that I had to flatten using:

yd = [item for sublist in yd for item in sublist]

h/t @Alex Martelli Making a flat list out of list of lists in Python

and this was the final product:

#####################################################
#force 'autoscale'
#####################################################
yd = [] #matrix of y values from all lines on plot
for n in range(len(plt.gca().get_lines())):
        line = plt.gca().get_lines()[n]
        yd.append((line.get_ydata()).tolist())

yd = [item for sublist in yd for item in sublist]
ax.set_ylim([0.9*np.min(yd), 1.1*np.max(yd)])
#####################################################

enter image description here

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

Comments

0

If you look at the documentation the function is like-

matplotlib.pyplot.autoscale(enable=True, axis='both', tight=None)

What you are sending is an invalid argument...

just make it

plt.autoscale(True, axis = 'both')

And about tight -

If True, set view limits to data limits; if False, let the locator and margins expand the view limits; if None, use tight scaling if the only artist is an image, otherwise treat tight as False. The tight setting is retained for future autoscaling until it is explicitly changed.

1 Comment

Thanks. I have corrected the code like this plt.xscale('log') plt.grid(True) plt.autoscale(True, axis = 'both') plt.legend(loc='best') plt.show() but it's the same like before. When I delete plt.xscale('log') it works correctly.
0

I had a similar problem and I was able to solve it by setting the 'log' scale before plotting. In this case, the autoscaling is working as expected.

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.