I would like to change the major tick label spacing to intervals of 0.1 (base 0.1) and have minor ticks (without labels) at 0.01 spacing for the code below (output shown in 1.
x = np.array([1, 5, 10, 32])
y = np.array([0.34, 0.27, 0.25, 0.21])
yerr = np.array([0.02, 0.019, 0.019, 0.016])
fig, ax = plt.subplots()
res = ax.errorbar(x, y, yerr=yerr, fmt='.', ls='')
ax.set_xscale('log')
ax.set_yscale('log')
I've tried to do
import matplotlib.ticker as mtick
ax.yaxis.set_major_locator(mtick.LogLocator(base=0.01))
however nothing changes, which makes me think the base can not be less than 10.
SOLUTION: Thanks ImportanceOfBeingErnest for the advice. My solution is to add this:
import matplotlib.ticker as mtick
ax.yaxis.set_major_locator(mtick.LogLocator(base=10, subs=range(10)))
ax.yaxis.set_minor_locator(mtick.LogLocator(base=10, subs=range(100)))
plt.setp(ax.get_yminorticklabels(), visible=False);
EDIT: OK, the reasoning behind this is wrong ( & I misundertood the question)
This would add equidistant space between the ticks, definitely not you were asking.
plt.grid("on") # Just to see the spacing more clearly
ax.yaxis.set_major_locator(mtick.LogLocator(base=10**(1.0/1)))
ax.yaxis.set_minor_locator(mtick.LogLocator(base=10**(1.0/10)))
(asuming 10 is the base of the log scale you're using and the fraction is how many more (or less) lines you want.
I did not understand how the decimal values in the 'base' variable work when using logarithmic scale.
Well, since you're working in logarithmic values ... that 'spacing' shouldn't be 1 or less. (using 1 you get an error) if you want to reduce spacing, just use a value between less than 10 (but more than 1).
In fact, using the line:
plt.grid("on") # Just to see the spacing more clearly
ax.yaxis.set_major_locator(mtick.LogLocator(base=10**(1/10)))
you get a tenth of a spacing than before.
It's all in how the vertical axes is computed when using the logarithmic scale.
Related
I have a bar graph that is log scaled that I am trying to change the y ticks from 10^1, 10^2, etc., to whole numbers. I have tried setting the tick values manually, and tried setting the values from the data, and also setting the format to scalar. One thing I notice in all of the questions I am looking at is that my construction of the graph doesn't include subplot.
def confirmed_cases():
x = df['Date']
y = df['Confirmed']
plt.figure(figsize=(20, 10))
plt.bar(x, y)
plt.yscale('log')
# plt.yticks([0, 100000, 250000, 500000, 750000, 1000000, 1250000])
# plt.get_yaxis().set_major_formatter(matplotlib.ticker.ScalarFormatter())
plt.title('US Corona Cases By Date')
plt.xlabel('Date')
plt.ylabel('Confirmed Cases')
plt.xticks(rotation=90)
There a few issues:
The formatter needs to be placed at the yaxis of the ax. Useplt.gca() to get the current ax. Note that there is no function plt.get_yaxis().
The scalar formatter starts using exponential notation for large numbers. To prevent that, set_powerlimits((m,n)) makes sure the powers are only shown for values outside the range 10**m and 10**n.
In a log scale, major ticks are used for values 10**n for integer n. The other ticks or minor ticks, at positions k*10**n for k from 2 to 9. If there are only a few major ticks visible, the minor ticks can also get a tick label. To suppress both the minor tick marks and their optional labels, a NullFormatter can be used.
Avoid using a tick at zero for a log-scale axis. Log(0) is minus infinity.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
plt.figure(figsize=(20, 10))
plt.bar(np.arange(100), np.random.geometric(1/500000, 100))
plt.yscale('log')
formatter = matplotlib.ticker.ScalarFormatter()
formatter.set_powerlimits((-6,9))
plt.gca().yaxis.set_major_formatter(formatter)
plt.gca().yaxis.set_minor_locator(matplotlib.ticker.NullLocator())
plt.yticks([100000, 250000, 500000, 750000, 1000000, 1250000])
plt.show()
Thanks in advance for taking the time to read my question. I'm having trouble plotting an array of negative powers of 10 in matplotlib
I have read through all of the log xscale options in the matplotlib documentation but to no avail. I have also read the following questions and some others which seemed similar but they did not end up helping me out:
Matplotlib: disable powers of ten in log plot
Plot Axis in Python with Log Scale for Negative Exponents of 10
Logscale plots with zero values in matplotlib *with negative exponents*
Logscale plots with zero values in matplotlib
This is more or less in simple form what my code looks like.
x = np array with 100 values of 0.99999, 0.9999, 0.999, 0.99
y = np array with corresponding evaluation outputs to be plotted.
plt.plot(x, y, 'o')
plt.xticks([0.99999,0.9999,0.999,0.99])
plt.gca().set_xscale('log')
What I'm trying to attain is a plot with just the values 0.99999, 0.9999, 0.999, 0.99 evenly spaced on the x axis plotted against their corresponding y values.
Once again I would like to thank you so much for taking the time to read this question, and I sincerely hope you can help me out!
You could easily "fake" this kind of plot, by plotting y against [0,1,2,3,...] and then replacing the xtickslabel with [0.9999,0.999,0.99,...]
x = [0.99999,0.9999,0.999,0.99]
y = [1,2,3,4]
fig, ax = plt.subplots()
ax.plot(range(len(x)),y, 'o-')
ax.set_xticks(range(len(x)))
ax.set_xticklabels(x)
I am trying to customize the xticks and yticks for my scatterplot with the simple code below:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
y_ticks = np.arange(10, 41, 10)
x_ticks = np.arange(1000, 5001, 1000)
ax.set_yticks(y_ticks)
ax.set_xticks(x_ticks)
ax.scatter(some_x, some_y)
plt.show()
If we comment out the line: ax.scatter(x, y), we get an empty plot with the correct result:
However if the code is run exactly as shown, we get this:
Finally, if we run the code with ax.set_yticks(yticks) and ax.set_xticks(xticks) commented out, we also get the correct result (just with the axes not in the ranges I desire them to be):
Note that I am using Python version 2.7. Additionally, some_x and some_y are omitted.
Any input on why the axes are changing in such an odd manner only after I try plotting a scatterplot would be appreciated.
EDIT:
If I run ax.scatter(x, y) before xticks and yticks are set, I get odd results that are slightly different than before:
Matplotlib axes will always adjust themselves to the content. This is a desirable feature, because it allows to always see the plotted data, no matter if it ranges from -10 to -9 or from 1000 to 10000.
Setting the xticks will only change the tick locations. So if you set the ticks to locations between -10 and -9, but then plot data from 1000 to 10000, you would simply not see any ticks, because they do not lie in the shown range.
If the automatically chosen limits are not what you are looking for, you need to set them manually, using ax.set_xlim() and ax.set_ylim().
Finally it should be clear that in order to have correct numbers appear on the axes, you need to actually use numbers. If some_x and some_y in ax.scatter(some_x, some_y) are strings, they will not obey to any reasonable limits, but simply be plotted one after the other.
I am generating plots like this one:
When using less ticks, the plot fits nicely and the bars are wide enough to see them correctly. Nevertheless, when there are lots of ticks, instead of making the plot larger, it just compress the y axe, resulting in thin bars and overlapping tick text.
This is happening both for plt.show() and plt.save_fig().
Is there any solution so it plots the figure in a scale which guarantees that bars have the specified width, not more (if too few ticks) and not less (too many, overlapping)?
EDIT:
Yes, I'm using barh, and yes, I'm setting height to a fixed value (8):
height = 8
ax.barh(yvalues-width/2, xvalues, height=height, color='blue', align='center')
ax.barh(yvalues+width/2, xvalues, height=height, color='red', align='center')
I don't quite understand your code, it seems you do two plots with the same (only shifted) yvalues, but the image doesn't look so. And are you sure you want to shift by width/2 if you have align=center? Anyways, to changing the image size:
No, I am not sure there is no other way, but I don't see anything in the manual at a glance. To set image size by hand:
fig = plt.figure(figsize=(5, 80))
ax = fig.add_subplot(111)
...your_code
the size is in cm. You can compute it beforehand, try for example
import numpy as np
fig_height = (max(yvalues) - min(yvalues)) / np.diff(yvalue)
this would (approximately) set the minimum distance between ticks to a centimeter, which is too much, but try to adjust it.
I think of two solutions for your case:
If you are trying to plot a histogram, use hist function [1]. This will automatically bin your data. You can even plot multiple overlapping histograms as long as you set alpha value lower than 1. See this post
import matplotlib.pyplot as plt
import numpy as np
x = mu + sigma*np.random.randn(10000)
plt.hist(x, 50, normed=1, facecolor='green',
alpha=0.75, orientation='horizontal')
You can also identify interval of your axis ticks. This will place a tick every 10 items. But I doubt this will solve your problem.
import matplotlib.ticker as ticker
...
ax.yaxis.set_major_locator(ticker.MultipleLocator(10))
I am trying to plot the following numbers on a log scale as a scatter plot in matplotlib. Both the quantities on the x and y axes have very different scales, and one of the variables has a huge dynamic range (nearly 0 to 12 million roughly) while the other is between nearly 0 and 2. I think it might be good to plot both on a log scale.
I tried the following, for a subset of the values of the two variables:
fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1)
ax.set_yscale('log')
ax.set_xscale('log')
plt.scatter([1.341, 0.1034, 0.6076, 1.4278, 0.0374],
[0.37, 0.12, 0.22, 0.4, 0.08])
The x-axes appear log scaled but the points do not appear -- only two points appear. Any idea how to fix this? Also, how can I make this log scale appear on a square axes, so that the correlation between the two variables can be interpreted from the scatter plot?
thanks.
I don't know why you only get those two points. For this case, you can manually adjust the limits to make sure all your points fit. I ran:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 8)) # You were missing the =
ax = fig.add_subplot(1, 1, 1)
ax.set_yscale('log')
ax.set_xscale('log')
plt.scatter([1.341, 0.1034, 0.6076, 1.4278, 0.0374],
[0.37, 0.12, 0.22, 0.4, 0.08])
plt.xlim(0.01, 10) # Fix the x limits to fit all the points
plt.show()
I'm not sure I understand understand what "Also, how can I make this log scale appear on a square axes, so that the correlation between the two variables can be interpreted from the scatter plot?" means. Perhaps someone else will understand, or maybe you can clarify?
You can also just do,
plt.loglog([1.341, 0.1034, 0.6076, 1.4278, 0.0374],
[0.37, 0.12, 0.22, 0.4, 0.08], 'o')
This produces the plot you want with properly scaled axes, though it doesn't have all the flexibility of a true scatter plot.