axes=plt.subplot(111)
axes.invert_xaxis() # not inverted
ts.plot(ax=axes)
# axes.invert_xaxis() # inverted
plt.show()
Why can not it invert the axis before calling pandas.Series.plot, but it can do it after calling? since my program is complicated, the figure is embedded in tkinter, lines on the axes are drawn via pressing buttons, so to invert the axis before calling plot is optimal. What is convenient for it?
I just did some research on matplotlib.plot
when you first define axes and reverse x-axis, it did reverse the x-axis.
axes=plt.subplot(111)
print(axes.get_xlim())
# (0.0, 1.0)
axes.invert_xaxis()
print(axes.get_xlim())
# (1.0, 0.0)
But when you call ts.plot(ax=axes), the function overwrites the x_axis value in object axes with new ts's axis value:
ts = pd.DataFrame([1,2,3])
ts.plot(ax=axes)
print(axes.get_xlim())
#(0.0, 2.0)
what you have done to axes before have been overwritten.
It just likes the example below:
x = [1,2,3]
x[0] = 4
print(x)
#[4, 2, 3]
def func(l):
l[0] = 1
func(x)
print(x)
#[1, 2, 3]
you did do some change on the list, but the func also did the some changes on the list and covered your changes.
Related
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
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()
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
I'm trying to annotate points plotted with the points3d() function using mayavi.mlab.
Each point is associated with a label which I would like to plot next to the points using the text3d() function. Plotting the points is fast, however the mlab.text3d() function does not seem to accept arrays of coordinates, so I have to loop over the points and plot the text individually, which is very slow:
for i in xrange(0, self.n_labels):
self.mlab_data.append(
mlab.points3d( pX[self.labels == self.u_labels[i], 0],
pX[self.labels == self.u_labels[i], 1],
pX[self.labels == self.u_labels[i], 2],
color=self.colours[i],
opacity=1,
scale_mode="none",
scale_factor=sf ) )
idcs, = np.where(self.labels == self.u_labels[i])
for n in idcs.flatten():
mlab.text3d( pX[n, 0],
pX[n, 1],
pX[n, 2],
"%d" % self.u_labels[i],
color=self.colours[i],
opacity=1,
scale=sf )
Any ideas how I could speed this up? Also, is it possible to add a legend (as for instance in matplotlib), I couldn't find anything in the docs.
Thanks,
Patrick
The way you are doing it above will render the scene every time you plot a point or text. This is slow. You can disable the scene rendering, do the plotting and then render the scene by figure.scene.disable_render = True/False:
import scipy
from mayavi import mlab
X = 100 * scipy.rand(100, 3)
figure = mlab.figure('myfig')
figure.scene.disable_render = True # Super duper trick
mlab.points3d(X[:,0], X[:,1], X[:,2], scale_factor=0.4)
for i, x in enumerate(X):
mlab.text3d(x[0], x[1], x[2], str(i), scale=(2, 2, 2))
figure.scene.disable_render = False # Super duper trick
I use this trick and others in Figure class in morphic Viewer https://github.com/duanemalcolm/morphic/blob/master/morphic/viewer.py
Another good trick in the code is to reuse existing objects, i.e., if you've plotted the text already, don't replot them, just update their position and text attributes. This means saving the mlab object. You can see how I do this in morphic.Viewer.
I'm searching for a way to extract all text elements from a matplotlibfigure including their position, style, alignment etc. Calling the findobj(matplotlib.text.Text) method of a figure does that job exactly. However, I get some weird duplicates for all the tick labels and I don't know how to handle them.
For example, use findobj for printing all Text elements of an axis:
import matplotlib
import pylab as p
p.plot([1,2,3])
p.xticks([1],["tick"])
ax = p.gca()
fig = p.gcf()
p.draw()
def print_texts(artist):
for t in artist.findobj(matplotlib.text.Text):
if t.get_visible() and t.get_text():
print " %r # %s" % (t.get_text(), t.get_position())
print "X-Axis Text Elements:"
print_texts(ax.xaxis)
print "Y-Axis Text Elements:"
print_texts(ax.yaxis)
Result:
X-Axis Text Elements:
'tick' # (1.0, 0.0)
'tick' # (0.0, 1.0)
Y-Axis Text Elements:
u'1.0' # (0.0, 1.0)
u'1.0' # (1.0, 0.0)
u'1.5' # (0.0, 1.5)
u'1.5' # (1.0, 0.0)
u'2.0' # (0.0, 2.0)
u'2.0' # (1.0, 0.0)
u'2.5' # (0.0, 2.5)
u'2.5' # (1.0, 0.0)
u'3.0' # (0.0, 3.0)
u'3.0' # (1.0, 0.0)
Note that all tick labels have duplicates positioned at the end of the axis. Why? How to filter them out from a list of Text elements? Their get_visible() attribute is True.
Another thing is that I first have to do call draw() in order to update/generate the ticks. How do I force an update of the tick labels? matplotlib.colorbar.Colorbar seems to have a update_ticks() method, but I can't find something similar for ticks on the axes.
I also tried writing a custum backend and fetch all the texts from the draw_text()
method of the renderer. In contrast to the documentation draw_text() does
not receive a matplotlib.text.Text instance with all the necessary
information but only a simple string and a pre-layouted position.
The answer to this problem was given in the matplotlib mailing list. The Tick object always creates two text labels, one for the left/bottom and one for the right/top. When a Tick artist is drawn its label1On and label2On attributes define which of the two child text labels receive the draw() call. Both of them remain in the visible state however.
So before iterating through all the text elements of a figure, I hide those labels that are not supposed to be seen:
for tick in fig.findobj(matplotlib.axis.Tick):
tick.label1.set_visible(tick.label1On)
tick.label2.set_visible(tick.label2On)
for text in fig.findobj(match=Text, include_self=False):
s = text.get_text()
if not s or not text.get_visible(): continue
# do something with the texts