How to set the value of the axis multiplier in matplotlib? - python

I have to plot values in the range (0, 32000). When I do, I get the following tick labels:
0, 5000, 10000, 15000, 20000, 25000, 30000, 35000
but I would like to have the following:
0, 5, 10, 15, 20, 25, 30, 35
with the axis multiplier (that small number just below the tick labels) x 10^3. I really need x 10^3.
I know how to force matplotlib to use an axis multiplier. When I use the following:
fmt = ScalarFormatter()
fmt.set_powerlimits((-3, 3))
ax.xaxis.set_major_formatter(fmt)
or this:
pylab.ticklabel_format(axis='x', style='sci', scilimits=(-3, 3),
useOffset=False)
matplotlib always returns with the axis multiplier x 10^4, so I get these ugly tick labels:
0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5
You will agree that the multiplier x 10^3 results in a lot nicer tick labels. How do I set 10^3 instead of 10^4?
This question is similar but does not concern setting a concrete value for the axis multiplier.

From the available tickers, two options are:
EngFormatter()
FuncFormatter()
Using EngFormatter you get the SI prefixes, and optionally a unit by passing unit='Hz' for example.
More generally, you can define your own formatter
scale_factor = 10**3
fmt = mpl.ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x/scale_factor))
Edit:
You could also sub-class ScalarFormatter and override the order of magnitude determination, as in:
class MagnitudeFormatter(matplotlib.ticker.ScalarFormatter):
def __init__(self, exponent=None):
super().__init__()
self._fixed_exponent = exponent
def _set_order_of_magnitude(self):
if self._fixed_exponent:
self.orderOfMagnitude = self._fixed_exponent
else:
super()._set_order_of_magnitude()
Then using MagnitudeFormatter(3) as your formatter. This has the benefit in that it retains the "1e3" axis decoration.

This may not be the answer you are looking for, but you can specify a list of axis tick titles. For instance instead of plotting every tick from 1-10 you could make a list like ['1', '', '3', '', '5', '', '7', '', '9'] would only show a tick label on every other tick. This means so long as your domain you are plotting over doesn't change you can specify the exact strings you want displayed. If you would like I can post some code where I did this.

Related

Pyplot - show x-axis labels according to y-axis value

