matplotlib: fail to plot line or bar; valid axes - python

I'm attempting generate matplotlib images through a loop. I have two iterations of loops that generate images. The first loop works, the second doesn't. The axes are valid, I can see that when I print the numpy arrays.
plt_mean = float(week_occurrences) / len(x_axis)
y_np = np.array(y_axis)
std_d = np.std(y_np)
plt.plot(x_axis, y_np, color='#758AA8')
plt.axis([y_axis[0], y_axis[6], 0, int(y_max * 1.2)])
plt.axhline(plt_mean, color='black')
plt.ylabel("Events")
plt.xlabel("Day")
plt.title(event)
plt.savefig("tmp/{} {}.jpg".format(event, y_axis[0]), bbox_inches='tight')
plt.clf()
print(event)
print(y_max)
print(plt_mean)
print(x_axis)
raw_input(y_np)
output:
A user account was changed.
384
111.571428571
[5, 22, 4, 384, 363, 3, 0]
[166 167 168 169 170 171 172]
What am I missing? Why won't it plot the associated lines?

I believe the line is plotted, but I think your axis limits are wrong. I'm not entirely sure what you're trying to do, because it looks like you've inverted your x and y.
here is the result after the line:
plt.plot(x_axis, y_np, color='#758AA8')
However, after the line
plt.axis([y_axis[0], y_axis[6], 0, int(y_max * 1.2)])
the axes limit do not make any sense anymore and you're seeing a region where there are no data.
plt.axis() takes its argument in the order [xmin, xmax, ymin, ymax]

Looks like you didn't define y_max correctly. This works for me:
import numpy as np
import matplotlib.pylab as plt
x_axis = [5, 22, 4, 384, 363, 3, 0]
y_axis = [166, 167, 168, 169, 170, 171, 172]
y_max = np.max(y_axis)
event = np.str('A user account was changed.')
week_occurrences = 780.999999997
plt_mean = float(week_occurrences) / len(x_axis)
y_np = np.array(y_axis)
std_d = np.std(y_np)
plt.plot(x_axis, y_np, color='#758AA8')
plt.axis([y_axis[0], y_axis[6], 0, int(y_max * 1.2)])
plt.axhline(plt_mean, color='black')
plt.ylabel("Events")
plt.xlabel("Day")
plt.title(event)
# plt.savefig("tmp/{} {}.jpg".format(event, y_axis[0]), bbox_inches='tight')
# plt.clf()
print(event)
print(y_max)
print(plt_mean)
print(x_axis)

Related

Python curve for a lot points

I'm using Python and matplotlib.
I have a lot of Points, generated with arrays.
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=Groesse_cm/2.54)
ax.set_title(title)
ax.set_xlabel(xlabel) # Beschriftung X-Achse
ax.set_ylabel(ylabel) # Beschriftung Y-Achse
ax.plot(xWerte, yWerte, 'ro', label=kurveName)
ax.plot(xWerte, y2Werte, 'bo', label=kurveName2)
plt.show()
So I have the arrayX for x Values and the arrayYmax for Y Values (red) and arrayYmin for Y Values (blue). I can't give you my arrays, couse that is much too complicated.
My question is:
How can I get a spline/fit like in the upper picture? I do not know the function of my fited points, so I have just Points with [x / y] Values. So i don't wann connect the points i wanna have a fit. So yeah I say fit to this :D
Here is an example i don't wanna have:
The code for this is:
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=Groesse_cm/2.54)
degree = 7
np.poly1d(np.polyfit(arrayX,arrayYmax,degree))
ax.plot(arrayX, arrayYmax, 'r')
np.poly1d(np.polyfit(arrayX,arrayYmin,degree))
ax.plot(arrayX, arrayYmin, 'b')
#Punkte
ax.plot(arrayX, arrayYmin, 'bo')
ax.plot(arrayX, arrayYmax, 'ro')
plt.show()
you're pretty close, you just need to use the polynomial model you're estimating/fitting.
start with pulling in packages and defining your data:
import numpy as np
import matplotlib.pyplot as plt
arr_x = [-0.8, 2.2, 5.2, 8.2, 11.2, 14.2, 17.2]
arr_y_min = [65, 165, 198, 183, 202, 175, 97]
arr_y_max = [618, 620, 545, 626, 557, 626, 555]
then we estimate the polynomial fit, as you were doing, but saving the result into a variable that we can use later:
poly_min = np.poly1d(np.polyfit(arr_x, arr_y_min, 2))
poly_max = np.poly1d(np.polyfit(arr_x, arr_y_max, 1))
next we plot the data:
plt.plot(arr_x, arr_y_min, 'bo:')
plt.plot(arr_x, arr_y_max, 'ro:')
next we use the polynomial fit from above to plot estimated value at a set of sampled points:
poly_x = np.linspace(-1, 18, 101)
plt.plot(poly_x, poly_min(poly_x), 'b')
plt.plot(poly_x, poly_max(poly_x), 'r')
giving us:
note that I'm using much lower degree polynomials (1 and 2) than you (7). a seven degree polynomial is certainly overfitting this small amount of data, and these look like a reasonable fits

