I'm attempting to compile 12 boxplots on a single set of axes using a loop. However, when I run the code as show below, I end up with 12 different figures. Can anyone provide input on how to make sure they all stay on one figure?
import numpy as np
import matplotlib.pyplot as plt
mons =['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
for i in range(len(mons)):
data = np.genfromtxt('Z:/Dan/SnowStatData/Errors/'+mons[i]+'ErrorStats.txt',skip_header=4)
lat = data[:,1]
lon = data[:,2]
corr = data[:,3]
corp = data[:,4]
RMSE = data[:,5]
MAE = data[:,6]
SDE = data[:,7]
sigcorrs = []
clat = []
clon = []
for j in range(len(lat)):
if corp[j] < 0.05:
sigcorrs = np.append(sigcorrs,corr[j])
clat = np.append(clat,lat[j])
clon = np.append(clon,lon[j])
else:
continue
plt.boxplot(sigcorrs,positions=[i])
plt.show()
The trick is to create the figure before you start looping:
fig = plt.figure()
ax = plt.subplot(111)
Now, in the loop don't use plt.boxplot which might create a new figure, but call the function directly from the axes object:
ax.boxplot(sigcorrs,positions=[i])
And then call plt.show() after the loop
It looks like you're calling plt.show() every time through the loop, so it's drawing the figure every time. Try putting it after the loop.
Related
I am designing a currency converter app and I had an idea to add graphical currency analysis to it.
for this I've started using matplotlib.pyplot . I am taking from date(i.e. date from which graph compares data ) as input from user.And using this data , i am taking real time currency data from certain sources.
But here came the main issue.When i drew the graph the x - axis is really bad😫.
Ill insert the output i am getting--> graph and a rough code of mine.The main isuue i want to eliminate is that i want only certain parts of x-axis visible.
import matplotlib.pyplot as plt
import requests
x = []
y = []
for i in range(fyear,tyear):
for j in range(fmonth,tmonth):
for k in range(fday,tday):
response = requests.get("https://api.ratesapi.io/api/{}-{}-{}?base={}&symbols{}".format(i,j,k,inp_curr,out_curr))
data = response.json()
rate = data['rates'][out_curr]
y.append(rate)
x.append("{}/{}/{}".format(j,i,k))
plt.plot(x,y)
OBTAINED OUTPUT:
enter image description here
need answer quickly.....
If for parts you mean to set only few labels along x axis you could use xticks and locator_params. See docs here: https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.xticks.html
import matplotlib.pyplot as plt
import numpy as np
import requests
# use some fake data for testing - use your params
fyear = 2019
tyear = 2020
fmonth = 1
tmonth = 13
fday=1
tday=28
inp_curr = "EUR"
out_curr = "GBP"
# init lists
x = []
y = []
for i in range(fyear,tyear):
for j in range(fmonth,tmonth):
for k in range(fday,tday):
response = requests.get("https://api.ratesapi.io/api/{}-{}-{}?base={}&symbols{}".format(i,j,k,inp_curr,out_curr))
data = response.json()
rate = data['rates'][out_curr]
y.append(rate)
x.append("{}/{}/{}".format(j,i,k))
# create subplot
fig, ax = plt.subplots(1,1, figsize=(20, 11))
# plot image
img = ax.plot(x, y)
# set the total number of x_ticks (the ticks on the x label)
ax.set_xticks(np.arange(len(x)))
# set the labels for each x_tick (actually is x list)
ax.set_xticklabels(x)
# set the number of ticks you want to visualize
# you can just select a number i.e. 10 and you will visualize onlu 10 ticks
# in order to visualize, say the first day of each month set this
n = round(len(x)/(tday-fday))
plt.locator_params(axis='x', nbins=n)
# change labels position to oblique
ax.get_figure().autofmt_xdate()
fig.tight_layout()
Remember to import numpy! Hope it helps you. Here you can see my output.
I'm making a program which takes a random list of data and will plot it.
I want the colour of the graph to change if it goes above a certain value.
https://matplotlib.org/gallery/lines_bars_and_markers/multicolored_line.html
Matplotlib has an entry on doing just this but it seems to require using a function as input for the graph not using lists.
Does anyone know how to either convert this to work for lists or another way of doing so?
Here's my code so far (without my horrific failed attempts to colour code them)
from matplotlib import pyplot as plt
import random
import sys
import numpy as np
#setting the max and min values where I want the colour to change
A_min = 2
B_max = 28
#makes lists for later
A_min_lin = []
B_max_lin = []
#simulating a corruption of the data where it returns all zeros
sim_crpt = random.randint(0,10)
print(sim_crpt)
randomy = []
if sim_crpt == 0:
randomy = []
#making the empty lists for corrupted data
for i in range(0,20):
randomy.append(0)
print(randomy)
else:
#making a random set of values for the y axis
for i in range(0,20):
n = random.randint(0,30)
randomy.append(n)
print(randomy)
#making an x axis for time
time = t = np.arange(0, 20, 1)
#Making a list to plot a straight line showing where the maximum and minimum values
for i in range(0, len(time)):
A_min_lin.append(A_min)
B_max_lin.append(B_max)
#Testing to see if more than 5 y values are zero to return if it's corrupted
tracker = 0
for i in (randomy):
if i == 0:
tracker += 1
if tracker > 5:
sys.exit("Error, no data")
#ploting and showing the different graphs
plt.plot(time,randomy)
plt.plot(time,A_min_lin)
plt.plot(time,B_max_lin)
plt.legend(['Data', 'Minimum for linear', "Maximum for linear"])
plt.show
You can use np.interp to generate the fine-grain data to plot:
# fine grain time
new_time = np.linspace(time.min(), time.max(), 1000)
# interpolate the y values
new_randomy = np.interp(new_time, time, randomy)
# this is copied from the link with few modification
points = np.array([new_time, new_randomy]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
fig, axs = plt.subplots()
norm = plt.Normalize(new_randomy.min(), new_randomy.max())
lc = LineCollection(segments, cmap='viridis', norm=norm)
# Set the values used for colormapping
lc.set_array(new_randomy[1:])
lc.set_linewidth(2)
line = axs.add_collection(lc)
fig.colorbar(line, ax=axs)
# set the limits
axs.set_xlim(new_time.min(), new_time.max())
axs.set_ylim(new_randomy.min(), new_randomy.max())
plt.show()
Output:
I want to make a real time plot of temeperature vs. iteration but I will end up having so many points that it would not make sense to have them on the same plot. Does anyone know of any good ways to only show the most recent (lets say 100) data points so that after the first 100 the plot starts to replace the old data points with the new data points?
I thought it would be easier without code but here is the real time ploting that I have now.
from time import sleep
from labjack import ljm
import pylab as pl
import matplotlib.pyplot as plt
# Open T7 over USB
handle = ljm.openS("T7", "USB", "ANY")
# Configure thermocouple line on AIN0
ljm.eWriteName(handle, "AIN0_EF_INDEX", 22) # Feature index for type K thermocouple
ljm.eWriteName(handle, "AIN0_EF_CONFIG_A", 1) # Units. Default = Kelvin. 1 = Celsius. 2 = Fahrenheit.
ljm.eWriteName(handle, "AIN0_EF_CONFIG_B", 60052) # CJC source, address for device temperature sensor
ljm.eWriteName(handle, "AIN0_EF_CONFIG_D", 1.0) # Slope for CJC reading
ljm.eWriteName(handle, "AIN0_EF_CONFIG_E", 0.0) # Offset for CJC reading
temperature = []
x = list()
y = list()
x1 = list()
y1 = list()
dT_tol = .5
plt.ion()
fig=plt.figure()
# Read loop
for i in range(60):
# Get the thermocouple reading on AIN0.
tempC = ljm.eReadName(handle, "AIN0_EF_READ_A")
temperature.append(tempC)
dT = temperature[i]-temperature[i-1]
if -dT_tol<dT<dT_tol:
print "Temperature:","%.3f"% temperature[i]," " "dT:", "%.3f"% dT, " " "Steady State"
sleep(1)
else:
print "Temperature:","%.3f"% temperature[i]," " "dT:", "%.3f"% dT
sleep(1)
#Plotting
plt.figure(1)
plt.subplot(211)
plt.axis([0,60,0,80])
x.append(i)
y.append(temperature[i])
plt.scatter(x,y)
plt.ylabel('Temperature (C)')
plt.subplot(212)
plt.axis([0,60,-4,4])
x1.append(i)
y1.append(dT)
plt.scatter(x1,y1,zorder = 2)
#Set dT steady state boundaries
plt.axhspan(-dT_tol, dT_tol, color='#87CEFA', alpha=1, zorder = 1)
plt.ylabel('dT')
plt.xlabel('Time (s)')
plt.show()
plt.pause(.0001)
# Close handle
ljm.close(handle)
you can use list of array to show the all data given for a while.
for example
tempaturelist=[]
for i in range(50):
enter code here
tempaturelist.append(tempature)
print tempaturelist
There is a overwriting if you use same variable for all values.
Thats why you see only most recent values .
Edit:
You might consider using a deque object to improve performance. It is like a stack/queue hybrid, which may be faster than numpy.roll. I left the old code in for example..
from collections import deque
You can use something like this, just update it to fit your needs ( I am just going to make up random data because im too lazy to use your example)
import numpy as np
import pylab as plt
buffer_size = 100 # how many data points you want to plot at any given time
#data_buffer = np.zeros( buffer_size) # this is where you will keep the latest data points
data_buffer = deque()
for i in range( buffer_size):
data_buffer.append(0)
temperatures = np.random.random( 200 ) # some random temperature data, i dunno
# setup the figure
fig = plt.figure(1)
plt.suptitle('Previous %d temperatures'%buffer_size, fontsize=12)
ax = plt.gca()
for i,Temp in enumerate( temperatures ):
#data_buffer = np.roll( data_buffer, shift=-1)
#data_buffer[ -1] = Temp
data_buffer.popleft()
data_buffer.append( Temp)
ax.plot( data_buffer, 'rs', ms=6) # whatever style you want...
plt.draw()
plt.pause(0.01)
plt.cla() # clears the axis
I won't post the output of this plot because it will always be changing, but try it yourself ;)
Today my task is to produce a histogram where the y axis is a relative frequency rather than just an absolute count. I've located another question regarding this (see: Setting a relative frequency in a matplotlib histogram) however, when I try to implement it, I get the error message:
'list' object has no attribute size
despite having the exact same code given in the answer -- and despite their information also being stored in a list.
In addition, I have tried the method here(http://www.bertplot.com/visualization/?p=229) with no avail, as the output still doesn't show the y label as ranging from 0 to 1.
import numpy as np
import matplotlib.pyplot as plt
import random
from tabulate import tabulate
import matplotlib.mlab as mlab
precision = 100000000000
def MarkovChain(n,s) :
"""
"""
matrix = []
for l in range(n) :
lineLst = []
sum = 0
crtPrec = precision
for i in range(n-1) :
val = random.randrange(crtPrec)
sum += val
lineLst.append(float(val)/precision)
crtPrec -= val
lineLst.append(float(precision - sum)/precision)
matrix2 = matrix.append(lineLst)
print("The intial probability matrix.")
print(tabulate(matrix2))
baseprob = []
baseprob2 = []
baseprob3 = []
baseprob4 = []
for i in range(1,s): #changed to do a range 1-s instead of 1000
#must use the loop variable here, not s (s is always the same)
matrix_n = np.linalg.matrix_power(matrix2, i)
baseprob.append(matrix_n.item(0))
baseprob2.append(matrix_n.item(1))
baseprob3.append(matrix_n.item(2))
baseprob = np.array(baseprob)
baseprob2 = np.array(baseprob2)
baseprob3 = np.array(baseprob3)
baseprob4 = np.array(baseprob4)
# Here I tried to make a histogram using the plt.hist() command, but the normed=True doesn't work like I assumed it would.
'''
plt.hist(baseprob, bins=20, normed=True)
plt.show()
'''
#Here I tried to make a histogram using the method from the second link in my post.
# The code runs, but then the graph that is outputted isn't doesn't have the relative frequency on the y axis.
'''
n, bins, patches = plt.hist(baseprob, bins=30,normed=True,facecolor = "green",)
y = mlab.normpdf(bins,mu,sigma)
plt.plot(bins,y,'b-')
plt.title('Main Plot Title',fontsize=25,horizontalalignment='right')
plt.ylabel('Count',fontsize=20)
plt.yticks(fontsize=15)
plt.xlabel('X Axis Label',fontsize=20)
plt.xticks(fontsize=15)
plt.show()
'''
# Here I tried to make a histogram using the method seen in the Stackoverflow question I mentioned.
# The figure that pops out looks correct in terms of the axes, but no actual data is posted. Instead the error below is shown in the console.
# AttributeError: 'list' object has no attribute 'size'
fig = plt.figure()
ax = fig.add_subplot(111)
ax.hist(baseprob, weights=np.zeros_like(baseprob)+1./ baseprob.size)
n, bins, patches = ax.hist(baseprob, bins=100, normed=1, cumulative=0)
ax.set_xlabel('Bins', size=20)
ax.set_ylabel('Frequency', size=20)
ax.legend
plt.show()
print("The final probability matrix.")
print(tabulate(matrix_n))
matrixTranspose = zip(*matrix_n)
evectors = np.linalg.eig(matrixTranspose)[1][:,0]
print("The steady state vector is:")
print(evectors)
MarkovChain(5, 1000)
The methods I tried are each commented out, so to reproduce my errors, make sure to erase the comment markers.
As you can tell, I'm really new to Programming. Also this is not for a homework assignment in a computer science class, so there are no moral issues associated with just providing me with code.
The expected input to matplotlib functions are usually numpy arrays, which have the methods nparray.size. Lists do not have size methods so when list.size is called in the hist function, this causes your error. You need to convert, using nparray = np.array(list). You can do this after the loop where you build the lists with append, something like,
baseprob = []
baseprob2 = []
baseprob3 = []
baseprob4 = []
for i in range(1,s): #changed to do a range 1-s instead of 1000
#must use the loop variable here, not s (s is always the same)
matrix_n = numpy.linalg.matrix_power(matrix, i)
baseprob.append(matrix_n.item(0))
baseprob2.append(matrix_n.item(1))
baseprob3.append(matrix_n.item(2))
baseprob = np.array(baseprob)
baseprob2 = np.array(baseprob2)
baseprob3 = np.array(baseprob3)
baseprob4 = np.array(baseprob4)
EDIT: minimal hist example
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
baseprob = np.random.randn(1000000)
ax.hist(baseprob, weights=np.zeros_like(baseprob)+1./ baseprob.size, bins=100)
n, bins, patches = ax.hist(baseprob, bins=100, normed=1, cumulative=0, alpha = 0.4)
ax.set_xlabel('Bins', size=20)
ax.set_ylabel('Frequency', size=20)
ax.legend
plt.show()
which gives,
I have much the same problem as this guy: Dynamically updating plot in matplotlib. I want to update a graph with data from a serial port and I have been trying to implement this answer, but I can't get a MWE to work. The graph simply doesn't appear, but everything else seems to work. I have read about problems with the installation of Matplotlib causing similar symptoms.
Here is my Minimum Not Working Example (MNWE):
import numpy as np
import matplotlib.pyplot as plt
fig1 = plt.figure() #Create figure
l, = plt.plot([], [], 'r-') #What is the comma for? Is l some kind of struct/class?
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.xlabel('x')
plt.title('test')
k = 5
xdata=[0.5 for i in range(k+1)] # Generate a list to hold data
ydata=[j for j in range(k+1)]
while True:
y = float(raw_input("y val :"))
xdata.append(y) # Append new data to list
k = k + 1 # inc x value
ydata.append(k)
l.set_data(xdata,ydata) # update data
print xdata # Print for debug perposes
print ydata
plt.draw # These seem to do nothing
plt.show # !?
Could someone please point me in the right direction / provide a link / tell me what to google? I'm lost. Thanks
As suggested by user #fhdrsdg I was missing brackets. Getting the rescale to work requires code from: set_data and autoscale_view matplotlib
A working MWE is provided below:
import numpy as np
import matplotlib.pyplot as plt
plt.ion() # Enable interactive mode
fig = plt.figure() # Create figure
axes = fig.add_subplot(111) # Add subplot (dont worry only one plot appears)
axes.set_autoscale_on(True) # enable autoscale
axes.autoscale_view(True,True,True)
l, = plt.plot([], [], 'r-') # Plot blank data
plt.xlabel('x') # Set up axes
plt.title('test')
k = 5
xdata=[0.5 for i in range(k+1)] # Generate a list to hold data
ydata=[j for j in range(k+1)]
while True:
y = float(raw_input("y val :")) #Get new data
xdata.append(y) # Append new data to list
k = k + 1 # inc x value
ydata.append(k)
l.set_data(ydata,xdata) # update data
print xdata # Print for debug perposes
print ydata
axes.relim() # Recalculate limits
axes.autoscale_view(True,True,True) #Autoscale
plt.draw() # Redraw