Animated Interactive plots in Jupyter - python

I have a df that contains some data that I interactively filter with ipywidgets. This is the code that filters the df:
#interact_manual(channel=channel_widget,currency=currency_widget,
use_cumulative=cumulative_widget)
def filter_df_1(channel, currency, use_cumulative):
filtered1 = df[(df['SALES CHANNEL'].isin(channel)) &
(df['CURRENCY']==currency)]
return filtered1
This code works fine and produces the expected output.
After the data is filtered, I wish two plot two KDE Lines on the same plot (Im using seaborn but don't really mind any plotting library as long as I can get the animation to work properly) and then animate the plot month by month, drawing two lines for each month on the same figure and erasing the previous month's lines. Here is the unworking code:
def animate_kde():
fig = plt.figure()
plt.xlim(0,17500)
plt.xlabel('Price')
plt.ylabel('Density')
month_list = ['','January','February','March','April','May','June','July',
'August','September','October','Novemer','December']
plt.title('Price Density {}'.format(month_list[current_date]))
data = filter_df_1(channel_widget.value,currency_widget.value,cumulative_widget.value)
data = data[data['MONTH']==current_date]
base = data.groupby('FAMILY')[' PRICE/UNIT (EGP) '].mean().rename('BASE')
ax1 = sns.kdeplot(base)
ax2 = sns.kdeplot(data[' PRICE/UNIT (EGP) '])
def init():
plt.cla()
ax1 = sns.kdeplot(base)
ax2 = sns.kdeplot(data[' PRICE/UNIT (EGP) '])
def animate(i):
plt.cla()
current_date=i
ax1 = sns.kdeplot(base)
ax2 = sns.kdeplot(data[' PRICE/UNIT (EGP) '])
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=range(0,12), interval=1000)
rc('animation',html='jshtml')
HTML(anim.to_jshtml())
animate_kde()
When run, this code just produces a static image that doesn't animate and doesn't observe changes in the filtration of the df through interacting with the widgets.
Like this:
I am not trained as a programmer so I know I am probably making a bunch of mistakes in my code.
The desired output is an animated plot that observes the filtration of the df through the interactive widgets.

Related

matplotlib: Second empty window on plt.show()

I usually don't ask questions on this platform, but I have a problem that quite bugs me.
Context
I have a function that plots data from a dataframe that has stockdata. It all works perfectly except for the fact that a second, empty window shows next to the actual graph whenever I execute this function. (image)
Here is all the relevant code, I'd be very grateful if some smart people could help me.
def plot(self):
plt.clf()
plt.cla()
colors = Colors()
data = self.getStockData()
if data.empty:
return
data.index = [TimeData.fromTimestamp(x) for x in data.index]
current, previous = data.iloc[-1, 1], data.iloc[0, 1]
percentage = (current / previous - 1) * 100
# Create a table
color = colors.decideColorPct(percentage)
# Create the table
fig = plt.figure(edgecolor=colors.NEUTRAL_COLOR)
fig.patch.set_facecolor(colors.BACKGROUND_COLOR)
plt.plot(data.close, color=color)
plt.title(self.__str2__(), color=colors.NEUTRAL_COLOR)
plt.ylabel("Share price in $", color=colors.NEUTRAL_COLOR)
plt.xlabel("Date", color=colors.NEUTRAL_COLOR)
ax = plt.gca()
ax.xaxis.set_major_formatter(plt_dates.DateFormatter('%Y/%m/%d %H:%M'))
ax.set_xticks([data.index[0], data.index[-1]])
ax.set_facecolor(colors.BACKGROUND_COLOR)
ax.tick_params(color=colors.NEUTRAL_COLOR, labelcolor=colors.NEUTRAL_COLOR)
for spine in ax.spines.values():
spine.set_edgecolor(colors.NEUTRAL_COLOR)
ax.yaxis.grid(True, color=colors.NEUTRAL_COLOR, linestyle=(0, (5, 10)), linewidth=.5)
plt.show()
Some notes:
Matplotlib never gets used in the program before this.
The data is standardized and consists of the following columns: open, low, high, close, volume.
The index of the dataframe exists of timestamps, which gets converted to an index of datetime objects at the following line: data.index = [TimeData.fromTimestamp(x) for x in data.index]
Remove plt.clf() and plt.cla() because it automatically creates window for plot when you don't have this window.
And later fig = plt.figure() creates new window which it uses to display your plot.
Minimal code for test
import matplotlib.pyplot as plt
import pandas as pd
data = pd.DataFrame({'x': [1,2,3], 'y': [2,3,1]})
#plt.clf()
#plt.cla()
fig = plt.figure()
plt.plot(data)
ax = plt.gca()
plt.show()

