The 2 red lines in the graph are the 2 extrapolated lines. The upper line works well but the lower line seems to take into account the data outside the range of time2 and temp2 which makes the line look awkward after the point t=420s. I would like to know how to fix this.
*On a less important note: how can i remove the extra ticks on x-axis on the left of the origin? Thanks a lot.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
from matplotlib.ticker import (MultipleLocator, FormatStrFormatter,
AutoMinorLocator)
from sklearn.linear_model import LinearRegression
from scipy.interpolate import InterpolatedUnivariateSpline
%matplotlib inline
file = pd.read_excel("T8.xlsx","Phthalansäureanhydrid",usecols=[2,3])
X = file['Zeit(s)']
Y = file['Temperatur(Celcius Grad)']
fig, ax = plt.subplots()
ax.plot(X,Y,'-',color='#10A5F3', label="Phthalansäureanhydrid")
ax.grid(True, which='major', axis='both', color='#F19211', linestyle='-')
#ax.grid(True, which='minor', axis='both', color='#F19211', linestyle='--')
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
#ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
#ax.legend(loc='upper center', frameon=True)
#major & minor ticks
ax.xaxis.set_major_locator(MultipleLocator(100))
ax.xaxis.set_major_formatter(FormatStrFormatter('%d'))
ax.xaxis.set_minor_locator(MultipleLocator(10))
#extrapolation - first line
temp1 = []
time1 = []
xnew1 = []
for i in file.index:
if i > 630:
temp1.append(file['Temperatur(Celcius Grad)'][i])
time1.append(file['Zeit(s)'][i])
else:
xnew1.append(file['Zeit(s)'][i])
order = 1
extrapo1 = InterpolatedUnivariateSpline(time1, temp1, k=1)
ynew1 = extrapo1(xnew1)
#extrapolation - second line
temp2 = []
time2 = []
xnew2 = []
for i in file.index:
if 100<i<400:
temp2.append(file['Temperatur(Celcius Grad)'][i])
time2.append(file['Zeit(s)'][i])
if i>200:
xnew2.append(file['Zeit(s)'][i])
ynew2 = []
f = interpolate.interp1d(time2, temp2, fill_value='extrapolate')
for i in xnew2:
ynew2.append(f(i))
plt.xlabel(r'Zeit[s]')
plt.ylabel(r'Temperatur[c]')
plt.plot(xnew1,ynew1,'-', color = '#B94A4D')
plt.plot(xnew2,ynew2,'-', color = '#B94A4D')
plt.savefig('kmn.pdf')
Link to the data: https://docs.google.com/spreadsheets/d/1xznXj-aA-Szq2s4KWb-qPWYxZbQNrA5FgUCQT6i7oVo/edit?usp=sharing
Related
The code below is supposed to update the graph (change the colors of the bar) depending on the ydata of on_click event. Some how, the colors do not chnage as supposed. Also, I'm using 'ax.clear()' to refresh the redraw the bars and the line every time the graph is clicked. Any idea what's wrong with this code?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from matplotlib import cm
import pandas as pd
# Use the following data for this assignment:
np.random.seed(12345)
df = pd.DataFrame([np.random.normal(32000,200000,3650),
np.random.normal(43000,100000,3650),
np.random.normal(43500,140000,3650),
np.random.normal(48000,70000,3650)],
index=[1992,1993,1994,1995])
fig, ax = plt.subplots()
#Plotting the Bar chart
mean = df.mean(axis = 1)
std = df.std(axis = 1)
n= df.shape[1]
yerr = 1.96*std/np.sqrt(3650)
plt.bar(range(df.shape[0]), mean, yerr = yerr, color = 'grey',capsize=10, alpha = 0.5)
plt.xticks(range(len(df.index)), df.index)
plt.title('Proportion of confidence interval lying below the threshold value')
plt.ylabel('Number of votes')
#Click on the graph to choose a value, the color of the bar change based on the yvalue
colourofbars = []
norm = None
cmap = plt.cm.get_cmap('RdYlBu')
dict = {mean[x]: yerr[x] for x in list(df.index)}
def onclick(event):
val = event.ydata
global colourofbars
global norm
#Defining the condition based on the ydata
for key,value in dict.items():
if val > (key+(value)):
colour = 0
colourofbars.append(colour)
elif val < (key-(value)):
colour = 1
colourofbars.append(colour)
elif ((key+(value))> val > (key-(value))):
colour = ((key+(value))-val)/((key+value)-(key-value))
colourofbars.append(colour)
ax.clear()
norm = matplotlib.colors.Normalize(vmin=min(colourofbars),vmax=max(colourofbars), clip=False)
#Plotting the colored bar chart
plt.bar(range(df.shape[0]), mean, yerr = yerr, capsize=10, alpha = 0.5, color=cmap(norm(colourofbars)))
plt.axhline(y=val,linewidth=1, color='k')
plt.gcf().canvas.draw_idle()
#Adding the colorbar legend
scalarmappaple = cm.ScalarMappable(norm=norm, cmap=cmap)
scalarmappaple.set_array(colourofbars)
plt.colorbar(scalarmappaple)
plt.gcf().canvas.mpl_connect('button_press_event', onclick)
fig.canvas.draw()
In Jupyter Notebook you have to add
%matplotlib notebook
in order to make the plot interactive (adding that line after import statements is fine).
With the above statement I get this plot:
If I click somewhere in the plot I get:
In the following code for each for loop i'm getting a single colorbar. But I want to represent the following data with a single colorbar.
`import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig = plt.figure()
ax= fig.add_subplot(111)
h_1 = np.load("./Result_2D/disorder.npy")
h = h_1[0:2]
print("h: ",h)
for k in range(len(h)):
h_val = round(h[k],1)
KL=np.load("./KL_%s.npy"%h_val)
print("KL: ",KL[0:5])
E = np.load("./E_%s.npy"%h_val)
print("E_shape: ",E[0:5])
W =np.load("./W_%s.npy"%h_val)
print("W: ",W[0:5])
sc= ax.scatter(E,W,c=KL,cmap='RdBu_r')
plt.colorbar(sc)`
here is some example code of how to print multiple scatter sets with the same single colorbar
pltrange = np.logspace(1, 2, num=20) #or use np.linspace, or provide a range of values (based on the limits of your data)
lbrange = pltrange[::2] #labels for colorbar
ax.scatter(x=stream['Dist'], y=stream['Depth'], s=50,
c=stream['Sand Concentration (mg/l)'],
cmap='rainbow', edgecolor='k', linewidths=1,
vmin=pltrange[0],vmax=pltrange[-1]) #note the vmin and vmax, do this for all scatter sets
cb = fig.colorbar(ax=ax, ticks=lbrange, pad=0.01) #display colorbar, keep outside loop
cb.ax.set_yticklabels(['{:.1f}'.format(i) for i in lbrange]) #format labels if desired
I realize it's not exactly formatted for your code but..it's the exact same principle and I'm posting this from bed :) so I think you could make the necessary adaptations
try this
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
fig = plt.figure()
ax= fig.add_subplot(111)
h_1 = np.load("./Result_2D/disorder.npy")
h = h_1[0:2]
print("h: ",h)
for k in range(len(h)):
h_val = round(h[k],1)
KL=np.load("./KL_%s.npy"%h_val)
print("KL: ",KL[0:5])
E = np.load("./E_%s.npy"%h_val)
print("E_shape: ",E[0:5])
W =np.load("./W_%s.npy"%h_val)
print("W: ",W[0:5])
sc= ax.scatter(E,W,c=KL,cmap='RdBu_r')
plt.colorbar(sc)
Consider the following code which implements ArtistAnimation to animate two different subplots within the same figure object.
import numpy as np
import itertools
import matplotlib.pyplot as plt
import matplotlib.mlab as ml
import matplotlib.animation as animation
def f(x,y,a):
return ((x/a)**2+y**2)
avals = np.linspace(0.1,1,10)
xaxis = np.linspace(-2,2,9)
yaxis = np.linspace(-2,2,9)
xy = itertools.product(xaxis,yaxis)
xy = list(map(list,xy))
xy = np.array(xy)
x = xy[:,0]
y = xy[:,1]
fig, [ax1,ax2] = plt.subplots(2)
ims = []
for a in avals:
xi = np.linspace(min(x), max(x), len(x))
yi = np.linspace(min(y), max(y), len(y))
zi = ml.griddata(x, y, f(x, y, a), xi, yi, interp='linear') # turn it into grid data, this is what imshow takes
title = plt.text(35,-4,str(a), horizontalalignment = 'center')
im1 = ax1.imshow(zi, animated = True, vmin = 0, vmax = 400)
im2 = ax2.imshow(zi, animated=True, vmin=0, vmax=400)
ims.append([im1,im2, title])
ani = animation.ArtistAnimation(fig, ims, interval = 1000, blit = False)
plt.show()
In this case the number of items in im1 and im2 are the same, and the frame rate for each subplot is identical.
Now, imagine I have 2 lists with different numbers of items, and that I wish ArtistAnimate to go through the frames in the same total time. Initially I thought of manipulating the interval keyword in the ArtistAnimation call but this implies that you can set different intervals for different artists, which I don't think is possible.
Anyway, I think the basic idea is pretty clear len(im1) is not equal to len(im2), but the animation needs to go through them all in the same amount of time.
Is there any way to do this please? Thanks
EDIT
While I try out the answer provided below, I should add that I would rather use ArtistAnimation due to the structure of my data. If there are no alternatives I will revert to the solution below.
Yes that is possible, kinda, using Funcanimation and encapsulating your data inside func.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
arr1 = np.random.rand(300,3,4)
arr2 = np.random.rand(200,5,6)
fig, (ax1, ax2) = plt.subplots(1,2)
img1 = ax1.imshow(arr1[0])
img2 = ax2.imshow(arr2[0])
# set relative display rates
r1 = 2
r2 = 3
def animate(ii):
if ii % r1:
img1.set_data(arr1[ii/r1])
if ii % r2:
img2.set_data(arr2[ii/r2])
return img1, img2
ani = animation.FuncAnimation(fig, func=animate, frames=np.arange(0, 600))
plt.show()
I am here looking for some advice. I have a data file, basically containing Time, Displacement & Force items I recorded from a mechanical experiment. During the experiment, I recorded a picture of it every 2 seconds.
What I would like to make, is an animation (*.avi, *.gif, ...) of the evolution of the Force vs. Displacement plot and the corresponding pictures above (or below) the plot.
To do so, I first made a script, greatly inspired by another post on the forum, to generate an animation of the plots only. Then another one to open a plot above and a picture below. However, I did not manage to mix these two codes.
Below are the two scripts if needed for more understanding.
Script 1: Generation an animated plot
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import pytex as p
import os
#1- Data reading
for filename in os.listdir("."):
if (filename[0]=="#"):
f = open(filename,"r+",encoding="utf8")
d = f.readlines()
f.seek(0)
for i in range(len(d)):
if i == 21:
f.write(d[i])
if i > 23:
f.write(d[i])
f.truncate()
f.close()
os.rename(filename,filename[1:])
#2- Data for plot
def simData():
for filename in os.listdir("."):
data = p.loadDataMatrix(filename)
tt = data["Time (sec)"]
x_raw = data["Position (microns)"]
y_raw = data["Load (N)"]
x = []
y = []
t = 0.
for i in range(0,len(x_raw),3):
x = x + [x_raw[i] - x_raw[0]]
y = y + [y_raw[i]]
t = tt[i]
yield x, y, t
def simPoints(simData):
xx, yy, t = simData[0], simData[1], simData[2]
time_text.set_text(time_template%(t))
line.set_data(xx, yy)
return line, time_text
#3- Plotting the figure
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlim(0, 450)
ax.set_ylim(0, 65)
delay = 1
line, = ax.plot([], [], 'b-', linewidth = 0.6)
time_template = 'Time = %.01f s'
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
ani = animation.FuncAnimation(fig, simPoints, simData, interval=delay, repeat=False, save_count = 50000)
ani.save('animation.mp4', fps=100, dpi=100)
Script 2: Merging a plot and an image
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as im
fig, (chart, picture) = plt.subplots(nrows=2, figsize=(10,8))
# First, the chart
chart.plot(np.random.random(100))
# Second, an image
image=im.imread("../test_no_8/IMG_004850.tiff")
picture.imshow(image, aspect='auto')
picture.axis('off')
plt.show()
fig.savefig('temp.tiff', dpi=100)
Thanks a lot for any help of yours, and please pardon my English if it ever seems unclear.
Sorry in advance if this is a little long winded but if I cut it down too much the problem is lost. I am trying to make a module on top of pandas and matplotlib which will give me the ability to make profile plots and profile matrices analogous to scatter_matrix. I am pretty sure my problem comes down to what object I need to return from Profile() so that I can handle Axes manipulation in Profile_Matrix(). Then the question is what to return form Profile_Matrix() so I can edit subplots.
My module (ProfileModule.py) borrows a lot from https://github.com/pydata/pandas/blob/master/pandas/tools/plotting.py and looks like:
import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import matplotlib.pyplot as plt
def Profile(x,y,nbins,xmin,xmax):
df = DataFrame({'x' : x , 'y' : y})
binedges = xmin + ((xmax-xmin)/nbins) * np.arange(nbins+1)
df['bin'] = np.digitize(df['x'],binedges)
bincenters = xmin + ((xmax-xmin)/nbins)*np.arange(nbins) + ((xmax-xmin)/(2*nbins))
ProfileFrame = DataFrame({'bincenters' : bincenters, 'N' : df['bin'].value_counts(sort=False)},index=range(1,nbins+1))
bins = ProfileFrame.index.values
for bin in bins:
ProfileFrame.ix[bin,'ymean'] = df.ix[df['bin']==bin,'y'].mean()
ProfileFrame.ix[bin,'yStandDev'] = df.ix[df['bin']==bin,'y'].std()
ProfileFrame.ix[bin,'yMeanError'] = ProfileFrame.ix[bin,'yStandDev'] / np.sqrt(ProfileFrame.ix[bin,'N'])
fig = plt.figure();
ax = ProfilePlot.add_subplot(1, 1, 1)
plt.errorbar(ProfileFrame['bincenters'], ProfileFrame['ymean'], yerr=ProfileFrame['yMeanError'], xerr=(xmax-xmin)/(2*nbins), fmt=None)
return ax
#or should I "return fig"
def Profile_Matrix(frame):
import pandas.core.common as com
import pandas.tools.plotting as plots
from pandas.compat import lrange
from matplotlib.artist import setp
range_padding=0.05
df = frame._get_numeric_data()
n = df.columns.size
fig, axes = plots._subplots(nrows=n, ncols=n, squeeze=False)
# no gaps between subplots
fig.subplots_adjust(wspace=0, hspace=0)
mask = com.notnull(df)
boundaries_list = []
for a in df.columns:
values = df[a].values[mask[a].values]
rmin_, rmax_ = np.min(values), np.max(values)
rdelta_ext = (rmax_ - rmin_) * range_padding / 2.
boundaries_list.append((rmin_ - rdelta_ext, rmax_+ rdelta_ext))
for i, a in zip(lrange(n), df.columns):
for j, b in zip(lrange(n), df.columns):
ax = axes[i, j]
common = (mask[a] & mask[b]).values
nbins = 100
(xmin,xmax) = boundaries_list[i]
ax=Profile(df[b][common],df[a][common],nbins,xmin,xmax)
#Profile(df[b][common].values,df[a][common].values,nbins,xmin,xmax)
ax.set_xlabel('')
ax.set_ylabel('')
plots._label_axis(ax, kind='x', label=b, position='bottom', rotate=True)
plots._label_axis(ax, kind='y', label=a, position='left')
if j!= 0:
ax.yaxis.set_visible(False)
if i != n-1:
ax.xaxis.set_visible(False)
for ax in axes.flat:
setp(ax.get_xticklabels(), fontsize=8)
setp(ax.get_yticklabels(), fontsize=8)
return axes
This will run with something like:
import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import matplotlib.pyplot as plt
import ProfileModule as pm
x = np.random.uniform(0, 100, size=1000)
y = x *x + 50*x*np.random.randn(1000)
z = x *y + 50*y*np.random.randn(1000)
nbins = 25
xmax = 100
xmin = 0
ProfilePlot = pm.Profile(x,y,nbins,xmin,xmax)
plt.title("Look this works!")
#This does not work as expected
frame = DataFrame({'z' : z,'x' : x , 'y' : y})
ProfileMatrix = pm.Profile_Matrix(frame)
plt.show()
This would hopefully produce a simple profile plot and a 3x3 profile matrix but it does not. I have tried various different methods to get this to work but I imagine it is not worth explaining them all.
I should mention I am using Enthought Canopy Express on Windows 7. Sorry for the long post and thanks again for any help with the code. This is my first week using Python.
You should pass around Axes objects and break your functions up to operate on a single axes at a time. You are close, but just change
import numpy as np
import matplotlib.pyplot as plt
def _profile(ax, x, y):
ln, = ax.plot(x, y)
# return the Artist created
return ln
def profile_matrix(n, m):
fig, ax_array = plt.subplots(n, m, sharex=True, sharey=True)
for ax in np.ravel(ax_array):
_profile(ax, np.arange(50), np.random.rand(50))
profile_matrix(3, 3)