I have a for loop running through my data to find dips in my data set. This gives me five different graphs. I need to superimpose these five graphs onto each other with different colors. Yes, it will ve very messy.
I've done this before but not while it's in a four loop so I'm not sure how to go about it. Here is my data
# data
data = np.loadtxt('student_021.txt') # loading light curve data file
time_x = data[:,0] # taking the first column of data
lum_y = data[:,1] # second column
mean = lum_y.mean() # mean value of the light curve
std = lum_y.std() # standard deviation of the light curve
light_dip = [] # initalize empty array for areas where the light curve dips
end = None # cut off the values here where the data goes to normal
# for loop to go through the data and find where the light dips are
for i, x in enumerate(lum_y): #enumerate to assign positional values so I can identify and sepparate them
if x < mean - (std *4): # if the iterator is less than the mean - an arbitrarly chosen 4stds
if not light_dip: # is it an outlier or not?
light_dip.append(i) # if it is, let me know and append the data
end = i
else:
if i > end + 250: # find the end of the light dip
end = light_dip.append(i)
end = i
print(light_dip)
# plotting the primary chart
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlabel('Time(s)')
ax.set_ylabel('Brightnes')
ax.plot(time_x,lum_y)
plt.title('Original Graph')
for dip in light_dip: # sort through and print out the five different light dips
i = max(dip - 50, 0) # left limit
j = dip + 150 # right limit
factor_x = time_x[i:j]
factor_y = lum_y[i:j]
# plotting
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlabel('Time (s)')
ax.set_ylabel('Brightnes')
#ax.plot(time_x,lum_y)
ax.plot(factor_x, factor_y)
Related
I am drawing streamplots using matplotlib, and exporting them to a vector format. However, I find the streamlines are exported as a series of separate lines - not joined objects. This has the effect of reducing the quality of the image, and making for an unwieldy file for further manipulation. An example; the following images are of a pdf generated by exportfig and viewed in Acrobat Reader:
This is the entire plot
and this is a zoom of the center.
Interestingly, the length of these short line segments is affected by 'density' - increasing the density decreases the length of the lines. I get the same behavior whether exporting to svg, pdf or eps.
Is there a way to get a streamplot to export streamlines as a single object, preferably as a curved line?
MWE
import matplotlib.pyplot as plt
import numpy as np
square_size = 101
x = np.linspace(-1,1,square_size)
y = np.linspace(-1,1,square_size)
u, v = np.meshgrid(-x,y)
fig, axis = plt.subplots(1, figsize = (4,3))
axis.streamplot(x,y,u,v)
fig.savefig('YourDirHere\\test.pdf')
In the end, it seemed like the best solution was to extract the lines from the streamplot object, and plot them using axis.plot. The lines are stored as individual segments with no clue as to which line they belong, so it is necessary to stitch them together into continuous lines.
Code follows:
import matplotlib.pyplot as plt
import numpy as np
def extract_streamlines(sl):
# empty list for extracted lines, flag
new_lines = []
for line in sl:
#ignore zero length lines
if np.array_equiv(line[0],line[1]):
continue
ap_flag = 1
for new_line in new_lines:
#append the line segment to either start or end of exiting lines, if either the star or end of the segment is close.
if np.allclose(line[0],new_line[-1]):
new_line.append(list(line[1]))
ap_flag = 0
break
elif np.allclose(line[1],new_line[-1]):
new_line.append(list(line[0]))
ap_flag = 0
break
elif np.allclose(line[0],new_line[0]):
new_line.insert(0,list(line[1]))
ap_flag = 0
break
elif np.allclose(line[1],new_line[0]):
new_line.insert(0,list(line[0]))
ap_flag = 0
break
# otherwise start a new line
if ap_flag:
new_lines.append(line.tolist())
return [np.array(line) for line in new_lines]
square_size = 101
x = np.linspace(-1,1,square_size)
y = np.linspace(-1,1,square_size)
u, v = np.meshgrid(-x,y)
fig_stream, axis_stream = plt.subplots(1, figsize = (4,3))
stream = axis_stream.streamplot(x,y,u,v)
np_new_lines = extract_streamlines(stream.lines.get_segments())
fig, axis = plt.subplots(1, figsize = (4,4))
for line in np_new_lines:
axis.plot(line[:,0], line[:,1])
fig.savefig('YourDirHere\\test.pdf')
A quick solution to this issue is to change the default cap styles of those tiny segments drawn by the streamplot function. In order to do this, follow the below steps.
Extract all the segments from the stream plot.
Bundle these segments through LineCollection function.
Set the collection's cap style to round.
Set the collection's zorder value smaller than the stream plot's default 2. If it is higher than the default value, the arrows of the stream plot will be overdrawn by the lines of the new collection.
Add the collection to the figure.
The solution of the example code is presented below.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.collections import LineCollection # Import LineCollection function.
square_size = 101
x = np.linspace(-1,1,square_size)
y = np.linspace(-1,1,square_size)
u, v = np.meshgrid(-x,y)
fig, axis = plt.subplots(1, figsize = (4,3))
strm = axis.streamplot(x,y,u,v)
# Extract all the segments from streamplot.
strm_seg = strm.lines.get_segments()
# Bundle segments with round capstyle. The `zorder` value should be less than 2 to not
# overlap streamplot's arrows.
lc = LineCollection(strm_seg, zorder=1.9, capstyle='round')
# Add the bundled segment to the subplot.
axis.add_collection(lc)
fig.savefig('streamline.pdf')
Additionally, if you want to have streamlines their line widths changing throughout the graph, you have to extract them and append this information to LineCollection.
strm_lw = strm.lines.get_linewidths()
lc = LineCollection(strm_seg, zorder=1.9, capstyle='round', linewidths=strm_lw)
Sadly, the implementation of a color map is not as straight as the above solution. Therefore, using a color map with above approach will not be very pleasing. You can still automate the coloring process, as shown below.
strm_col = strm.lines.get_color()
lc = LineCollection(strm_seg, zorder=1.9, capstyle='round', color=strm_col)
Lastly, I opened a pull request to change the default capstyle option in the matplotlib repository, it can be seen here. You can apply this commit using below code too. If you prefer to do so, you do not need any tricks explained above.
diff --git a/lib/matplotlib/streamplot.py b/lib/matplotlib/streamplot.py
index 95ce56a512..0229ae107c 100644
--- a/lib/matplotlib/streamplot.py
+++ b/lib/matplotlib/streamplot.py
## -222,7 +222,7 ## def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
arrows.append(p)
lc = mcollections.LineCollection(
- streamlines, transform=transform, **line_kw)
+ streamlines, transform=transform, **line_kw, capstyle='round')
lc.sticky_edges.x[:] = [grid.x_origin, grid.x_origin + grid.width]
lc.sticky_edges.y[:] = [grid.y_origin, grid.y_origin + grid.height]
if use_multicolor_lines:
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 would like to animate the data points which i receive from a DL model.
I have followed the answer from here.
I had created my animated plot which satisfies my requirement.
Kindly see the picture below, where it shows X axes labels Defect & No Defect start to raise from 0 and reach a maximum point.
I want two conditions to be met, after the animation completed,
How can I annotate or display a message in the plot after the animation gets completed. (for eg : in my case I want to display maximum value - either defect or No defect in the plot based on the value)
The picture shows below is for 1 iteration which ran for 100 frames. In the same way, i have another 30 iterations data where each of them should run for 100 frames using FuncAnimtaion, which produces animation graph for each iterations and display/annotate the maximum value at the end of iterations.
I can give my 30 iterations one by one and produce results, but how one can achieve in code totally.
Picture
Code
from matplotlib import animation
import matplotlib
from matplotlib import pyplot as plt
import numpy as np
def barlist(n):
# model detail
b = n + 1
c = X_test[0][:b].reshape((-1, b, X_test.shape[2])) # Input to model
mod = model.predict_on_batch(c) # DL Model which takes input c
pred = np.argmax(mod, axis=2) # Output a array
St = np.count_nonzero(pred == 0)
Rt = np.count_nonzero(pred)
return [St, Rt] # for every frame St, Rt gets updated & animate plot
fig = plt.figure()
axes = plt.axes()
axes.set_ylim([0, 110])
x = np.arange(0,2)
my_xticks = ['Defect','No Defect']
plt.xticks(x, my_xticks)
barcollection = plt.bar(x,[0, 0], width= 0.3)
n = 100 #Number of frames
def animate(i):
y = barlist(i)
for i, b in enumerate(barcollection):
b.set_height(y[i])
anim=animation.FuncAnimation(fig,animate,repeat=False,blit=False,frames=n,interval=50)
plt.show()
Currently, I'm working on an introductory paper on data manipulation and such; however... the CSV I'm working on has some things I wish to do a scatter graph on!
I want a scatter graph to show me the volume sold on certain items as well as their average price, differentiating all data according to their region (Through colours I assume).
So what I want is to know if I can add the region column as a quantitative value
or if there's a way to make this possible...
It's my first time using Python and I'm confused way too often
I'm not sure if this is what you mean, but here is some working code, assuming you have data in the format of [(country, volume, price), ...]. If not, you can change the inputs to the scatter method as needed.
import random
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
n_countries = 50
# get the data into "countries", for example
countries = ...
# in this example: countries is [('BS', 21, 25), ('WZ', 98, 25), ...]
df = pd.DataFrame(countries)
# arbitrary method to get a color
def get_color(i, max_i):
cmap = matplotlib.cm.get_cmap('Spectral')
return cmap(i/max_i)
# get the figure and axis - make a larger figure to fit more points
# add labels for metric names
def get_fig_ax():
fig = plt.figure(figsize=(14,14))
ax = fig.add_subplot(1, 1, 1)
ax.set_xlabel('volume')
ax.set_ylabel('price')
return fig, ax
# switch around the assignments depending on your data
def get_x_y_labels():
x = df[1]
y = df[2]
labels = df[0]
return x, y, labels
offset = 1 # offset just so annotations aren't on top of points
x, y, labels = get_x_y_labels()
fig, ax = get_fig_ax()
# add a point and annotation for each of the labels/regions
for i, region in enumerate(labels):
ax.annotate(region, (x[i] + offset, y[i] + offset))
# note that you must use "label" for "legend" to work
ax.scatter(x[i], y[i], color=get_color(i, len(x)), label=region)
# Add the legend just outside of the plot.
# The .1, 0 at the end will put it outside
ax.legend(loc='upper right', bbox_to_anchor=(1, 1, .1, 0))
plt.show()
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 ;)