Change matplotlib subplots to seperate plots

I have gathered a code to make plots from data from multiple days. I have a data file containing over 40 days and 19k timestamps, and I need a plot, one for each day. I want python to generate them as different plots.
Mr. T helped me a lot with providing the code, but I cannot manage the code to get it to plot individual plots instead of all in one subplot. Can somebody help me with this?
Picture shows the current output:
My code:
import matplotlib.pyplot as plt
import numpy as np
#read your data and create datetime index
df= pd.read_csv('test-februari.csv', sep=";")
df.index = pd.to_datetime(df["Date"]+df["Time"].str[:-5], format="%Y:%m:%d %H:%M:%S")
#group by date and hour, count entries
dfcounts = df.groupby([df.index.date, df.index.hour]).size().reset_index()
dfcounts.columns = ["Date", "Hour", "Count"]
maxcount = dfcounts.Count.max()
#group by date for plotting
dfplot = dfcounts.groupby(dfcounts.Date)
#plot each day into its own subplot
fig, axs = plt.subplots(dfplot.ngroups, figsize=(6,8))
for i, groupdate in enumerate(dfplot.groups):
ax=axs[i]
#the marker is not really necessary but has been added in case there is just one entry per day
ax.plot(dfplot.get_group(groupdate).Hour, dfplot.get_group(groupdate).Count, color="blue", marker="o")
ax.set_title(str(groupdate))
ax.set_xlim(0, 24)
ax.set_ylim(0, maxcount * 1.1)
ax.xaxis.set_ticks(np.arange(0, 25, 2))
plt.tight_layout()
plt.show()
Welcome to the Stackoverflow.
Instead of creating multiple subplots, you can create a figure on the fly and plot onto it in every loop separately. And at the end show all of them at the same time.
for groupdate in dfplot.groups:
fig = plt.figure()
plt.plot(groupdate.Hour, groupdate.Count, color="blue", marker="o")
plt.title(str(groupdate))
plt.xlim(0, 24)
plt.ylim(0, maxcount * 1.1)
plt.xticks(np.arange(0, 25, 2))
plt.tight_layout()
plt.show()

X tickers problem with plotting against time in matplotlib

