I would like to make a dropdown menu that shows each column name from the dataset, and the user can choose a column to visualize the data.
With Python this code is:
for i in df.columns:
plt.figure(figsize = (10,6))
plt.title("Count vs "+i)
sns.histplot(data = df, x = i, element = 'bars')
I have tried the following code, which does not account for each column name, nor does it output charts similar to the above code.
def f(x):
return x
def f(age):
df.loc[age].iplot(
xTitle='Year',
yTitle='Count of {}'.format(age),
title='Count per Age'
)
interact(f, age=df.index)
Related
I'm trying to create an input form based on a Excel spreadsheet.
I use the spreadsheet to create a dataframe (which has 30 "products" listed)
I need to create a series of input boxes for each product on the list.
Currently I do this in a very inefficient way :
product_1 = (ipw.Dropdown(options=barrier_list['Product Name'],
value = barrier_list['Product Name'][0],
description= barrier_list['ISIN'][0],
disabled=False,
layout = {'width':'350px'}))
product_1.style.description_width = 'initial'
units_1 = (ipw.IntText(value=for_table['Units'][0],
description='Units:',
disabled=False,
layout = {'width':'200px'}
))
price_1 = (ipw.FloatText(value=for_table['Price'][0],
description='Price:',
disabled=False,
layout = {'width':'200px'}
))
value_1 = (ipw.FloatText(value=0,
description='Value:',
disabled=False,
layout = {'width':'200px'}
))
HBox_1 = ipw.HBox([product_1,units_1,price_1, value_1])
Which creates exactly what I need for one line of the input sheet. To do the next line I copy this exact code again and change all the [0] to [1]. This goes on 30x.
I know this is a terrible way to do it but I cannot figure out how to use a loop to create the 30 lines (1 per product) of input boxes.
The guidance worked. My solution was simple and along the lines of :
dd_list = []
for i in range(len(barrier_list['Product Name'])):
dropdown = widgets.Text(description=barrier_list['ISIN'][i],
value=barrier_list['Product Name'][i])
dd_list.append(dropdown)
VBox1 = widgets.VBox(dd_list)
VBox1
Just need to create the other boxes and add to the VBox.
I am working on a charting module where I can pass on dataframe and the module will create reports based on plots generated by calling few functions as mentioned below.
I am using Altair for plotting and "Datapane" for creating the report, the documentation of the same can be found here : https://datapane.github.io/datapane/
My DataFrame looks like this
d = {'Date': ['2021-01-01', '2021-01-01','2021-01-01','2021-01-01','2021-01-02','2021-01-03'],
'country': ['IND','IND','IND','IND','IND','IND' ],
'channel': ['Organic','CRM','Facebook','referral','CRM','CRM' ],
'sessions': [10000,8000,4000,2000,7000,6000 ],
'conversion': [0.1,0.2,0.1,0.05,0.12,0.11 ],
}
country_channel = pd.DataFrame(d)
Plotting functions :
def plot_chart(source,Y_axis_1,Y_axis_2,chart_caption):
base = alt.Chart(source).encode(
alt.X('Date:T', axis=alt.Axis(title="Date"))
)
line_1 = base.mark_line(opacity=1, color='#5276A7').encode(
alt.Y(Y_axis_1,
axis=alt.Axis( titleColor='#5276A7'))
)
line_2 = base.mark_line(opacity=0.3,color='#57A44C', interpolate='monotone').encode(
alt.Y(Y_axis_2,
axis=alt.Axis( titleColor='#57A44C'))
)
chart_ae=alt.layer(line_1, line_2).resolve_scale(
y = 'independent'
).interactive()
charted_plot = dp.Plot(chart_ae , caption=chart_caption)
return charted_plot
def channel_plot_split(filter_1,filter_2,country,channel):
channel_split_data = country_channel[(country_channel[filter_1]==country.upper())]
channel_split_data =channel_split_data[(channel_split_data[filter_2].str.upper()==channel.upper())]
channel_split_data=channel_split_data.sort_values(by='Date',ascending = True)
channel_split_data=channel_split_data.reset_index(drop=True)
channel_split_data.head()
plot_channel_split = plot_chart(source=channel_split_data,Y_axis_1='sessions:Q',Y_axis_2='conversion:Q',chart_caption="Sessions-Conversion Plot for Country "+country.upper()+" and channel :"+ channel)
channel_plot=dp.Group(dp.HTML("<div class='center'> <h3> Country : "+country.upper()+" & Channel : "+channel.upper()+"</h3></div>"),plot_channel_split,rows=2)
return channel_plot
def grpplot(plot_1,plot_2):
gp_plot = dp.Group(plot_1,plot_2,columns=2)
return gp_plot
The above functions when called, will filter the dataframe, create plot for each filters and group 2 plots in a row.
row_1 = grpplot(channel_plot_split('country','channel','IND','Organic'),channel_plot_split('country','channel','IND','CRM'))
row_2 = grpplot(channel_plot_split('country','channel','IND','Facebook'),channel_plot_split('country','channel','IND','referral'))
I can now generate a report by calling datapane.Report() function as follows
r= dp.Report(row_1,row_2)
Problem: This works fine when I know how many channels are present, but my channel list is dynamic.I am thing of using "for" loop to generate rows, but not sure how can I pass on these rows as kwargs in dp.Report() function. For example, if I have 10 channels, I need to pass 10 rows dynamically.
I had a similar problem and solved it as follows
Create a list to store the pages or elements of the report, such as
report_pages=[]
report_pages.append(dp.Page)
report_pages.append(dp.Table)
report_pages.append(dp.Plot)
At the end just generate the report with a pointer to the list
dp.Report(*pages)
In your case, I think you can do the following
create a list
rows=[]
add the rows to the list
rows.append(row_1)
rows.append(row_2)
and then create the report with
r= dp.Report(*rows)
I found this solution on datapane's GitHub and in this notebook in the last line of code.
So here is how I solved this problem.
channel_graph_list=[]
for i in range(0,len(unique_channels),1):
channel_1_name = unique_channels[i]
filtered_data = filter_the_data(source=channel_data,filter_1='channel',fv_1=channel_1_name)
get_chart = plot_chart(filtered_data,Y_axis_1='sessions:Q',Y_axis_2='conversion:Q',chart_title='Session & Conv. Chart for '+channel_1_name)
#This is where the trick starts - The below code creates a dynamic variable
vars() ["channel_row_"+str(i)] = get_chart
channel_graph_list.append("dp.Plot(channel_row_"+str(i)+",label='"+channel_1_name+"')")
#convert the list to a string
channel_graph_row = ','.join(channel_graph_list)
# assign the code you want to run
code="""channel_graph = dp.Select(blocks=["""+channel_graph_row+ """],type=dp.SelectType.TABS)"""
#execute the code
exec(code)
Hope the above solution helps others looking to pass dynamically generated parameters into any function.
I am trying to use a Holoviz Panel dropdown widget value to query a dataframe. The dataframe however does not reflect the change in the dropdown value. I added a markdown widget to check if the change in the dropdown value is being captured - It seems to be. However, I can't figure out how to update the dataframe. I am a complete beginner to programming, just trying to learn. Any help is appreciated.
import pandas as pd
import panel as pn
pn.extension()
# Dataframe
df = pd.DataFrame({'CcyPair':['EUR/USD', 'AUD/USD' ,'USD/JPY'],
'Requester':['Client1', 'Client2' ,'Client3'],
'Provider':['LP1', 'LP2' ,'LP3']})
# Dropdown
a2 = pn.widgets.Select(options=list(df.Provider.unique()))
# Query dataframe based on value in Provider dropdown
def query(x=a2):
y = pn.widgets.DataFrame(df[(df.Provider==x)])
return y
# Test Markdown Panel to check if the dropdown change returns value
s = pn.pane.Markdown(object='')
# Register watcher and define callback
w = a2.param.watch(callback, ['value'], onlychanged=False)
def callback(*events):
print(events)
for event in events:
if event.name == 'value':
df1 = query(event.new)
s.object = event.new
# Display Output
pn.Column(query, s)
Output Image
Inspired by the self-answer, the following code produces a select box containing the list of providers and a dataframe filtered on that selection. It was tested on Panel version 0.13.1.
Note that the watch=True suggestion in the self-answer wasn't necessary.
import pandas as pd
import panel as pn
pn.extension()
# Dataframe
df = pd.DataFrame({
'CcyPair':['EUR/USD', 'AUD/USD' ,'USD/JPY'],
'Requester':['Client1', 'Client2' ,'Client3'],
'Provider':['LP1', 'LP2' ,'LP3']
})
# Dropdown
providers = list(df.Provider.unique())
select_widget = pn.widgets.Select(options=providers)
# Query dataframe based on value in Provider dropdown
#pn.depends(select_widget)
def query(x):
filtered_df = pn.widgets.DataFrame(df[df.Provider==x])
return filtered_df
# Display Output
pn.Column(select_widget, query)
Figured it out, turned out I just needed to add #pn.depends above my query function. Once I added pn.depends(a2, watch=True), the dataframe was filtered based on a2 input. The callback and watcher were unnecessary.
Python Panel passing a dataframe in param.Parameterized class
I can build a dashboard using panel. I know want to include the code in a class including the data manipulation.
df = ydata.load_web(rebase=True)
class Plot(param.Parameterized):
df = df
col = list(df.columns)
Index1 = param.ListSelector(default=col, objects=col)
Index2 = param.ListSelector(default=col[1:2], objects=col)
def dashboard(self, **kwargs):
unds = list(set(self.Index1 + self.Index2))
return self.df[unds].hvplot()
b = Plot(name="Index Selector")
pn.Row(b.param, b.dashboard)
I would like to call
b = Plot(name="Index Selector", df=ydata.load_web(rebase=True))
Using a parameterized DataFrame and two methods for
setting the ListSelector according the available columns in the data frame and
creating a plot with hv.Overlay (containing single plots for each choosen column),
the code could look like this:
# Test data frame with two columns
df = pd.DataFrame(np.random.randint(90,100,size=(100, 1)), columns=['1'])
df['2'] = np.random.randint(70,80,size=(100, 1))
class Plot(param.Parameterized):
df = param.DataFrame(precedence=-1) # precedence <1, will not be shown as widget
df_columns = param.ListSelector(default=[], objects=[], label='DataFrame columns')
def __init__(self, **params):
super(Plot, self).__init__(**params)
# set the column selector with the data frame provided at initialization
self.set_df_columns_selector()
# method is triggered each time the data frame changes
#param.depends('df', watch=True)
def set_df_columns_selector(self):
col = list(self.df.columns)
print('Set the df index selector when the column list changes: {}'.format(col))
self.param.df_columns.objects = list(col) # set choosable columns according current df
self.df_columns = [self.param.df_columns.objects[0]] # set column 1 as default
# method is triggered each time the choosen columns change
#param.depends('df_columns', watch=True)
def set_plots(self):
print('Plot the columns choosen by the df column selector: {}'.format(self.df_columns))
plotlist = [] # start with empty list
for i in self.df_columns:
# append plot for each choosen column
plotlist.append(hv.Curve({'x': self.df.index, 'y':self.df[i]}))
self.plot = hv.Overlay(plotlist)
def dashboard(self):
return self.plot
b = Plot(name="Plot", df=df)
layout = pn.Row(b.param, b.dashboard)
layout.app()
#or:
#pn.Row(b.param, b.dashboard)
This way the parameterized variables take care of updating the plots.
I want to create 2 dropdown widgets in my Jupyter Notebook. The dropdown content is taken from a dataframe.
Let's say I have a pandas dataframe consisting of 3 categorical variables 'a', 'b', 'c'. 'a' has 3 subtypes 'a1','a2' and 'a3'. 'b' and 'c' are similar to a in the sense that they also have their own subtypes. I want to create 2 dropdown widgets: the first dropdown widget will have ['a','b','c'], and the second dropdown widget will display subtypes depending on what variable the user selects for the first widget.
I honestly have any idea how to do this. I'll try to write out some codes for this:
import pandas as pd
from IPython.display import *
import ipywidgets as widgets
from ipywidgets import *
# Create the dataframe
df = pd.DataFrame([['a1','a2','a3'],
['b1','b2','b3'],
['c1','c2','c3']], index = ['a','b','c']).transpose()
# Widgets
widget1 = Dropdown(options = ['a','b','c'])
display(widget1)
widget2 = Dropdown(???????)
display(widget2)
And depending on what I select for the two dropdown widgets, I want some function executed.
Any help is appreciated.
I found out how to do this. I hope this helps for anyone else who's also looking to do the same thing.
x_widget = Dropdown(options = ['a','b','c'])
y_widget = Dropdown()
# Define a function that updates the content of y based on what we select for x
def update(*args):
y_widget.options = df[x_widget.value].unique().tolist()
x_widget.observe(update)
# Some function you want executed
def random_function():
...
interact(random_function,
x = x_widget,
y = y_widget);