Matplotlib 3D scatter giving confusing error message

I want to set the color of different scatters and here comes the error, as is shown in the following code:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
points = np.array([[1,2,3]])
labels = np.array([1])
colors = [[255, 0, 0],[0, 255, 0],[0, 0, 255], [255, 255, 0],[255, 0, 255],[0,255,255],[128,255,128]]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for i in range(0,len(points)):
print('point and label')
print(points[i], labels[i])
color = colors[labels[i]-1]
print([0,0,0])
ax.scatter(points[i,0], points[i,1],zs=points[i,2],c=[0,0,0]) # work
print(color)
ax.scatter(points[i,0], points[i,1],zs=points[i,2],c=color) # error
print('finish')
plt.savefig('a.jpg',format='jpg')
The problem is that, if I set the c of the ax.scatter as [0,0,0], it works. However, if I set it to a list chosen from the colors I defined, it reports errors.
The complete print message is shown as follows (including the error message):
point and label
(array([1, 2, 3]), 1)
[0, 0, 0]
[255, 0, 0]
Traceback (most recent call last):
File "plot.py", line 47, in <module>
ax.scatter(points[i,0], points[i,1],zs=points[i,2],c=color) # error
File "mypath/local/lib/python2.7/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 2362, in scatter
xs, ys, s=s, c=c, *args, **kwargs)
File "mypath/local/lib/python2.7/site-packages/matplotlib/__init__.py", line 1867, in inner
return func(ax, *args, **kwargs)
File "mypath/local/lib/python2.7/site-packages/matplotlib/axes/_axes.py", line 4293, in scatter
.format(c.shape, x.size, y.size))
AttributeError: 'list' object has no attribute 'shape'
What's wrong with my code and how to set the color of 3D scatter?
Thank you!
I cannot reproduce your error using matplotlib 3.0.1. However, here are a few suggestions.
First, matplotlib expects RGB[A] values to be in the range 0–1 and not 0–255
Second, do you really need to process your points in a loop? Your code could be simplified to a one line call to scatter:
points = np.random.random(size=(7,3))
colors = np.array([[1, 0, 0],[0, 1, 0],[0, 0, 1], [1, 1, 0],[1, 0, 1],[0,1,1],[0.5,1,0.5]])
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(points[:,0], points[:,1], zs=points[:,2], c=colors, s=100)
Third, if you have to pass points one at a time, you should have received a warning like:
'c' argument looks like a single numeric RGB or RGBA sequence, which
should be avoided as value-mapping will have precedence in case its
length matches with 'x' & 'y'. Please use a 2-D array with a single
row if you really want to specify the same RGB or RGBA value for all
points.
As it clearly states, when passing a single color, you should still use a 2D array to specify the color, i.e. ax.scatter(x,y,zs=z,c=[[0,0,0]])

scatter update with animation