I have 1min 20s long video record of 23.813 FPS. More precisely, I have 1923 frames in which I've been scanning desired features. I've detected some specific behavior via neural network and using chosen metric I calculated a value for each frame.
So, now, I have X-Y values to plot a graph:
X: time (each step of size 0,041993869s)
Y: a value measured by neural network
In the default state, the plot looks like this:
So, I've tried to limit the number of bins in the faith that the bins will be spread over all my values. But they are not. As you can see, only first fifteen x-values are rendered:
pyplot.locator_params(axis='x', nbins=15)
But neither one is desired state. The desired state should render the labels of such x-bins with y-value higher than e.g. 1.2. So, it should look like this:
Is possible to achieve such result?
Code:
# draw plot
from pandas import read_csv
from matplotlib import pyplot
test_video_fps = 23.813
df = read_csv('/path/to/csv/file/file.csv', header=None)
df.columns = ['anomaly']
df['time'] = [round((i + 1) / test_video_fps, 2) for i in range(df.shape[0])]
axes = df.plot.bar(x='time', y='anomaly', rot='0')
# pyplot.locator_params(axis='x', nbins=15)
# axes.get_xaxis().set_visible(False)
fig = pyplot.gcf()
fig.set_size_inches(16, 10)
fig.savefig('/path/to/output/plot.png', dpi=100)
# pyplot.show()
Example:
Simple example with a subset of original data.
0.379799
0.383786
0.345488
0.433286
0.469474
0.431993
0.474253
0.418843
0.491070
0.447778
0.384890
0.410994
0.898229
1.872756
2.907009
3.691382
4.685749
4.599612
3.738768
8.043357
7.660785
2.311198
1.956096
2.877326
3.467511
3.896339
4.250552
6.485533
7.452986
7.103761
2.684189
2.516134
1.512196
1.435303
0.852047
0.842551
0.957888
0.983085
0.990608
1.046679
1.082040
1.119655
0.962391
1.263255
1.371034
1.652812
2.160451
2.646674
1.460051
1.163745
0.938030
0.862976
0.734119
0.567076
0.417270
Desired plot:
Your question has become a two-part problem, but it is interesting enough that I will answer both.
I will answer this in Matplotlib object oriented notation with numpy data rather than pandas. This will make things easier to explain, and can be easily generalized to pandas.
I will assume that you have the following two data arrays:
dt = 0.041993869
x = np.arange(0.0, 15 * dt, dt)
y = np.array([1., 1.1, 1.3, 7.6, 2.4, 0.8, 0.7, 0.8, 1.0, 1.5, 10.0, 4.5, 3.2, 0.9, 0.7])
Part 1: Identifying the locations where you want labels
The data can be masked to get the locations of the peaks:
mask = y > 1.2
Consecutive peaks can be easily eliminated by computing the diff. A diff of a boolean mask will be True at the locations where the mask changes sense. You will then have to take every other element to get the locations where it goes from False to True. The following code will capture all the corner cases where you start with a peak or end in the middle of a peak:
d = np.flatnonzero(np.diff(mask))
if mask[d[0]]: # First diff is end of peak: True to False
d = np.concatenate(([0], d[1::2] + 1))
else:
d = d[::2] + 1
d is now an array indices into x and y that represent the first element of each run of peaks. You can get the last element by swapping the indices [1::2] and [::2] in the if-else statement, and removing the + 1 in both cases.
The locations of the labels are now simply x[d].
Part 2: Locating and formatting the labels
For this part, you will need to access Matplotlib's object oriented API via the Axes object you are plotting on. You already have this in the pandas form, making the transfer easy. Here is a sample in raw Matplotlib:
fig, axes = plt.subplots()
axes.plot(x, y)
Now use the ticker API to easily set the locations and labels. You actually set the locations directly (not with a Locator) since you have a very fixed list of ticks:
axes.set_xticks(x[d])
axes.xaxis.set_major_formatter(ticker.StrMethodFormatter('{x:0.01g}s'))
For the sample data show here, you get

How to plot x axis with month?

I want to plot a dataframe df1. The x axis contains month and the y-axis counts. My x axis is just a black bar because of too many values. I tried a lot but nothing works. Is there a simple way to plot just every 5th date for example?
I think the problem is that the month are date times and I can't build the minimum and maximum?

