def plotCommunity(self,colorscale=False): #make copy of node dataframe df_temp = self.node_df.copy() #change community label to string (needed for plot) df_temp['community'] = df_temp['community'].map(lambda x: str(x)) #conditionals for plot type if colorscale == False: fig = px.sunburst(df_temp, path=['community', 'id'], values='adjacency_frequency',color='community',hover_name=None, hover_data=None) else: fig = px.sunburst(df_temp, path=['community', 'id'], values='adjacency_frequency', color='betweeness_centrality', hover_data=None, color_continuous_scale='blugrn', color_continuous_midpoint=np.average(df_temp['betweeness_centrality'], weights=df_temp['betweeness_centrality'])) #add margin to plot fig.update_layout(margin = dict(t=0, l=0, r=0, b=0)) #retain community plot as attribute self.community_plot = fig #offline sunburst plot iplot(self.community_plot) return
def getSunburst(path, channel, style): df = pd.read_csv(path + channel + '.csv') df['Time'] = pd.to_datetime(df['Time']) import calendar df['month'] = pd.DatetimeIndex(df['Time']).month df_new = df.groupby(['month', 'Source', 'Target' ]).size().reset_index().rename(columns={0: 'count'}) df_new['month'] = df['month'].apply(lambda x: calendar.month_abbr[x]) #fig1 = px.sunburst(df_new, path=['Source','month', 'Target'], values=df_new['count'], color='month',color_continuous_scale='RdBu') #fig2 = px.sunburst(df_new, path=['month','Source', 'Target'], values=df_new['count'], color='month',color_continuous_scale='RdBu') if style == 1: return px.sunburst(df_new, path=['Source', 'month', 'Target'], values=df_new['count'], color='Source', color_continuous_scale='RdBu') elif style == 2: return px.sunburst(df_new, path=['month', 'Source', 'Target'], values=df_new['count'], color='month', color_continuous_scale='RdBu') else: return px.sunburst(df_new, path=['Target', 'month', 'Source'], values=df_new['count'], color='Target', color_continuous_scale='RdBu')
def test_sunburst_treemap_with_path_and_hover(): df = px.data.tips() fig = px.sunburst(df, path=["sex", "day", "time", "smoker"], color="smoker", hover_data=["smoker"]) assert "smoker" in fig.data[0].hovertemplate df = px.data.gapminder().query("year == 2007") fig = px.sunburst(df, path=["continent", "country"], color="lifeExp", hover_data=df.columns) assert fig.layout.coloraxis.colorbar.title.text == "lifeExp" df = px.data.tips() fig = px.sunburst(df, path=["sex", "day", "time", "smoker"], hover_name="smoker") assert "smoker" not in fig.data[ 0].hovertemplate # represented as '%{hovertext}' assert "%{hovertext}" in fig.data[ 0].hovertemplate # represented as '%{hovertext}' df = px.data.tips() fig = px.sunburst(df, path=["sex", "day", "time", "smoker"], custom_data=["smoker"]) assert fig.data[0].customdata[0][0] in ["Yes", "No"] assert "smoker" not in fig.data[0].hovertemplate assert "%{hovertext}" not in fig.data[0].hovertemplate
def test_sunburst_treemap_column_parent(): vendors = ["A", "B", "C", "D", "E", "F", "G", "H"] sectors = [ "Tech", "Tech", "Finance", "Finance", "Tech", "Tech", "Finance", "Finance", ] regions = [ "North", "North", "North", "North", "South", "South", "South", "South" ] values = [1, 3, 2, 4, 2, 2, 1, 4] df = pd.DataFrame( dict( id=vendors, sectors=sectors, parent=regions, values=values, )) path = ["parent", "sectors", "id"] # One column of the path is a reserved name - this is ok and should not raise px.sunburst(df, path=path, values="values")
def sunburst(self, title, colorscale=False, color_col='betweeness_centrality', color_continuous_scale='Oryel', width=1100, height=1100, save=False) -> px.sunburst: """Plots of sunburst chart Args: title (str): title of plot colorscale (bool): Size of the maker color_col (str): Color-coded column names. color_continuous_scale (str): cf.https://plotly.com/python/builtin-colorscales/ width (int): width of the graph height (int): height of the graph save (bool): Whether or not to save the HTML file. Returns: px.sunburst: Figure of a sunburst graph """ # make copy of node dataframe _df = self.node_df.copy() # change community label to string (needed for plot) _df.loc[:, 'community'] = _df['community'].map(lambda x: str(x)) # conditionals for plot type if colorscale is False: fig = px.sunburst(_df, path=['community', 'id'], values='adjacency_frequency', color='community', hover_name=None, hover_data=None) else: fig = px.sunburst(_df, path=['community', 'id'], values='adjacency_frequency', color=color_col, hover_data=None, color_continuous_scale=color_continuous_scale, color_continuous_midpoint=np.average( _df[color_col], weights=_df[color_col])) fig.update_layout( title=str(title), width=width, height=height, ) if save: self.save_plot(fig, title) del _df gc.collect() return fig
def plot_sunbirst_charts(solved_data: pd.DataFrame): sb1 = px.sunburst(solved_data, values="expense", path=["type", "entity"])._data sb2 = px.sunburst( solved_data[solved_data["solution"] == 1], values="expense", path=["type", "entity"], )._data # use data and structure FROM sb1 and sb2 (trick) fig = make_subplots(rows=1, cols=2, specs=[[{ "type": "domain" }, { "type": "domain" }]]) fig.add_trace( go.Sunburst( branchvalues="total", labels=sb1[0]["labels"], parents=sb1[0]["parents"], values=sb1[0]["values"], ), 1, 1, ) fig.add_trace( go.Sunburst( branchvalues="total", labels=sb2[0]["labels"], parents=sb2[0]["parents"], values=sb2[0]["values"], ), 1, 2, ) fig.update_layout( title_text="Expenses distribution in solution, sunbirst chart", # Add annotations in the center of the donut pies. annotations=[ dict(text="Original", x=0.17, y=1.1, font_size=20, showarrow=False), dict(text="Optimized", x=0.84, y=1.1, font_size=20, showarrow=False), ], ) # fig = go.Figure(data = [trace1, trace2], layout = layout) fig.show()
def sunburst_interactive(count_dict,lexique,lexique_class_labels): df_viz = pd.DataFrame(count_dict.items(),columns=("word","freq")) class_dict = dict(lexique["word class".split()].values) if lexique_class_labels: df_viz["class"] = df_viz.word.apply(lambda x:lexique_class_labels[class_dict[x]]) fig = px.sunburst(df_viz, path=["class",'word'], values='freq') else: fig = px.sunburst(df_viz, path=['word'], values='freq') return fig
def refresh_overview_zone_chart(jsonified_cleaned_data,clickData,selected_axis): # Init chart when none click if json.dumps(clickData,indent=2) == "null": return px.sunburst(), None, None # Axe definition geo_axis = "ZONE" if selected_axis == 'Statut des PDVs': analysis_axis = 'POS_STATUS' else: analysis_axis = 'IMPACT_VISITE' # Clicked DACR if clickData['points'][0]['currentPath'] == '/': dacr_name = clickData['points'][0]['id'] elif clickData['points'][0]['currentPath'] in ['/Agadez/','/Diffa/','/Dosso/','/Maradi/','/Niamey/','/Tahoua/','/Tillaberi/','/Zinder/']: dacr_name = clickData['points'][0]['parent'] else: dacr_name = "Agadez" # load pos data df2 = pd.read_json(jsonified_cleaned_data) df2 = df2[df2['DACR'] == dacr_name] filtered_data = df2.to_json() # AGG DATA dacr_data = ( df2 .groupby(['MONTH','DACR',geo_axis,analysis_axis]) .agg({"POS" : "nunique"}) .reset_index() .rename(columns={"POS" : "NOMBRE DE PDVs"}) # .pivot(index="DACR",columns='POS_STATUS',values='POS_CNT') # .reset_index() ) # Chart color dict if selected_axis == 'Statut des PDVs': chart_color_dict = {x:status_markers_colors[x] for x in dacr_data[analysis_axis]} else: chart_color_dict = {x:impact_markers_colors[x] for x in dacr_data[analysis_axis]} fig = px.sunburst( dacr_data, path=[geo_axis, analysis_axis], values='NOMBRE DE PDVs', color=analysis_axis, color_discrete_map=chart_color_dict # hovertemplate='<extra>{fullData.DACR}</extra>' ) fig.update_layout(margin = dict(t=5, l=5, r=5, b=5)) return fig,filtered_data, "Zones de {0}: ".format(dacr_name)
def refresh_overview_sector_chart(jsonified_cleaned_data,clickData,selected_axis): # Init chart when none click if json.dumps(clickData,indent=2) == "null": return px.sunburst(), None # Axis definition geo_axis = "SECTEUR" if selected_axis == 'Statut des PDVs': analysis_axis = 'POS_STATUS' else: analysis_axis = 'IMPACT_VISITE' # Clicked DACR if clickData['points'][0]['currentPath'] == '/': zone_name = clickData['points'][0]['id'] else: zone_name = clickData['points'][0]['parent'] # load pos data df2 = pd.read_json(jsonified_cleaned_data) df2 = df2[df2['ZONE'] == zone_name] dacr_name = list(df2['DACR'].unique())[0] # AGG DATA zone_data = ( df2 .groupby(['MONTH','DACR',geo_axis,analysis_axis]) .agg({"POS" : "nunique"}) .reset_index() .rename(columns={"POS" : "NOMBRE DE PDVs"}) # .pivot(index="DACR",columns='POS_STATUS',values='POS_CNT') # .reset_index() ) # Chart color dict if selected_axis == 'Statut des PDVs': chart_color_dict = {x:status_markers_colors[x] for x in zone_data[analysis_axis]} else: chart_color_dict = {x:impact_markers_colors[x] for x in zone_data[analysis_axis]} fig = px.sunburst( zone_data, path=[geo_axis, analysis_axis], values='NOMBRE DE PDVs', color=analysis_axis, color_discrete_map=chart_color_dict # hovertemplate='<extra>{fullData.DACR}</extra>' ) fig.update_layout(margin = dict(t=5, l=5, r=5, b=5)) return fig, "Secteurs de {0} {1}: ".format(dacr_name,zone_name)
def test_sunburst_treemap_with_path_color(): vendors = ["A", "B", "C", "D", "E", "F", "G", "H"] sectors = [ "Tech", "Tech", "Finance", "Finance", "Tech", "Tech", "Finance", "Finance", ] regions = ["North", "North", "North", "North", "South", "South", "South", "South"] values = [1, 3, 2, 4, 2, 2, 1, 4] calls = [8, 2, 1, 3, 2, 2, 4, 1] total = ["total",] * 8 df = pd.DataFrame( dict( vendors=vendors, sectors=sectors, regions=regions, values=values, total=total, calls=calls, ) ) path = ["total", "regions", "sectors", "vendors"] fig = px.sunburst(df, path=path, values="values", color="calls") colors = fig.data[0].marker.colors assert np.all(np.array(colors[:8]) == np.array(calls)) fig = px.sunburst(df, path=path, color="calls") colors = fig.data[0].marker.colors assert np.all(np.array(colors[:8]) == np.array(calls)) # Hover info df["hover"] = [el.lower() for el in vendors] fig = px.sunburst(df, path=path, color="calls", hover_data=["hover"]) custom = fig.data[0].customdata assert np.all(custom[:8, 0] == df["hover"]) assert np.all(custom[8:, 0] == "(?)") assert np.all(custom[:8, 1] == df["calls"]) # Discrete color fig = px.sunburst(df, path=path, color="vendors") assert len(np.unique(fig.data[0].marker.colors)) == 9 # Numerical column in path df["regions"] = df["regions"].map({"North": 1, "South": 2}) path = ["total", "regions", "sectors", "vendors"] fig = px.sunburst(df, path=path, values="values", color="calls") colors = fig.data[0].marker.colors assert np.all(np.array(colors[:8]) == np.array(calls))
def draw(self): """ Generate SunBurstChart visualization """ label_column, numerical_var = self._check_requirements() if numerical_var is not None: #plot fig = px.sunburst(self.dataframe, values=numerical_var, path=label_column) fig.show() else: fig = px.sunburst(self.dataframe, path=label_column) fig.show()
def makeSunburstCharts(DN_DF): # DN_DF = DN_DF[DN_DF['DT Hemisphere'] != "check DT"] DN_DF_FindSoma_Filter = DN_DF[DN_DF['Soma Hemisphere'] != "FindSoma"] DN_DF_RightDT = DN_DF_FindSoma_Filter[DN_DF_FindSoma_Filter['DT Hemisphere'] == "Right"] fig = px.sunburst(DN_DF_FindSoma_Filter, path=['DT Hemisphere', 'Soma Hemisphere', 'DN Type'], title="Both DT - Soma Hem - DN Type") py.plot(fig, filename="Both DT - Soma Hem - DN Type") DN_DF_RightDT.Classification = DN_DF_RightDT['Classification'].fillna('No Classification') fig = px.sunburst(DN_DF_RightDT, path=['Soma Hemisphere', 'DN Type', 'Classification'], title="Right DT - Soma Hem - DN Type - Classification") py.plot(fig, filename="Right DT - Soma Hem - DN Type - Classification") return
def exibe_instrucao(cpf): st.subheader("Considerando o grau de instrução") parlamentar = df_parlamentares[df_parlamentares["CPF"] == cpf] grau = parlamentar["DS_GRAU_INSTRUCAO"].iloc[0] uf = parlamentar["SG_UE"].iloc[0] x_brasil = pd.crosstab(index=[df_parlamentares['DS_GRAU_INSTRUCAO']], columns=[df_parlamentares['DS_GRAU_INSTRUCAO']], normalize=True).T perc_brasil = x_brasil[grau][grau].round(3) * 100 x_estado = pd.crosstab(index=[df_parlamentares['DS_GRAU_INSTRUCAO']], columns=[ df_parlamentares[df_parlamentares["SG_UE"] == uf]['DS_GRAU_INSTRUCAO'] ], normalize=True).T perc_estado = x_estado[grau][grau].round(3) * 100 st.write( "Faz parte dos {}% dos parlamentares com {} no Brasil, {}% no estado {}." .format(perc_brasil.round(1), grau.lower(), perc_estado.round(1), uf)) df_instruc = df_parlamentares[[ "CPF", "NM_CANDIDATO", "SG_UE", "SG_PARTIDO", "DS_GRAU_INSTRUCAO" ]].copy() df_instruc = df_instruc[df_instruc["SG_UE"] == uf].copy() data = df_instruc fig = px.sunburst(data, path=['SG_UE', "DS_GRAU_INSTRUCAO", "NM_CANDIDATO"]) st.plotly_chart(fig, use_container_width=True) # # return
def exibe_estado_civil(cpf): st.subheader("Considerando o Estado Civil") parlamentar = df_parlamentares[df_parlamentares["CPF"] == cpf] civil = parlamentar["DS_ESTADO_CIVIL"].iloc[0] uf = parlamentar["SG_UE"].iloc[0] x_brasil = pd.crosstab(index=[df_parlamentares['DS_ESTADO_CIVIL']], columns=[df_parlamentares['DS_ESTADO_CIVIL']], normalize=True).T perc_brasil = x_brasil[civil][civil].round(3) * 100 x_estado = pd.crosstab(index=[df_parlamentares['DS_ESTADO_CIVIL']], columns=[ df_parlamentares[df_parlamentares["SG_UE"] == uf]['DS_ESTADO_CIVIL'] ], normalize=True).T perc_estado = x_estado[civil][civil].round(3) * 100 st.write( "Faz parte dos {}% dos parlamentares com estado civil {} no Brasil, {}% no estado {}." .format(perc_brasil.round(1), civil.lower(), perc_estado.round(1), uf)) df_civil = df_parlamentares[[ "CPF", "NM_CANDIDATO", "SG_UE", "SG_PARTIDO", "DS_ESTADO_CIVIL" ]].copy() df_civil = df_civil[df_civil["SG_UE"] == uf].copy() data = df_civil fig = px.sunburst(data, path=['SG_UE', "DS_ESTADO_CIVIL", "NM_CANDIDATO"]) st.plotly_chart(fig, use_container_width=True) # # return
def exibe_cor(cpf): st.subheader("Considerando a cor declarada") parlamentar = df_parlamentares[df_parlamentares["CPF"] == cpf] cor = parlamentar["DS_COR_RACA"].iloc[0] uf = parlamentar["SG_UE"].iloc[0] x_brasil = pd.crosstab(index=[df_parlamentares['DS_COR_RACA']], columns=[df_parlamentares['DS_COR_RACA']], normalize=True).T perc_brasil = x_brasil[cor][cor].round(3) * 100 x_estado = pd.crosstab( index=[df_parlamentares['DS_COR_RACA']], columns=[ df_parlamentares[df_parlamentares["SG_UE"] == uf]['DS_COR_RACA'] ], normalize=True).T perc_estado = x_estado[cor][cor].round(3) * 100 st.write( "Faz parte dos {}% dos parlamentares de cor {} no Brasil e {}% do estado {}." .format(perc_brasil.round(1), cor.lower(), perc_estado.round(1), uf)) df_cor = df_parlamentares[[ "CPF", "NM_CANDIDATO", "SG_UE", "SG_PARTIDO", "DS_COR_RACA" ]].copy() df_cor = df_cor[df_cor["SG_UE"] == uf].copy() data = df_cor fig = px.sunburst(data, path=['SG_UE', "DS_COR_RACA", "NM_CANDIDATO"]) st.plotly_chart(fig, use_container_width=True) # # return
def exibe_genero(cpf): st.subheader("Considerando o gênero") parlamentar = df_parlamentares[df_parlamentares["CPF"] == cpf] genero = parlamentar["DS_GENERO"].iloc[0] uf = parlamentar["SG_UE"].iloc[0] gen_brasil = pd.crosstab(index=[df_parlamentares['DS_GENERO']], columns=[df_parlamentares['DS_GENERO']], normalize=True).T perc_brasil = (gen_brasil[genero][genero]) * 100 gen_estado = pd.crosstab( index=[df_parlamentares['DS_GENERO']], columns=[ df_parlamentares[df_parlamentares["SG_UE"] == uf]['DS_GENERO'] ], normalize=True).T perc_estado = (gen_estado[genero][genero]) * 100 st.write( "Faz parte dos {}% dos parlamentares do sexo {} no Brasil e {}% do estado {}." .format(perc_brasil.round(1), genero.lower(), perc_estado.round(1), uf)) df_genero = df_parlamentares[[ "CPF", "NM_CANDIDATO", "SG_UE", "SG_PARTIDO", "DS_GENERO" ]].copy() df_genero = df_genero[df_genero["SG_UE"] == uf].copy() data = df_genero fig = px.sunburst(data, path=['SG_UE', "DS_GENERO", "NM_CANDIDATO"]) st.plotly_chart(fig, use_container_width=True) # # return
def update_current_ratio(entity): ticker = Ticker(entity) df = ticker.balance_sheet() print("df: ", df) df = df.reset_index(drop=True) cols = df.columns totalCurrentAssets = df["totalCurrentAssets"][0] totalCurrentLiabilities = df["totalCurrentLiabilities"][0] ratio = float(totalCurrentAssets) / float(totalCurrentLiabilities) if ratio > 2: financial_status = "Conservatively financed" elif ratio > 1: financial_status = "Be careful" else: financial_status = "indebted" data = dict( asset_and_liability=[financial_status, "totalCurrentAssets", "totalCurrentLiabilities"], parent=["", financial_status, financial_status], value=[ratio, totalCurrentAssets, totalCurrentLiabilities] ) fig = px.sunburst( data, names='asset_and_liability', parents='parent', values='value', ) return fig
def test_pie_like_px(): # Pie labels = ["Oxygen", "Hydrogen", "Carbon_Dioxide", "Nitrogen"] values = [4500, 2500, 1053, 500] fig = px.pie(names=labels, values=values) trace = go.Pie(labels=labels, values=values) _compare_figures(trace, fig) labels = [ "Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura" ] parents = ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve"] values = [10, 14, 12, 10, 2, 6, 6, 4, 4] # Sunburst fig = px.sunburst(names=labels, parents=parents, values=values) trace = go.Sunburst(labels=labels, parents=parents, values=values) _compare_figures(trace, fig) # Treemap fig = px.treemap(names=labels, parents=parents, values=values) trace = go.Treemap(labels=labels, parents=parents, values=values) _compare_figures(trace, fig) # Funnel x = ["A", "B", "C"] y = [3, 2, 1] fig = px.funnel(y=y, x=x) trace = go.Funnel(y=y, x=x) _compare_figures(trace, fig) # Funnelarea fig = px.funnel_area(values=y, names=x) trace = go.Funnelarea(values=y, labels=x) _compare_figures(trace, fig)
def draw_fig_ad(df_yesterday): # sunburst for ad click df_yesterday_ad = df_yesterday.iloc[:, [1, -2, -1]].groupby( '訪問網站').sum().reset_index().melt(id_vars=["訪問網站"], var_name="行為", value_name="人次") fig_ad = px.sunburst( df_yesterday_ad, path=['訪問網站', '行為'], # 分類變數 values='人次', # 面積依據資料 color='訪問網站', # 分色變數 # hover_data=['訪問網站'], # 游標顯示資料 ) fig_ad.update_traces(marker=dict( # colors=themeColor, line=dict(color='#ffffff', width=2))) fig_ad.update_layout( margin=dict(l=10, r=10, t=10, b=10), # 圖形在畫布的邊界設定 paper_bgcolor="rgba(0,0,0,0)", # 畫布背景顏色 plot_bgcolor="rgba(0,0,0,0)", # 圖形背景顏色 autosize=True, # 自動調整大小 font_color='white', # 文字顏色 font_size=20, # 文字大小 font_family='Microsoft JhengHei', # 字體 ) return fig_ad
def test_sunburst_treemap_with_path_and_hover(): df = px.data.tips() fig = px.sunburst(df, path=["sex", "day", "time", "smoker"], color="smoker", hover_data=["smoker"]) assert "smoker" in fig.data[0].hovertemplate
def plot_sunburst( df: pd.DataFrame, col: str, path: List[str]=['state_id', 'store_id', 'cat_id', 'dept_id'], color_discrete_sequence: List[str]=px.colors.qualitative.Prism ) -> go.Figure: """ Expected columns: - 'state_id' - 'store_id' - 'cat_id' - 'dept_id' - col """ fig = px.sunburst( df, path=path, values=col, color_discrete_sequence=color_discrete_sequence ) fig.update_layout( title='USD sales repartition', height=1000 ) return fig
def plot(drive): # The drive itself sections = [drive.name] parents = [''] values = [drive.disk_size] # Game libraries on the drive #library_names = [f'{library[0]} ({len(drive.game_sizes[i])} games)' for i, library in enumerate(drive.game_libraries)] library_names = [library[0] for library in drive.game_libraries] sections.extend(library_names) parents.extend((len(library_names)) * [drive.name]) values.extend(drive.game_library_sizes) # OS/other apps and free space sections.extend(['Other', 'Free Space']) parents.extend(2 * [drive.name]) values.append(round(drive.disk_usage - sum(drive.game_library_sizes), 1)) values.append(round(drive.disk_size - drive.disk_usage, 1)) # Games for i, library_name in enumerate(library_names): for game in drive.game_sizes[i]: sections.append(game[0]) parents.append(library_name) values.append(game[1]) data = dict(sections=sections, parents=parents, values=values) fig = px.sunburst(data, names='sections', parents='parents', values='values', branchvalues='total') fig.show()
def update_graph(value, df): df = df.query("year == {}".format(value)) # no JSON de-serialization here return px.sunburst(df, path=['continent', 'country'], values='pop', color='lifeExp', hover_data=['iso_alpha'])
def sunburstgraph(self, df): fig = px.sunburst( df, path=['Continent', 'sex', 'age'], values='suicides_no', title="Suicides with respect to Continent, Sex and Age") return fig
def make_sunburst_plot(clickData=None, toAdd=None, col=None, val=None): if clickData != None: col = clickData["points"][0]['x'].split(": ")[0] val = clickData["points"][0]['x'].split(": ")[1] elif col == None: col = 'Thickness Material A' val = '47' desc = list(descriptors[:-2]) if col in desc: desc.remove(col) if toAdd != None: for item in toAdd: desc.append(item) test = production_df.loc[production_df[col] == val] fig = px.sunburst(test, path=desc[:], color='Adjusted EBITDA', title='{}: {}'.format( col, val), color_continuous_scale=px.colors.sequential.Viridis) fig.update_layout({ "plot_bgcolor": "#F9F9F9", "title": '(Select in Violin) {}: {}'.format(col,val), "paper_bgcolor": "#F9F9F9", "height": 400, "margin": dict( l=0, r=0, b=0, t=30, pad=4 ), }) return fig