I am trying to do a real time scatter-kind plot using matplotlib's animation module but I'm quite a newbie with it. My objective is to update the plot whenever I receive the data I want to plot, so that any time data is received, previous points disappear and the new ones are plotted.
My program can be written like this if I substitute the data receiving with a endless loop and a random generation of data:
fig = plt.figure()
skyplot = fig.add_subplot(111, projection='polar')
skyplot.set_ylim(90) # sets radius of the circle to maximum elevation
skyplot.set_theta_zero_location("N") # sets 0(deg) to North
skyplot.set_theta_direction(-1) # sets plot clockwise
skyplot.set_yticks(range(0, 90, 30)) # sets 3 concentric circles
skyplot.set_yticklabels(map(str, range(90, 0, -30))) # reverse labels
plt.ion()
while(1):
azimuths = random.sample(range(360), 8)
elevations = random.sample(range(90), 8)
colors = numpy.random.rand(3,1)
sat_plot = satellite()
ani= animation.FuncAnimation(fig, sat_plot.update, azimuths, elevations, colors)
class satellite:
def __init__(self):
self.azimuths = []
self.elevations = []
self.colors = []
self.scatter = plt.scatter(self.azimuths, self.elevations, self.colors)
def update(self, azimuth, elevation, colors):
self.azimuths = azimuth
self.elevations = elevation
return self.scatter
Right now, I'm getting the following error:
> Traceback (most recent call last):
File "./skyplot.py", line 138, in <module>
ani= animation.FuncAnimation(fig, sat_plot.update, azimuths, elevations, colors)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 442, in __init__
TimedAnimation.__init__(self, fig, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 304, in __init__
Animation.__init__(self, fig, event_source=event_source, *args, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 53, in __init__
self._init_draw()
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 469, in _init_draw
self._drawn_artists = self._init_func()
TypeError: 'list' object is not callable
Can anyone tell me what I'm doing wrong and how could I do this?
Thanks in advance
I think you do not need an animation. You need a simple endless loop (while for example) with plot update in a thread. I can propose something like this:
import threading,time
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
data = np.random.uniform(0, 1, (5, 3))
plt.scatter(data[:, 0], data[:,1],data[:, 2]*50)
def getDataAndUpdate():
while True:
"""update data and redraw function"""
new_data = np.random.uniform(0, 1, (5, 3))
time.sleep(1)
plt.clf()
plt.scatter(new_data[:, 0], new_data[:, 1], new_data[:, 2] * 50)
plt.draw()
t = threading.Thread(target=getDataAndUpdate)
t.start()
plt.show()
The result is an animated-like figure with scatterplot.

Connect different data series with the same line

Is there a way to get matplotlib to connect data from two different data sets with the same line?
Context: I need to plot some data in log scale, but some of them are negative. I use the workaround of plotting the data absolute value in different colours (red for positive and green for negative), something like:
import pylab as pl
pl.plot( x, positive_ys, 'r-' ) # positive y's
pl.plot( x, abs( negative_ys ), 'g-' ) # negative y's
pl.show()
However, as they represent the same quantity, it would be helpful to have the two data series connected by the same line. Is this possible?
I cannot use pl.plot( x, abs( ys )) because I need to be able to differentiate between the positive and originally negative values.
With numpy you can use logical indexing.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
x = np.array([10000, 1000, 100, 10, 1, 5, 50, 500, 5000, 50000])
y = np.array([-10000, -1000, -100, -10, -1, 5, 50, 500, 5000, 50000])
ax.plot(x,abs(y),'+-b',label='all data')
ax.plot(abs(x[y<= 0]),abs(y[y<= 0]),'o',markerfacecolor='none',
markeredgecolor='r',
label='we are negative')
ax.set_xscale('log')
ax.set_yscale('log')
ax.legend(loc=0)
plt.show()
The key feature is first plotting all absolute y-values and then re-plotting those that were originally negative as hollow circles to single them out. This second step uses the logical indexing x[y<=0] and y[y<=0] to only pick those elements of the y-array which are negative.
The example above gives you this figure:
If you really have two different data sets, the following code will give you the same figure as above:
x1 = np.array([1, 10, 100, 1000, 10000])
x2 = np.array([5, 50, 500, 5000, 50000])
y1 = np.array([-1, -10, -100, -1000, -10000])
y2 = np.array([5, 50, 500, 5000, 50000])
x = np.concatenate((x1,x2))
y = np.concatenate((y1,y2))
sorted = np.argsort(y)
ax.plot(x[sorted],abs(y[sorted]),'+-b',label='all data')
ax.plot(abs(x[y<= 0]),abs(y[y<= 0]),'o',markerfacecolor='none',
markeredgecolor='r',
label='we are negative')
Here, you first use np.concatenate to combine both the x- and the y-arrays. Then you employ np.argsort to sort the y-array in a way that makes sure you do not get a overly zig-zaggy line when plotting. You use that index-array (sorted) when you call the first plot. As the second plot only plots symbols but no connecting line, you do not require sorted arrays here.

plotting/marking seleted points from a 1D array

this seems a simple question but I have tried it for a really long time.
I got a 1d array data(named 'hightemp_unlocked', after I found the peaks(an array of location where the peaks are located) of it, I wanted to mark the peaks on the plot.
import matplotlib
from matplotlib import pyplot as plt
.......
plt.plot([x for x in range(len(hightemp_unlocked))],hightemp_unlocked,label='200 mk db ramp')
plt.scatter(peaks, hightemp_unlocked[x in peaks], marker='x', color='y', s=40)
for some reason, it keeps telling me that x, y must be the same size
it shows:
File "period.py", line 86, in <module>
plt.scatter(peaks, hightemp_unlocked[x in peaks], marker='x', color='y', s=40)
File "/usr/local/lib/python2.6/dist-packages/matplotlib/pyplot.py", line 2548, in scatter
ret = ax.scatter(x, y, s, c, marker, cmap, norm, vmin, vmax, alpha, linewidths, faceted, verts, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/matplotlib/axes.py", line 5738, in scatter
raise ValueError("x and y must be the same size")
I don't think hightemp_unlocked[x in peaks] is what you want. Here x in peaks reads as the conditional statement "is x in peaks?" and will return True or False depending on what was last stored in x. When parsing hightemp_unlocked[x in peaks], True or False is interpreted as 0 or 1, which returns only the first or second element of hightemp_unlocked. This explains the array size error.
If peaks is an array of indexes, then simply hightemp_unlocked[peaks] will return the corresponding values.
You are almost on the right track, but hightemp_unlocked[x in peaks] is not what you are looking for. How about something like:
from matplotlib import pyplot as plt
# dummy temperatures
temps = [10, 11, 14, 12, 10, 8, 5, 7, 10, 12, 15, 13, 12, 11, 10]
# list of x-values for plotting
xvals = list(range(len(temps)))
# say our peaks are at indices 2 and 10 (temps of 14 and 15)
peak_idx = [2, 10]
# make a new list of just the peak temp values
peak_temps = [temps[i] for i in peak_idx]
# repeat for x-values
peak_xvals = [xvals[i] for i in peak_idx]
# now we can plot the temps
plt.plot(xvals, temps)
# and add the scatter points for the peak values
plt.scatter(peak_xvals, peak_temps)

Categories