df1 = pd.read_csv('hello.csv')
plt.plot(df1['a'],df1['b'])
plt.show()
My data frame df1 is:
a b
2006-06,211.0
2006-07,212.41176470588235
2006-08,238.26315789473685
2006-09,239.9375
2006-10,266.1111111111111
2006-11,265.22222222222223
2006-12,283.3333333333333
2007-01,290.0
2007-02,307.5
2007-03,325.0
2007-04,343.05882352941177
2007-05,340.42105263157896
2007-06,353.75
2007-07,348.5
2007-08,359.6111111111111
2007-09,346.5625
2007-10,365.57894736842104
2007-11,358.7647058823529
2007-12,372.8333333333333
2008-01,381.8888888888889
2008-02,396.25
2008-03,422.94117647058823
2008-04,428.6666666666667
2008-05,418.5882352941176
2008-06,433.0
2008-07,440.4736842105263
2008-08,470.375
2008-09,481.3529411764706
2008-10,489.44444444444446
2008-11,485.125
2008-12,514.5714285714286
2009-01,515.375
2009-02,535.3125
2009-03,555.0555555555555
2009-04,557.7222222222222
2009-05,533.375
2009-06,567.7222222222222
2009-07,575.1111111111111
2009-08,582.5294117647059
2009-09,569.1666666666666
2009-10,611.1176470588235
2009-11,591.6470588235294
2009-12,634.6428571428571
2010-01,647.9375
2010-02,655.375
2010-03,672.7368421052631
2010-04,678.5882352941177
2010-05,667.8235294117648
2010-06,689.5
2010-07,657.4117647058823
2010-08,679.1111111111111
2010-09,661.2222222222222
2010-10,685.75
2010-11,676.5555555555555
2010-12,692.3571428571429
2011-01,691.9411764705883
2011-02,697.4375
2011-03,720.5263157894736
2011-04,723.5
2011-05,694.7222222222222
2011-06,705.7222222222222
2011-07,677.9375
2011-08,693.7368421052631
2011-09,671.2352941176471
2011-10,685.1176470588235
2011-11,669.9444444444445
2011-12,708.3076923076923
2012-01,674.9444444444445
2012-04,748.0
2012-05,811.0526315789474
2012-06,863.6875
2012-07,843.1666666666666
2012-08,885.5
2012-09,857.75
2012-10,876.8421052631579
2012-11,863.1764705882352
2012-12,917.6666666666666
2013-01,933.4444444444445
2013-03,975.0625
2013-04,994.0
2013-05,1019.6666666666666
2013-06,1063.625
2013-07,1057.8947368421052
2013-08,1102.1764705882354
2013-09,1046.4117647058824
2013-10,1153.1052631578948
2013-11,1107.25
2013-12,1155.3076923076924
2014-01,1191.3529411764705
2014-02,1240.5
2014-03,1272.764705882353
2014-04,1316.9444444444443
2014-05,1310.3529411764705
2014-06,1349.4117647058824
2014-07,1403.8947368421052
2014-08,1412.375
2014-09,1409.0555555555557
2014-10,1472.9444444444443
2014-11,1421.8125
2014-12,1473.2142857142858
2015-01,1476.9375
2015-02,1495.75
2015-03,1546.111111111111
2015-04,1563.7777777777778
2015-05,1499.0
2015-06,1583.111111111111
2015-07,1594.2222222222222
2015-08,1618.1176470588234
2015-09,1595.8333333333333
2015-10,1706.3529411764705
2015-11,1652.8823529411766
2015-12,1691.0714285714287
2016-01,1717.125
2016-02,1746.7058823529412
2016-03,1945.4736842105262
2016-04,2329.375
2016-05,2408.4444444444443
2016-06,2404.222222222222
2016-07,2184.4375
2016-08,2160.6315789473683
2016-09,2402.176470588235
2016-10,2481.823529411765
2016-11,2372.0
2016-12,2153.0
2017-01,2145.777777777778
2017-02,2213.5625
2017-03,2309.6111111111113
2017-04,2295.8125
2017-05,2116.7894736842104
2017-06,2093.8823529411766
In order to show every nth value, what you can do is to set the x-ticks value.
x = df1['a']
plt.xticks(np.arange(0, len(x), 1.0)) #you can replace 1 with the step interval
Or else, what you can do to further improve the visibility and keep the accuracy is to rotate the x axis inputs by modifying the x-ticks with a rotation variable.
import matplotlib.pyplot as plt
x = [1, 2, 3, 4]
y = [1, 4, 9, 6]
labels = ['Frogs', 'Hogs', 'Bogs', 'Slogs']
plt.plot(x, y)
# You can specify a rotation for the tick labels in degrees or with keywords.
plt.xticks(x, labels, rotation='vertical') # You can input an integer too.
# Pad margins so that markers don't get clipped by the axes
plt.margins(0.2)
# Tweak spacing to prevent clipping of tick-labels
plt.subplots_adjust(bottom=0.15)
plt.show()

Python matplotlib - setting x-axis scale

I have this graph displaying the following:
plt.plot(valueX, scoreList)
plt.xlabel("Score number") # Text for X-Axis
plt.ylabel("Score") # Text for Y-Axis
plt.title("Scores for the topic "+progressDisplay.topicName)
plt.show()
valueX = [1, 2, 3, 4] and
scoreList = [5, 0, 0, 2]
I want the scale to go up in 1's, no matter what values are in 'scoreList'. Currently get my x-axis going up in .5 instead of 1s.
How do I set it so it goes up only in 1?
Just set the xticks yourself.
plt.xticks([1,2,3,4])
or
plt.xticks(valueX)
Since the range functions happens to work with integers you could use that instead:
plt.xticks(range(1, 5))
Or be even more dynamic and calculate it from the data:
plt.xticks(range(min(valueX), max(valueX)+1))
Below is my favorite way to set the scale of axes:
plt.xlim(-0.02, 0.05)
plt.ylim(-0.04, 0.04)
Hey it looks like you need to set the x axis scale.
Try
matplotlib.axes.Axes.set_xscale(1, 'linear')
Here's the documentation for that function