I am trying to write a define function to plot a line graph by the data of a imported a csv file.
This a small sample of my data( temperature reading for every minutes):-
00:01:00.0305040, 35.35985
00:02:00.0438094, 35.48547
00:03:00.0571148, 35.65295
00:04:00.0704203, 35.90417
00:05:00.0837257, 36.23914
.
.
.
.
08:52:07.2370729, 74.92772
08:53:07.2503783, 75.01146
08:54:07.2648837, 75.05333
08:55:07.2781891, 75.0952
08:56:07.2914945, 75.0952
When I try to set the x ticker to be appear every hour, they do not show up in the plotted graph.
This is my code
df = pd.read_csv(file,names=["time", "temp"])
df["time"]=pd.to_datetime(df["time"])
df=df.set_index('time')
df.index = df.index.map (lambda t: t.strftime('%H:%M'))
print(df)
fig, ax = plt.subplots()
df.plot(ax = ax, color = 'black', linewidth = 0.4, x_compat=True)
ax.set(xlabel='Time (Hour:Minutes)', ylabel='Temperature (Celsius)')
ax.xaxis.set_major_locator(mdates.HourLocator(interval = 1))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
fig.autofmt_xdate()
return plt.show()
I have tried labeling the x tickers manually
plt.xticks(['0:00', '1:00', '2:00', '3:00', '4:00:0', '5:00', '6:00:0', '7:00', '8:00', '9:00', '10:00'])
and it worked, but it there a way for any given case?
According to the official documentation
All of plotting functions expect np.array or np.ma.masked_array as input. Classes that are 'array-like' such as pandas data objects and np.matrix may or may not work as intended. It is best to convert these to np.array objects prior to plotting.
So I changed your code slightly (basically converted the pd df into numpy array).
df = pd.read_csv(file,names=["time", "temp"])
df["time"]=pd.to_datetime(df["time"])
x_axis = np.array(df.time.values)
y_axis = np.array(df.temp.values)
fig, ax = plt.subplots()
ax.plot(x_axis,y_axis)
ax.set(xlabel='Time (Hour:Minutes)', ylabel='Temperature (Celsius)')
ax.xaxis.set_major_locator(mdates.HourLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
plt.show()
The ticks are visible now as below.

Python: Legend has wrong colors on Pandas MultiIndex plot

I'm trying to plot data from 2 seperate MultiIndex, with the same data as levels in each.
Currently, this is generating two seperate plots and I'm unable to customise the legend by appending some string to individualise each line on the graph. Any help would be appreciated!
Here is the method so far:
def plot_lead_trail_res(df_ante, df_post, symbols=[]):
if len(symbols) < 1:
print "Try again with a symbol list. (Time constraints)"
else:
df_ante = df_ante.loc[symbols]
df_post = df_post.loc[symbols]
ante_leg = [str(x)+'_ex-ante' for x in df_ante.index.levels[0]]
post_leg = [str(x)+'_ex-post' for x in df_post.index.levels[0]]
print "ante_leg", ante_leg
ax = df_ante.unstack(0).plot(x='SHIFT', y='MUTUAL_INFORMATION', legend=ante_leg)
ax = df_post.unstack(0).plot(x='SHIFT', y='MUTUAL_INFORMATION', legend=post_leg)
ax.set_xlabel('Time-shift of sentiment data (days) with financial data')
ax.set_ylabel('Mutual Information')
Using this function call:
sentisignal.plot_lead_trail_res(data_nasdaq_top_100_preprocessed_mi_res, data_nasdaq_top_100_preprocessed_mi_res_validate, ['AAL', 'AAPL'])
I obtain the following figure:
Current plots
Ideally, both sets of lines would be on the same graph with the same axes!
Update 2 [Concatenation Solution]
I've solved the issues of plotting from multiple frames using concatenation, however the legend does not match the line colors on the graph.
There are not specific calls to legend and the label parameter in plot() has not been used.
Code:
df_ante = data_nasdaq_top_100_preprocessed_mi_res
df_post = data_nasdaq_top_100_preprocessed_mi_res_validate
symbols = ['AAL', 'AAPL']
df_ante = df_ante.loc[symbols]
df_post = df_post.loc[symbols]
df_ante.index.set_levels([[str(x)+'_ex-ante' for x in df_ante.index.levels[0]],df_ante.index.levels[1]], inplace=True)
df_post.index.set_levels([[str(x)+'_ex-post' for x in df_post.index.levels[0]],df_post.index.levels[1]], inplace=True)
df_merge = pd.concat([df_ante, df_post])
df_merge['SHIFT'] = abs(df_merge['SHIFT'])
df_merge.unstack(0).plot(x='SHIFT', y='MUTUAL_INFORMATION')
Image:
MultiIndex Plot Image
I think, with
ax = df_ante.unstack(0).plot(x='SHIFT', y='MUTUAL_INFORMATION', legend=ante_leg)
you put the output of the plot() in ax, including the lines, which then get overwritten by the second function call. Am I right, that the lines which were plotted first are missing?
The official procedure would be rather something like
fig = plt.figure(figsize=(5, 5)) # size in inch
ax = fig.add_subplot(111) # if you want only one axes
now you have an axes object in ax, and can take this as input for the next plots.

Matplotlib: Printing plot to pdf file : not working with figure()

I am trying plotting multiple pandas data frames to a single pdf file by:
def plot_user_data(df):
fig = plt.figure()
df.plot(x = 'm_srcaddr')
plt.xticks(df.index, df['m_srcaddr'], rotation=90)
fig.suptitle('User Data Usage for ')
return fig
for multiple df I am calling ::
plot = plot_user_data(df)
pdf = PdfPages('foo.pdf')
pdf.savefig()
Above code is creating a pdf file without plot and per page title only.
How ever if I change the function like:
def plot_user_data(df):
fig = df.plot(x = 'm_srcaddr').get_figure()
plt.xticks(df.index, df['m_srcaddr'], rotation=90)
fig.suptitle('User Data Usage for' )
return fig
I am not able to figure out why first function is not plotting actual plot.? Now I want to change the size of each figures as I am not aware how to change fig size in second function.

Categories