Here are the examples of the python api bokeh.embed.json_item taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.
11 Examples
3
View Source File : usage.py
License : MIT License
Project Creator : plotly
License : MIT License
Project Creator : plotly
def bokeh_fig(year):
df = gapminder.query("year == %d" % (year or 1952))
return json_item( hv.render( hv.Points(df, kdims=["gdpPercap", "lifeExp"])
.opts( color="continent", size=hv.dim("pop") ** (0.5) / 800,
logx=True, height=330, width=530, cmap="Category10",tools=["hover"],
legend_position="bottom_right", title="HoloViews / Bokeh") ))
@app.callback(Output("seaborn", "contents"), [Input("year", "value")])
0
View Source File : __init__.py
License : MIT License
Project Creator : ash2shukla
License : MIT License
Project Creator : ash2shukla
def streamlit_bokeh_events(bokeh_plot=None, events="", key=None, debounce_time=1000, refresh_on_update=True, override_height=None):
"""Returns event dict
Keyword arguments:
bokeh_plot -- Bokeh figure object (default None)
events -- Comma separated list of events dispatched by bokeh eg. "event1,event2,event3" (default "")
debounce_time -- Time in ms to wait before dispatching latest event (default 1000)
refresh_on_update -- Should the chart be re-rendered on refresh (default False)
: Set to False if you are not updating the datasource at runtime
override_height -- Override plot viewport height
"""
if key is None:
raise ValueError("key can not be None.")
div_id = "".join(choices(ascii_letters, k=16))
fig_dict = json_item(bokeh_plot, div_id)
json_figure = json.dumps(fig_dict)
component_value = _component_func(
bokeh_plot=json_figure,
events=events,
key=key,
_id=div_id,
default=None,
debounce_time=debounce_time,
refresh_on_update=refresh_on_update,
override_height=override_height
)
return component_value
if not _RELEASE:
0
View Source File : test_clustergram.py
License : MIT License
Project Creator : martinfleis
License : MIT License
Project Creator : martinfleis
def test_bokeh():
clustergram = Clustergram(range(1, 8), backend="sklearn", random_state=random_state)
clustergram.fit(data)
f = clustergram.bokeh(pca_kwargs=dict(random_state=random_state))
out = str(json_item(f, "clustergram"))
assert out.count("data") == 60
assert "cluster_labels" in out
assert "count" in out
assert "ratio" in out
assert "size" in out
f = clustergram.bokeh(pca_weighted=False)
out = str(json_item(f, "clustergram"))
assert out.count("data") == 60
assert "cluster_labels" in out
assert "count" in out
assert "ratio" in out
assert "size" in out
@pytest.mark.skipif(
0
View Source File : test_clustergram.py
License : MIT License
Project Creator : martinfleis
License : MIT License
Project Creator : martinfleis
def test_bokeh_cuml():
n_samples = 10
n_features = 2
n_clusters = 5
random_state = 0
device_data, device_labels = cuml.make_blobs(
n_samples=n_samples,
n_features=n_features,
centers=n_clusters,
random_state=random_state,
cluster_std=0.1,
)
data = cudf.DataFrame(device_data)
clustergram = Clustergram(range(1, 8), backend="cuML", random_state=random_state)
clustergram.fit(data)
f = clustergram.bokeh()
out = str(json_item(f, "clustergram"))
assert out.count("data") == 58
assert "cluster_labels" in out
assert "count" in out
assert "ratio" in out
assert "size" in out
0
View Source File : outputs.py
License : MIT License
Project Creator : PSLmodels
License : MIT License
Project Creator : PSLmodels
def aggregate_plot(tb):
"""
Function for creating a bokeh plot that shows aggregate tax liabilities for
each year the TaxBrain instance was run
Parameters
----------
tb: An instance of the TaxBrain object
Returns
-------
Bokeh figure
"""
# Pull aggregate data by year and transpose it for plotting
varlist = ["iitax", "payrolltax", "combined"]
base_data = tb.multi_var_table(varlist, "base").transpose()
base_data["calc"] = "Base"
reform_data = tb.multi_var_table(varlist, "reform").transpose()
reform_data["calc"] = "Reform"
base_cds = ColumnDataSource(base_data)
reform_cds = ColumnDataSource(reform_data)
num_ticks = len(base_data)
del base_data, reform_data
fig = figure(title="Aggregate Tax Liability by Year",
width=700, height=500, tools="save")
ii_base = fig.line(x="index", y="iitax", line_width=4,
line_color="#12719e", legend_label="Income Tax - Base",
source=base_cds)
ii_reform = fig.line(x="index", y="iitax", line_width=4,
line_color="#73bfe2", legend_label="Income Tax - Reform",
source=reform_cds)
proll_base = fig.line(x="index", y="payrolltax", line_width=4,
line_color="#408941", legend_label="Payroll Tax - Base",
source=base_cds)
proll_reform = fig.line(x="index", y="payrolltax", line_width=4,
line_color="#98cf90", legend_label="Payroll Tax - Reform",
source=reform_cds)
comb_base = fig.line(x="index", y="combined", line_width=4,
line_color="#a4201d", legend_label="Combined - Base",
source=base_cds)
comb_reform = fig.line(x="index", y="combined", line_width=4,
line_color="#e9807d", legend_label="Combined - Reform",
source=reform_cds)
# format figure
fig.legend.location = "top_left"
fig.yaxis.formatter = NumeralTickFormatter(format="$0.00a")
fig.yaxis.axis_label = "Aggregate Tax Liability"
fig.xaxis.minor_tick_line_color = None
fig.xaxis[0].ticker.desired_num_ticks = num_ticks
# Add hover tool
tool_str = """
< p> < b>@calc - {} < /b> < /p>
< p>${} < /p>
"""
ii_hover = HoverTool(
tooltips=tool_str.format("Individual Income Tax", "@iitax{0,0}"),
renderers=[ii_base, ii_reform]
)
proll_hover = HoverTool(
tooltips=tool_str.format("Payroll Tax", "@payrolltax{0,0}"),
renderers=[proll_base, proll_reform]
)
combined_hover = HoverTool(
tooltips=tool_str.format("Combined Tax", "@combined{0,0}"),
renderers=[comb_base, comb_reform]
)
fig.add_tools(ii_hover, proll_hover, combined_hover)
# toggle which lines are shown
plot_js = """
object1.visible = toggle.active
object2.visible = toggle.active
object3.visible = toggle.active
"""
base_callback = CustomJS(code=plot_js, args={})
base_toggle = Toggle(label="Base", button_type="primary",
active=True)
base_callback.args = {"toggle": base_toggle, "object1": ii_base,
"object2": proll_base, "object3": comb_base}
base_toggle.js_on_change('active', base_callback)
reform_callback = CustomJS(code=plot_js, args={})
reform_toggle = Toggle(label="Reform", button_type="primary",
active=True)
reform_callback.args = {"toggle": reform_toggle, "object1": ii_reform,
"object2": proll_reform, "object3": comb_reform}
fig_layout = layout([fig], [base_toggle, reform_toggle])
reform_toggle.js_on_change('active', reform_callback)
# Components needed to embed the figure
data = json_item(fig_layout)
outputs = {
"media_type": "bokeh",
"title": "",
"data": data,
}
return outputs
def create_layout(data, start_year, end_year):
0
View Source File : outputs.py
License : MIT License
Project Creator : PSLmodels
License : MIT License
Project Creator : PSLmodels
def create_layout(data, start_year, end_year):
"""
Function for creating a bokeh layout with all of the data tables
"""
agg_data = data["aggr_outputs"]
# create aggregate table
clt_title = f" < h3>{agg_data['current']['title']} < /h3>"
current_law_table = Div(text=clt_title + agg_data["current"]["renderable"],
width=1000)
rt_title = f" < h3>{agg_data['reform']['title']} < /h3>"
reform_table = Div(text=rt_title + agg_data["reform"]["renderable"],
width=1000)
ct_title = f" < h3>{agg_data['change']['title']} < /h3>"
change_table = Div(text=ct_title + agg_data["change"]["renderable"],
width=1000)
current_tab = Panel(child=current_law_table,
title="Current Law")
reform_tab = Panel(child=reform_table,
title="Reform")
change_tab = Panel(child=change_table,
title="Change")
agg_tabs = Tabs(tabs=[current_tab, reform_tab, change_tab])
key_map = {
"current": "Current",
"reform": "Reform",
"ind_income": "Income Tax",
"payroll": "Payroll Tax",
"combined": "Combined Tax",
"dist": "Distribution Table",
"diff": "Differences Table"
}
tbl_data = data["tbl_outputs"]
yr_panels = []
# loop through each year (start - end year)
for yr in range(start_year, end_year + 1):
# loop through each table type: dist, idff
tbl_panels = []
for tbl_type, content in tbl_data.items():
# loop through sub tables: current, reform for dist
# ind_income, payroll, combined for diff
content_panels = []
for key, value in content.items():
# loop through each grouping: bins, deciles
grp_panels = []
for grp, grp_data in value.items():
_data = grp_data[yr]
# create a data table for this tab
title = f" < h3>{_data['title']} < /h3>"
note = (" < p> < i>All monetary totals are in billions. "
"All counts are in millions. "
"Averages and shares are as shown. < /i> < /p>")
tbl = Div(text=title + note + _data["renderable"],
width=1000)
grp_panel = Panel(child=tbl, title=grp.title())
grp_panels.append(grp_panel)
grp_tab = Tabs(tabs=grp_panels)
# panel for the sub tables
content_panel = Panel(child=grp_tab, title=key_map[key])
content_panels.append(content_panel)
content_tab = Tabs(tabs=content_panels)
# panel for the table types
tbl_panel = Panel(child=content_tab,
title=key_map[tbl_type])
tbl_panels.append(tbl_panel)
type_tab = Tabs(tabs=tbl_panels)
# panel for the year
yr_panel = Panel(child=type_tab, title=str(yr))
yr_panels.append(yr_panel)
yr_tabs = Tabs(tabs=yr_panels)
agg_layout = layout(
children=[agg_tabs]
)
table_layout = layout(
children=[yr_tabs]
)
agg_data = json_item(agg_layout)
table_data = json_item(table_layout)
# return a dictionary of outputs ready for COMP
agg_outputs = {
"media_type": "bokeh",
"title": "Aggregate Results",
"data": agg_data,
}
table_outputs = {
"media_type": "bokeh",
"title": "Tables",
"data": table_data,
}
# return js, div, cdn_js, cdn_css, widget_js, widget_css
return agg_outputs, table_outputs
0
View Source File : outputs.py
License : MIT License
Project Creator : PSLmodels
License : MIT License
Project Creator : PSLmodels
def liability_plot(df_base, df_reform, span, mtr_opt):
df_base = ColumnDataSource(df_base)
df_reform = ColumnDataSource(df_reform)
tools = "pan, zoom_in, zoom_out, reset"
fig = figure(plot_width=600, plot_height=500,
x_range=(-10000, 300000), y_range=(-20000, 100000), tools=tools, active_drag="pan")
fig.yaxis.axis_label = "Tax Liabilities"
fig.yaxis.formatter = NumeralTickFormatter(format="$0,000")
filer_income = Span(location=span, dimension='height',
line_color='black', line_dash='dotted', line_width=1.5)
fig.add_layout(filer_income)
label_format = f'{span:,}'
filer_income_label = Label(x=span, y=25, y_units='screen', x_offset=10, text="{}: $".format(mtr_opt) + label_format,
text_color='#303030', text_font="arial", text_font_style="italic", text_font_size="10pt")
fig.add_layout(filer_income_label)
axis = Span(location=0, dimension='width',
line_color='#bfbfbf', line_width=1.5)
fig.add_layout(axis)
iitax_base = fig.line(x="Axis", y="Individual Income Tax", line_color='#2b83ba', muted_color='#2b83ba',
line_width=2, legend_label="Individual Income Tax Liability", muted_alpha=0.1, source=df_base)
payroll_base = fig.line(x="Axis", y="Payroll Tax", line_color='#abdda4', muted_color='#abdda4',
line_width=2, legend_label='Payroll Tax Liability', muted_alpha=0.1, source=df_base)
iitax_reform = fig.line(x="Axis", y="Individual Income Tax", line_color='#2b83ba', muted_color='#2b83ba',
line_width=2, line_dash='dashed', legend_label="Individual Income Tax Liability", muted_alpha=0.1, source=df_reform)
payroll_reform = fig.line(x="Axis", y="Payroll Tax", line_color='#abdda4', muted_color='#abdda4',
line_width=2, line_dash='dashed', legend_label='Payroll Tax Liability', muted_alpha=0.1, source=df_reform)
iitax_base.muted = False
payroll_base.muted = False
iitax_reform.muted = False
payroll_reform.muted = False
plot_js = """
object1.visible = toggle.active
object2.visible = toggle.active
"""
base_callback = CustomJS(code=plot_js, args={})
base_toggle = Toggle(label="Base (Solid)", button_type="default",
active=True)
base_callback.args = {"toggle": base_toggle, "object1": iitax_base,
"object2": payroll_base}
base_toggle.js_on_change('active', base_callback)
reform_callback = CustomJS(code=plot_js, args={})
reform_toggle = Toggle(label="Reform (Dashed)", button_type="default",
active=True)
reform_callback.args = {"toggle": reform_toggle, "object1": iitax_reform,
"object2": payroll_reform}
reform_toggle.js_on_change('active', reform_callback)
fig.xaxis.formatter = NumeralTickFormatter(format="$0,000")
fig.xaxis.axis_label = mtr_opt
fig.xaxis.minor_tick_line_color = None
fig.legend.click_policy = "mute"
layout = column(fig, row(base_toggle, reform_toggle))
data = json_item(layout)
outputs = {
"media_type": "bokeh",
"title": "Tax Liabilities by {} (Holding Other Inputs Constant)".format(mtr_opt),
"data": data
}
return outputs
def rate_plot(df_base, df_reform, span, mtr_opt):
0
View Source File : outputs.py
License : MIT License
Project Creator : PSLmodels
License : MIT License
Project Creator : PSLmodels
def rate_plot(df_base, df_reform, span, mtr_opt):
df_base = ColumnDataSource(df_base)
df_reform = ColumnDataSource(df_reform)
tools = "pan, zoom_in, zoom_out, reset"
fig = figure(plot_width=600, plot_height=500,
x_range=(-10000, 300000), y_range=(-0.3, 0.5), tools=tools, active_drag="pan")
fig.yaxis.axis_label = "Tax Rate"
fig.yaxis.formatter = NumeralTickFormatter(format="0%")
filer_income = Span(location=span, dimension='height',
line_color='black', line_dash='dotted', line_width=1.5)
fig.add_layout(filer_income)
label_format = f'{span:,}'
filer_income_label = Label(x=span, y=25, y_units='screen', x_offset=10, text="{}: $".format(mtr_opt) + label_format,
text_color='#303030', text_font="arial", text_font_style="italic", text_font_size="10pt")
fig.add_layout(filer_income_label)
axis = Span(location=0, dimension='width',
line_color='#bfbfbf', line_width=1.5)
fig.add_layout(axis)
iitax_atr_base = fig.line(x="Axis", y="IATR", line_color='#2b83ba', muted_color='#2b83ba',
line_width=2, legend_label="Income Tax Average Rate", muted_alpha=0.1, source=df_base)
payroll_atr_base = fig.line(x="Axis", y="PATR", line_color='#abdda4', muted_color='#abdda4',
line_width=2, legend_label='Payroll Tax Average Rate', muted_alpha=0.1, source=df_base)
iitax_mtr_base = fig.line(x="Axis", y="Income Tax MTR", line_color='#fdae61', muted_color='#fdae61',
line_width=2, legend_label="Income Tax Marginal Rate", muted_alpha=0.1, source=df_base)
payroll_mtr_base = fig.line(x="Axis", y="Payroll Tax MTR", line_color='#d7191c', muted_color='#d7191c',
line_width=2, legend_label='Payroll Tax Marginal Rate', muted_alpha=0.1, source=df_base)
iitax_atr_reform = fig.line(x="Axis", y="IATR", line_color='#2b83ba', muted_color='#2b83ba', line_width=2,
line_dash='dashed', legend_label="Income Tax Average Rate", muted_alpha=0.1, source=df_reform)
payroll_atr_reform = fig.line(x="Axis", y="PATR", line_color='#abdda4', muted_color='#abdda4', line_width=2,
line_dash='dashed', legend_label='Payroll Tax Average Rate', muted_alpha=0.1, source=df_reform)
iitax_mtr_reform = fig.line(x="Axis", y="Income Tax MTR", line_color='#fdae61', muted_color='#fdae61',
line_width=2, line_dash='dashed', legend_label="Income Tax Marginal Rate", muted_alpha=0.1, source=df_reform)
payroll_mtr_reform = fig.line(x="Axis", y="Payroll Tax MTR", line_color='#d7191c', muted_color='#d7191c',
line_width=2, line_dash='dashed', legend_label='Payroll Tax Marginal Rate', muted_alpha=0.1, source=df_reform)
iitax_atr_base.muted = False
iitax_mtr_base.muted = True
payroll_atr_base.muted = True
payroll_mtr_base.muted = True
iitax_atr_reform.muted = False
iitax_mtr_reform.muted = True
payroll_atr_reform.muted = True
payroll_mtr_reform.muted = True
plot_js = """
object1.visible = toggle.active
object2.visible = toggle.active
object3.visible = toggle.active
object4.visible = toggle.active
"""
base_callback = CustomJS(code=plot_js, args={})
base_toggle = Toggle(label="Base (Solid)", button_type="default",
active=True)
base_callback.args = {"toggle": base_toggle, "object1": iitax_atr_base,
"object2": payroll_atr_base, "object3": iitax_mtr_base,
"object4": payroll_mtr_base}
base_toggle.js_on_change('active', base_callback)
reform_callback = CustomJS(code=plot_js, args={})
reform_toggle = Toggle(label="Reform (Dashed)", button_type="default",
active=True)
reform_callback.args = {"toggle": reform_toggle, "object1": iitax_atr_reform,
"object2": payroll_atr_reform, "object3": iitax_mtr_reform,
"object4": payroll_mtr_reform}
reform_toggle.js_on_change('active', reform_callback)
fig.xaxis.formatter = NumeralTickFormatter(format="$0,000")
fig.xaxis.axis_label = mtr_opt
fig.xaxis.minor_tick_line_color = None
fig.legend.click_policy = "mute"
layout = column(fig, row(base_toggle, reform_toggle))
data = json_item(layout)
outputs = {
"media_type": "bokeh",
"title": "Tax Rates by {} (Holding Other Inputs Constant)".format(mtr_opt),
"data": data
}
return outputs
def credit_plot(df_base, df_reform, span, mtr_opt):
0
View Source File : outputs.py
License : MIT License
Project Creator : PSLmodels
License : MIT License
Project Creator : PSLmodels
def credit_plot(df_base, df_reform, span, mtr_opt):
df_base = ColumnDataSource(df_base)
df_reform = ColumnDataSource(df_reform)
tools = "pan, zoom_in, zoom_out, reset"
fig = figure(plot_width=600, plot_height=500, x_range=(
-2500, 70000), tools=tools, active_drag="pan")
filer_income = Span(location=span, dimension='height',
line_color='black', line_dash='dotted', line_width=1.5)
fig.add_layout(filer_income)
label_format = f'{span:,}'
filer_income_label = Label(x=span, y=45, y_units='screen', x_offset=10, text="{}: $".format(mtr_opt) + label_format,
text_color='#303030', text_font="arial", text_font_style="italic", text_font_size="10pt")
fig.add_layout(filer_income_label)
axis = Span(location=0, dimension='width',
line_color='#bfbfbf', line_width=1.5)
fig.add_layout(axis)
eitc_base = fig.line(x="Axis", y="EITC", line_color='#2b83ba', muted_color='#2b83ba',
line_width=2, legend_label="Earned Income Tax Credit", muted_alpha=0.1, source=df_base)
ctc_base = fig.line(x="Axis", y="CTC", line_color='#abdda4', muted_color='#abdda4',
line_width=2, legend_label='Nonrefundable Child Tax Credit', muted_alpha=0.1, source=df_base)
ctc_refund_base = fig.line(x="Axis", y="CTC Refundable", line_color='#fdae61', muted_color='#fdae61',
line_width=2, legend_label='Refundable Child Tax Credit', muted_alpha=0.1, source=df_base)
cdcc_base = fig.line(x="Axis", y="Child care credit", line_color='#d7191c', muted_color='#d7191c',
line_width=2, legend_label='Child and Dependent Care Credit', muted_alpha=0.1, source=df_base)
eitc_reform = fig.line(x="Axis", y="EITC", line_color='#2b83ba', muted_color='#2b83ba', line_width=2,
line_dash='dashed', legend_label="Earned Income Tax Credit", muted_alpha=0.1, source=df_reform)
ctc_reform = fig.line(x="Axis", y="CTC", line_color='#abdda4', muted_color='#abdda4', line_width=2,
line_dash='dashed', legend_label='Nonrefundable Child Tax Credit', muted_alpha=0.1, source=df_reform)
ctc_refund_reform = fig.line(x="Axis", y="CTC Refundable", line_color='#fdae61', muted_color='#fdae61',
line_width=2, line_dash='dashed', legend_label='Refundable Child Tax Credit', muted_alpha=0.1, source=df_reform)
cdcc_reform = fig.line(x="Axis", y="Child care credit", line_color='#d7191c', muted_color='#d7191c', line_width=2,
line_dash='dashed', legend_label='Child and Dependent Care Credit', muted_alpha=0.1, source=df_reform)
ctc_base.muted = True
ctc_refund_base.muted = True
cdcc_base.muted = True
ctc_reform.muted = True
ctc_refund_reform.muted = True
cdcc_reform.muted = True
plot_js = """
object1.visible = toggle.active
object2.visible = toggle.active
object3.visible = toggle.active
object4.visible = toggle.active
"""
base_callback = CustomJS(code=plot_js, args={})
base_toggle = Toggle(label="Base (Solid)", button_type="default",
active=True)
base_callback.args = {"toggle": base_toggle, "object1": eitc_base,
"object2": cdcc_base, "object3": ctc_base,
"object4": ctc_refund_base}
base_toggle.js_on_change('active', base_callback)
reform_callback = CustomJS(code=plot_js, args={})
reform_toggle = Toggle(label="Reform (Dashed)", button_type="default",
active=True)
reform_callback.args = {"toggle": reform_toggle, "object1": eitc_reform,
"object2": cdcc_reform, "object3": ctc_reform,
"object4": ctc_refund_reform}
reform_toggle.js_on_change('active', reform_callback)
fig.yaxis.formatter = NumeralTickFormatter(format="$0,000")
fig.yaxis.axis_label = "Tax Credits"
fig.xaxis.formatter = NumeralTickFormatter(format="$0,000")
fig.xaxis.axis_label = mtr_opt
fig.xaxis.minor_tick_line_color = None
fig.legend.click_policy = "mute"
layout = column(fig, row(base_toggle, reform_toggle))
data = json_item(layout)
outputs = {
"media_type": "bokeh",
"title": "Tax Credits by {} (Holding Other Inputs Constant)".format(mtr_opt),
"data": data
}
return outputs
0
View Source File : restservice.py
License : Apache License 2.0
Project Creator : scaleoutsystems
License : Apache License 2.0
Project Creator : scaleoutsystems
def run(self):
"""
:return:
"""
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['SECRET_KEY'] = self.SECRET_KEY
@app.route('/')
def index():
"""
:return:
"""
not_configured = self.check_configured()
if not_configured:
return not_configured
events = self.control.get_events()
message = request.args.get('message', None)
message_type = request.args.get('message_type', None)
return render_template('events.html', client=self.name, state=ReducerStateToString(self.control.state()),
events=events,
logs=None, refresh=True, configured=True, message=message, message_type=message_type)
# http://localhost:8090/add?name=combiner&address=combiner&port=12080&token=e9a3cb4c5eaff546eec33ff68a7fbe232b68a192
@app.route('/status')
def status():
"""
:return:
"""
return {'state': ReducerStateToString(self.control.state())}
@app.route('/netgraph')
def netgraph():
"""
Creates nodes and edges for network graph
:return: nodes and edges as keys
:rtype: dict
"""
result = {'nodes': [], 'edges': []}
result['nodes'].append({
"id": "reducer",
"label": "Reducer",
"role": 'reducer',
"status": 'active',
"name": 'reducer', #TODO: get real host name
"type": 'reducer',
})
combiner_info = combiner_status()
client_info = client_status()
if len(combiner_info) < 1:
return result
for combiner in combiner_info:
print("combiner info {}".format(combiner_info), flush=True)
try:
result['nodes'].append({
"id": combiner['name'], # "n{}".format(count),
"label": "Combiner ({} clients)".format(combiner['nr_active_clients']),
"role": 'combiner',
"status": 'active', #TODO: Hard-coded, combiner_info does not contain status
"name": combiner['name'],
"type": 'combiner',
})
except Exception as err:
print(err)
for client in client_info['active_clients']:
try:
result['nodes'].append({
"id": str(client['_id']),
"label": "Client",
"role": client['role'],
"status": client['status'],
"name": client['name'],
"combiner": client['combiner'],
"type": 'client',
})
except Exception as err:
print(err)
count = 0
for node in result['nodes']:
try:
if node['type'] == 'combiner':
result['edges'].append(
{
"id": "e{}".format(count),
"source": node['id'],
"target": 'reducer',
}
)
elif node['type'] == 'client':
result['edges'].append(
{
"id": "e{}".format(count),
"source": node['combiner'],
"target": node['id'],
}
)
except Exception as e:
pass
count = count + 1
return result
@app.route('/networkgraph')
def network_graph():
from bokeh.embed import json_item
try:
plot = Plot(self.control.statestore)
result = netgraph()
df_nodes = pd.DataFrame(result['nodes'])
df_edges = pd.DataFrame(result['edges'])
graph = plot.make_netgraph_plot(df_edges, df_nodes)
return json.dumps(json_item(graph, "myplot"))
except:
return ''
@app.route('/events')
def events():
"""
:return:
"""
import json
from bson import json_util
json_docs = []
for doc in self.control.get_events():
json_doc = json.dumps(doc, default=json_util.default)
json_docs.append(json_doc)
json_docs.reverse()
return {'events': json_docs}
@app.route('/add')
def add():
""" Add a combiner to the network. """
if self.token_auth_enabled:
self.authorize(request, app.config.get('SECRET_KEY'))
if self.control.state() == ReducerState.setup:
return jsonify({'status': 'retry'})
# TODO check for get variables
name = request.args.get('name', None)
address = str(request.args.get('address', None))
port = request.args.get('port', None)
# token = request.args.get('token')
# TODO do validation
if port is None or address is None or name is None:
return "Please specify correct parameters."
# Try to retrieve combiner from db
combiner = self.control.network.get_combiner(name)
if not combiner:
# Create a new combiner
import base64
certificate, key = self.certificate_manager.get_or_create(address).get_keypair_raw()
cert_b64 = base64.b64encode(certificate)
key_b64 = base64.b64encode(key)
# TODO append and redirect to index.
import copy
combiner = CombinerInterface(self, name, address, port, copy.deepcopy(certificate), copy.deepcopy(key),
request.remote_addr)
self.control.network.add_combiner(combiner)
combiner = self.control.network.get_combiner(name)
ret = {
'status': 'added',
'certificate': combiner['certificate'],
'key': combiner['key'],
'storage': self.control.statestore.get_storage_backend(),
'statestore': self.control.statestore.get_config(),
}
return jsonify(ret)
@app.route('/eula', methods=['GET', 'POST'])
def eula():
"""
:return:
"""
for r in request.headers:
print("header contains: {}".format(r), flush=True)
return render_template('eula.html', configured=True)
@app.route('/models', methods=['GET', 'POST'])
def models():
"""
:return:
"""
if request.method == 'POST':
# upload seed file
uploaded_seed = request.files['seed']
if uploaded_seed:
from io import BytesIO
a = BytesIO()
a.seek(0, 0)
uploaded_seed.seek(0)
a.write(uploaded_seed.read())
helper = self.control.get_helper()
model = helper.load_model_from_BytesIO(a.getbuffer())
self.control.commit(uploaded_seed.filename, model)
else:
not_configured = self.check_configured()
if not_configured:
return not_configured
h_latest_model_id = self.control.get_latest_model()
model_info = self.control.get_model_info()
return render_template('models.html', h_latest_model_id=h_latest_model_id, seed=True,
model_info=model_info, configured=True)
seed = True
return redirect(url_for('models', seed=seed))
@app.route('/delete_model_trail', methods=['GET', 'POST'])
def delete_model_trail():
"""
:return:
"""
if request.method == 'POST':
from fedn.common.tracer.mongotracer import MongoTracer
statestore_config = self.control.statestore.get_config()
self.tracer = MongoTracer(statestore_config['mongo_config'], statestore_config['network_id'])
try:
self.control.drop_models()
except:
pass
# drop objects in minio
self.control.delete_bucket_objects()
return redirect(url_for('models'))
seed = True
return redirect(url_for('models', seed=seed))
@app.route('/drop_control', methods=['GET', 'POST'])
def drop_control():
"""
:return:
"""
if request.method == 'POST':
self.control.statestore.drop_control()
return redirect(url_for('control'))
return redirect(url_for('control'))
# http://localhost:8090/control?rounds=4&model_id=879fa112-c861-4cb1-a25d-775153e5b548
@app.route('/control', methods=['GET', 'POST'])
def control():
""" Main page for round control. Configure, start and stop global training rounds. """
not_configured = self.check_configured()
if not_configured:
return not_configured
client = self.name
state = ReducerStateToString(self.control.state())
logs = None
refresh = True
if self.remote_compute_context:
try:
self.current_compute_context = self.control.get_compute_context()
except:
self.current_compute_context = None
else:
self.current_compute_context = "None:Local"
if self.control.state() == ReducerState.monitoring:
return redirect(
url_for('index', state=state, refresh=refresh, message="Reducer is in monitoring state"))
if request.method == 'POST':
timeout = float(request.form.get('timeout', 180))
rounds = int(request.form.get('rounds', 1))
task = (request.form.get('task', ''))
clients_required = request.form.get('clients_required', 1)
clients_requested = request.form.get('clients_requested', 8)
# checking if there are enough clients connected to start!
clients_available = 0
for combiner in self.control.network.get_combiners():
try:
combiner_state = combiner.report()
nac = combiner_state['nr_active_clients']
clients_available = clients_available + int(nac)
except Exception as e:
pass
if clients_available < clients_required:
return redirect(url_for('index', state=state,
message="Not enough clients available to start rounds! "
"check combiner client capacity",
message_type='warning'))
validate = request.form.get('validate', False)
if validate == 'False':
validate = False
helper_type = request.form.get('helper', 'keras')
# self.control.statestore.set_framework(helper_type)
latest_model_id = self.control.get_latest_model()
config = {'round_timeout': timeout, 'model_id': latest_model_id,
'rounds': rounds, 'clients_required': clients_required,
'clients_requested': clients_requested, 'task': task,
'validate': validate, 'helper_type': helper_type}
import threading
threading.Thread(target=self.control.instruct, args=(config,)).start()
# self.control.instruct(config)
return redirect(url_for('index', state=state, refresh=refresh, message="Sent execution plan.",
message_type='SUCCESS'))
else:
seed_model_id = None
latest_model_id = None
try:
seed_model_id = self.control.get_first_model()[0]
latest_model_id = self.control.get_latest_model()
except Exception as e:
pass
return render_template('index.html', latest_model_id=latest_model_id,
compute_package=self.current_compute_context,
seed_model_id=seed_model_id,
helper=self.control.statestore.get_framework(), validate=True, configured=True)
client = self.name
state = ReducerStateToString(self.control.state())
logs = None
refresh = False
return render_template('index.html', client=client, state=state, logs=logs, refresh=refresh,
configured=True)
@app.route('/assign')
def assign():
"""Handle client assignment requests. """
if self.token_auth_enabled:
self.authorize(request, app.config.get('SECRET_KEY'))
response = self.check_configured_response()
if response:
return response
name = request.args.get('name', None)
combiner_preferred = request.args.get('combiner', None)
if combiner_preferred:
combiner = self.control.find(combiner_preferred)
else:
combiner = self.control.find_available_combiner()
if combiner is None:
return jsonify({'status': 'retry',
'package': self.package,
'msg': "Failed to assign to a combiner, try again later."})
client = {
'name': name,
'combiner_preferred': combiner_preferred,
'combiner': combiner.name,
'ip': request.remote_addr,
'status': 'available'
}
# Add client to database
self.control.network.add_client(client)
# Return connection information to client
import base64
cert_b64 = base64.b64encode(combiner.certificate)
response = {
'status': 'assigned',
'host': combiner.address,
'package': self.package,
'ip': combiner.ip,
'port': combiner.port,
'certificate': str(cert_b64).split('\'')[1],
'model_type': self.control.statestore.get_framework()
}
return jsonify(response)
@app.route('/infer')
def infer():
"""
:return:
"""
if self.control.state() == ReducerState.setup:
return "Error, not configured"
result = ""
try:
self.control.set_model_id()
except fedn.exceptions.ModelError:
print("Failed to seed control.")
return result
def combiner_status():
""" Get current status reports from all combiners registered in the network.
:return:
"""
combiner_info = []
for combiner in self.control.network.get_combiners():
try:
report = combiner.report()
combiner_info.append(report)
except:
pass
return combiner_info
def client_status():
"""
Get current status of clients (available) from DB compared with client status from all combiners,
update client status to DB and add their roles.
"""
client_info = self.control.network.get_client_info()
combiner_info = combiner_status()
try:
all_active_trainers = []
all_active_validators = []
for client in combiner_info:
active_trainers_str = client['active_trainers']
active_validators_str = client['active_validators']
active_trainers_str = re.sub('[^a-zA-Z0-9-:\n\.]', '', active_trainers_str).replace('name:', ' ')
active_validators_str = re.sub('[^a-zA-Z0-9-:\n\.]', '', active_validators_str).replace('name:', ' ')
all_active_trainers.extend(' '.join(active_trainers_str.split(" ")).split())
all_active_validators.extend(' '.join(active_validators_str.split(" ")).split())
active_trainers_list = [client for client in client_info if client['name'] in all_active_trainers]
active_validators_list = [cl for cl in client_info if cl['name'] in all_active_validators]
all_clients = [cl for cl in client_info]
for client in all_clients:
status = 'offline'
role = 'None'
self.control.network.update_client_data(client, status, role)
all_active_clients = active_validators_list + active_trainers_list
for client in all_active_clients:
status = 'active'
if client in active_trainers_list and client in active_validators_list:
role = 'trainer-validator'
elif client in active_trainers_list:
role = 'trainer'
elif client in active_validators_list:
role = 'validator'
else:
role = 'unknown'
self.control.network.update_client_data(client, status, role)
return {'active_clients': all_clients,
'active_trainers': active_trainers_list,
'active_validators': active_validators_list
}
except:
pass
return {'active_clients': [],
'active_trainers': [],
'active_validators': []
}
@app.route('/metric_type', methods=['GET', 'POST'])
def change_features():
"""
:return:
"""
feature = request.args['selected']
plot = Plot(self.control.statestore)
graphJSON = plot.create_box_plot(feature)
return graphJSON
@app.route('/dashboard')
def dashboard():
"""
:return:
"""
not_configured = self.check_configured()
if not_configured:
return not_configured
plot = Plot(self.control.statestore)
try:
valid_metrics = plot.fetch_valid_metrics()
box_plot = plot.create_box_plot(valid_metrics[0])
except Exception as e:
valid_metrics = None
box_plot = None
print(e, flush=True)
table_plot = plot.create_table_plot()
# timeline_plot = plot.create_timeline_plot()
timeline_plot = None
clients_plot = plot.create_client_plot()
return render_template('dashboard.html', show_plot=True,
box_plot=box_plot,
table_plot=table_plot,
timeline_plot=timeline_plot,
clients_plot=clients_plot,
metrics=valid_metrics,
configured=True
)
@app.route('/network')
def network():
"""
:return:
"""
not_configured = self.check_configured()
if not_configured:
return not_configured
plot = Plot(self.control.statestore)
round_time_plot = plot.create_round_plot()
mem_cpu_plot = plot.create_cpu_plot()
combiners_plot = plot.create_combiner_plot()
combiner_info = combiner_status()
active_clients = client_status()
return render_template('network.html', network_plot=True,
round_time_plot=round_time_plot,
mem_cpu_plot=mem_cpu_plot,
combiners_plot=combiners_plot,
combiner_info=combiner_info,
active_clients=active_clients['active_clients'],
active_trainers=active_clients['active_trainers'],
active_validators=active_clients['active_validators'],
configured=True
)
@app.route('/config/download', methods=['GET'])
def config_download():
"""
:return:
"""
chk_string = ""
name = self.control.get_compute_context()
if name is None or name == '':
chk_string = ''
else:
file_path = os.path.join(UPLOAD_FOLDER, name)
print("trying to get {}".format(file_path))
from fedn.utils.checksum import md5
try:
sum = str(md5(file_path))
except FileNotFoundError as e:
sum = ''
chk_string = "checksum: {}".format(sum)
network_id = self.network_id
discover_host = self.name
discover_port = self.port
ctx = """network_id: {network_id}
controller:
discover_host: {discover_host}
discover_port: {discover_port}
{chk_string}""".format(network_id=network_id,
discover_host=discover_host,
discover_port=discover_port,
chk_string=chk_string)
from io import BytesIO
from flask import send_file
obj = BytesIO()
obj.write(ctx.encode('UTF-8'))
obj.seek(0)
return send_file(obj,
as_attachment=True,
attachment_filename='client.yaml',
mimetype='application/x-yaml')
@app.route('/context', methods=['GET', 'POST'])
def context():
"""
:return:
"""
# if self.control.state() != ReducerState.setup or self.control.state() != ReducerState.idle:
# return "Error, Context already assigned!"
reset = request.args.get('reset', None) # if reset is not empty then allow context re-set
if reset:
return render_template('context.html')
if request.method == 'POST':
if 'file' not in request.files:
flash('No file part')
return redirect(url_for('context'))
file = request.files['file']
helper_type = request.form.get('helper', 'keras')
# if user does not select file, browser also
# submit an empty part without filename
if file.filename == '':
flash('No selected file')
return redirect(url_for('context'))
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(file_path)
if self.control.state() == ReducerState.instructing or self.control.state() == ReducerState.monitoring:
return "Not allowed to change context while execution is ongoing."
self.control.set_compute_context(filename, file_path)
self.control.statestore.set_framework(helper_type)
return redirect(url_for('control'))
from flask import send_from_directory
name = request.args.get('name', '')
if name == '':
name = self.control.get_compute_context()
if name == None or name == '':
return render_template('context.html')
# There is a potential race condition here, if one client requests a package and at
# the same time another one triggers a fetch from Minio and writes to disk.
try:
mutex = Lock()
mutex.acquire()
return send_from_directory(app.config['UPLOAD_FOLDER'], name, as_attachment=True)
except:
try:
data = self.control.get_compute_package(name)
file_path = os.path.join(app.config['UPLOAD_FOLDER'], name)
with open(file_path, 'wb') as fh:
fh.write(data)
return send_from_directory(app.config['UPLOAD_FOLDER'], name, as_attachment=True)
except:
raise
finally:
mutex.release()
return render_template('context.html')
@app.route('/checksum', methods=['GET', 'POST'])
def checksum():
"""
:return:
"""
# sum = ''
name = request.args.get('name', None)
if name == '' or name is None:
name = self.control.get_compute_context()
if name == None or name == '':
return jsonify({})
file_path = os.path.join(UPLOAD_FOLDER, name)
print("trying to get {}".format(file_path))
from fedn.utils.checksum import md5
try:
sum = str(md5(file_path))
except FileNotFoundError as e:
sum = ''
data = {'checksum': sum}
from flask import jsonify
return jsonify(data)
if self.certificate:
print("trying to connect with certs {} and key {}".format(str(self.certificate.cert_path),
str(self.certificate.key_path)), flush=True)
app.run(host="0.0.0.0", port=self.port,
ssl_context=(str(self.certificate.cert_path), str(self.certificate.key_path)))
return app
0
View Source File : analyze.py
License : GNU General Public License v3.0
Project Creator : varadaio
License : GNU General Public License v3.0
Project Creator : varadaio
def main():
p = argparse.ArgumentParser()
p.add_argument(
"-i",
"--input-file",
type=pathlib.Path,
help="Path to the extracted JSONL file (the output of extract.py)",
)
p.add_argument(
"-o",
"--output-file",
type=pathlib.Path,
default="./output.zip",
help="Path to the resulting zipped HTML report",
)
p.add_argument("-l", "--limit", type=int)
p.add_argument("--filter", type=str)
p.add_argument("--fail-on-error", action="store_true", default=False)
p.add_argument("--high-contrast-mode", action="store_true", default=False)
p.add_argument("-q", "--quiet", action="store_true", default=False)
args = p.parse_args()
log.info(
"loading {} = {:.3f} MB", args.input_file, args.input_file.stat().st_size / 1e6
)
if args.input_file.name.endswith(".gz"):
lines = gzip.open(args.input_file.open("rb"), "rt")
else:
lines = args.input_file.open("rt")
if args.limit:
lines = itertools.islice(lines, args.limit)
lines = list(lines)
stats = []
for line in tqdm(lines, unit="files", disable=args.quiet):
s = json.loads(line)
if s["state"] == "FAILED":
continue
stats.append(s)
log.info("{} queries loaded", len(stats))
metrics = collect_metrics(stats)
charts = []
scripts = []
for func in tqdm(_ANALYZERS, unit="graphs", disable=args.quiet):
graph_id = func.__name__
if args.filter is None or args.filter == func.__name__:
try:
if 'colorblind' in signature(func).parameters:
p = func(stats, colorblind=args.high_contrast_mode)
else:
p = func(stats)
if p is None:
log.warn("not enough data for {}", graph_id)
continue
item = json_item(model=p, target=graph_id)
item["doc"]["roots"]["references"].sort(key=lambda r: (r["type"], r["id"]))
item = json.dumps({"doc": item["doc"]})
scripts.append(
' < script type="application/json" id="{}">\n{}\n < /script>\n'.format(
graph_id, item
)
)
charts.append(
{
"title": p.title.text or graph_id,
"description": func.__doc__.strip(),
"id": graph_id,
}
)
except Exception:
log.exception("failed to generate {}", graph_id)
if args.fail_on_error:
raise
scripts.append(
" < script>\nconst structure = {} < /script>".format(
json.dumps({"metrics": metrics, "charts": charts}, indent=4)
)
)
template = pathlib.Path(__file__).parent / "output.template.html"
placeholder = " < !-- PLACEHOLDER_FOR_BOKEH_JSONS -->"
output = template.open().read().replace(placeholder, "\n".join(scripts))
log.info("report is written to {}", args.output_file)
suffix = args.output_file.suffix
if suffix == ".zip":
with zipfile.ZipFile(args.output_file, "w") as f:
f.writestr("output.html", data=output, compress_type=zipfile.ZIP_DEFLATED)
elif suffix == ".html":
with open(args.output_file, "w") as f:
f.write(output)
else:
raise ValueError("Unsupport output file extension: {}".format(args.output_file))
if __name__ == "__main__":