Pyplot set tick frequency and tick labels

I'm trying to make a plot with matplotlib where I want to specify both the position of the tick marks, and the text of the tick marks. I can individually do both with yticks(np.arange(0,1.1,1/16.)) and gca().set_yticklabels(['1','2','3']). However, for some reason when I do both of them together, the labels do not appear on the graph. Is there a reason for this? How can I get around it? Below is a working example of what I want to accomplish.
x = [-1, -0.2, -0.15, 0.15, 0.2, 7.8, 7.85, 8.15, 8.2, 12]
y = [1, 1, 15/16., 15/16., 1, 1, 15/16., 15/16., 1, 1]
figure(1)
plot(x,y)
xlabel('Time (years)')
ylabel('Brightness')
yticks(np.arange(0,1.1,1/16.))
xticks(np.arange(0,13,2))
ylim(12/16.,16.5/16.)
xlim(-1,12)
gca().set_yticklabels(['12/16', '13/16', '14/16', '15/16', '16/16'])
show(block = False)
Effectively I just wanted to replace the numerical values with fractions, but when I run this, the labels do not appear. It seems that using both yticks() and set_yticklabels together is a problem because if I remove either line, the remaining line works as it should.
If anyone can indicate how to simply force the label to be a fraction, that would also solve my problem.
EDIT:
I found an ugly workaround by using
ylim(12/16., 16.5/16)
gca().yaxis.set_major_locator(FixedLocator([12/16., 13/16., 14/16., 15/16., 16/16.]))
gca().yaxis.set_major_formatter(FixedFormatter(['12/16', '13/16', '14/16', '15/16', '16/16']))
While this may work for this specific example, it does not generalize well and it is cumbersome to specify the exact location and label of every tick mark. If anyone finds another solution, I'm all ears.
1) Your arange should produce 5 ticks, the same as labels you set.
arange is not good for that. It is better to use linspace.
2) You can set ticks and labels with the same function
plot(x,y)
xlabel('Time (years)')
ylabel('Brightness')
yticks(np.linspace(12/16., 1, 5), ('12/16', '13/16', '14/16', '15/16', '16/16') )
xticks(np.arange(0,13,2))
ylim(12/16.,16.5/16.)
xlim(-1,12)
3) Note that you should adjust the actual values of the axis with the position of the labels using linspace(12/16., 1, 5) instead of arange(0, 1.1, 1/16.))

How can I force pyplot to show axis limits

My x and y axis normally range from 0 to 300 and 0 to 60, respectively.
I want to show only values from 5 <= x <= 300, however, so I do
ax.set_xlim(left=5)
after which the graph does indeed start at 5, but there is nothing to indicate that. My first tick on the x-axis is at 50, and then 100, 150... the y-axis has ticks labeled 0, 20, 40, 60, which will easily mislead the viewer into thinking that the lower limit of 0 for the y-axis also represents the lower limit of 0 for the x-axis.
How can I force pyplot to display an extra tick at x=5 so that the viewer is told explicitly that both axes do not have the same lower bound of 0?
You can use xticks to set the ticks of the x axis.
This is an ipython session:
In [18]: l = [random.randint(0, 10) for i in range(300)]
In [19]: plot(l)
Out[19]: [<matplotlib.lines.Line2D at 0x9241f60>]
In [20]: plt.xlim(xmin=5) # I set to start at 5. No label is draw
Out[20]: (5, 300.0)
In [21]: plt.xticks(arange(5, 301, 50)) # this makes the first xtick at left to be 5
# note the max range is 301, otherwise you will never
# get 300 even if you set the appropriate step
Note that now, at the right side of the xaxis, there is no label. Last label is 255 (the same problem you had at the left side). You can get this label modifying the step of the arange in order to max - min / step to be (or be very close to) an integer value (the number of ticks).
This makes it (although the decimal numbers are ugly):
In [38]: plt.xticks(arange(5, 301, 29.5))

Categories

Resources