Projet2024/Projet_data_viz_CZSS
0
1import seaborn as sns2import pandas as pd3import numpy as np 4from shared import uc, scoring, encodage_sfdr, encodage_devise5import plotly.graph_objects as go6import plotly.express as px7import plotly.figure_factory as ff8from shiny import App, render, ui, reactive, req9from shinywidgets import output_widget, render_widget 10import shinyswatch11from faicons import icon_svg as icon12from datatable import dt, f, by, g, join, sort, update, ifelse, rowsum, rowmean,math, min, max, median13 14page_presentation = ui.page_fluid(15 ui.div(16 ui.h3("Bienvenue sur votre application d'analyse et de visualisation des données !"),17 ui.p(18 """19 Cette plateforme vous permet d'explorer, d'analyser et de visualiser en profondeur 20 les performances des unités de compte (UC) en fonction de divers critères. 21 Voici un aperçu des principales fonctionnalités disponibles :22 """23 ),24 ui.tags.ul(25 ui.tags.li("Analyse des données : Parcourez et filtrez les données des UC selon des critères spécifiques comme le SRI, les critères ESG, les frais, et bien plus."),26 ui.tags.li("Gestion des Marchés Cibles : Définissez et personnalisez des marchés cibles en fonction de vos besoins. Créez, modifiez ou supprimez des segments et visualisez les UC qui répondent aux critères définis."),27 ui.tags.li("Scoring et évaluation : Analysez les scores des UC en fonction de facteurs clés tels que les rendements, les frais et les prix. Paramétrez vos critères de scoring pour adapter les évaluations à vos besoins."),28 ui.tags.li("Visualisations interactives : Explorez les données grâce à des graphiques dynamiques :"),29 ui.tags.ul(30 ui.tags.li("Des nuages de points pour comparer les performances globales des UC."),31 ui.tags.li("Des histogrammes et des courbes de densité pour visualiser les distributions des scores."),32 ui.tags.li("Des graphiques en bulles pour explorer les corrélations entre critères."),33 ),34 ui.tags.li("Vue globale : Obtenez un aperçu des scores moyens et des corrélations entre les UC de différents groupes ou marchés cibles."),35 ui.tags.li("Pensez à visiter toutes les pages dans l'ordre ! "),36 ui.tags.li("Les données proviennent d'un scrapping simple de Boursorama")37 ),38 style="padding: 2rem; background-color: #f8f8f8; border-radius: 10px; border: 1px solid #ccc;"39 )40)41 42 43page_uc = ui.div(ui.page_navbar(44 ui.nav_panel('Info', page_presentation),45 ui.nav_panel("marché cible",46 ui.page_sidebar(47 ui.sidebar(48 ui.div(ui.input_action_button("uc_pg_add", "Ajouter un marché cible")),49 ui.div(ui.input_action_button("uc_pg_del", "Supprimer un marché cible")),50 title=ui.div(icon('gear'), 'Gestion des marché cible', style = 'display : line'),51 52 ),53 ui.div(ui.div(ui.h6('Listing des marché cible'),style = 'padding-left : 10px;'),54 ui.output_data_frame("uc_grid_pg__"),55 style = 'width : 100%; height : 30vh; border: 1px solid; border-color : darkgrey; border-radius : 10px; margin-top: -15px;'),56 ui.div(ui.div(ui.h6(ui.output_text('uc_pg_selected_name')),style = 'padding-left : 10px;'),57 ui.output_data_frame("uc_pg_selected"),58 style = 'width : 100%; min-height : 30vh; height : fit-content; border: 1px solid; border-color : darkgrey; border-radius : 10px; '),59 )60 ),61 ui.nav_panel("Score",62 ui.page_sidebar(63 ui.sidebar(64 ui.input_selectize("uc_score_pg", label=None, choices=[], multiple=False, options={'placeholder':'Choisissez un marché cible'}),65 ui.input_switch('uc_score_critere_switch_all', 'Sélectionner tous les critères', True),66 ui.tags.ul(67 ui.tags.li(68 ui.h6("Rendement PRIIPS"),69 ui.row(70 ui.column(6,71 ui.input_checkbox_group("uc_score_critere_rdmt_priips_1an",72 "Rendement 1 an",73 {74 "score_rendement_tension_1an": "Tension", 75 "score_rendement_defavorable_1an": "Défavorable", 76 "score_rendement_intermediaire_1an": "Intermédiaire", 77 "score_rendement_favorable_1an": "Favorable"78 }79 )80 ),81 ui.column(6,82 ui.input_checkbox_group("uc_score_critere_rdmt_priips_ddr", 83 "Rendement à DDR", 84 { 85 "score_rendement_tension_ddr": "Tension", 86 "score_rendement_defavorable_ddr": "Défavorable", 87 "score_rendement_intermediaire_ddr": "Intermédiaire", 88 "score_rendement_favorable_ddr": "Favorable"89 }90 )91 )92 93 )94 95 ),96 ui.tags.li(97 ui.input_checkbox_group( 98 "uc_score_critere_frais", 99 "Frais", 100 { 101 "score_uc_frais_entree": "Frais d'entrée", 102 "score_uc_frais_gestion": "Frais de gestion", 103 "score_uc_frais_transaction": "Frais de transaction", 104 "score_uc_frais_sortie": "Frais de sortie" 105 }, 106 )107 ),108 ui.tags.li(109 ui.input_checkbox_group( 110 "uc_score_critere_riy", 111 "Prix / Coût", 112 { 113 "score_riy_1an": "Incidence des coûts après 1 an", 114 "score_riy_ddr": "Incidence des coûts à la DDR",115 }, 116 )117 ),118 119 ),120 title=ui.div(icon('gear'), 'Paramètres du scoring', style = 'display : line; margin-top : -35px'),121 width = '30%'122 ),123 ui.div(ui.div(ui.h6('Tableau des scores'),style = 'padding-left : 10px;'),124 ui.output_data_frame("uc_score_grid"),125 style = 'width : 100%; min-height : 30vh; height : fit-content; border: 1px solid; border-color : darkgrey; border-radius : 10px; margin-top: -15px;')126 )127 ),128 ui.nav_panel("Distribution",129 ui.input_selectize("uc_visu_pg", label=None, choices=[], multiple=False, options={'placeholder':'Choisissez un marché cible'}),130 131 ui.row(132 ui.column(6,ui.div("distplot", ui.input_radio_buttons("uc_visu_boutton", "Type de représentation", choices = {'hist' : "Histogramme"}), 133 output_widget('uc_visu_histo'), style = 'width : 100%; height-min : 30vh; height : fit-content; border: 1px solid; border-color : darkgrey; border-radius : 10px; '),134 135 ),136 ui.column(6,ui.div("boxplot", 137 ui.input_radio_buttons("uc_visu_boutton_box", "Type de représentation", 138 choices = {'score_rdmt_priips_1an' : "Rendement 1 an ", 'score_rdmt_priips_ddr' : "Rendement DDR",139 "score_frais" : "Frais"}),140 output_widget('uc_visu_box'),141 style = 'width : 100%; height-min : 30vh; height : fit-content; border: 1px solid; border-color : darkgrey; border-radius : 10px; '))142 ,style = 'padding-left : 2rem; padding-right : 2rem')), 143 144 ui.nav_panel("Visualisation",145 ui.input_selectize("uc_visu_2_pg", label=None, choices=[], multiple=False, options={'placeholder':'Choisissez un marché cible'}),146 147 148 ui.column(6,ui.div("Scatter", [ui.input_selectize('uc_bubble_abcisse',label = 'Abscisse', multiple= False, choices = [], options={'placeholder' : "abcisse"},),149 ui.input_selectize('uc_bubble_ordonnée',label = 'Ordonnée', multiple= False, choices = [], options={'placeholder' : "ordonnée"}),150 ui.input_selectize('uc_bubble_taille', label = 'Ventilation', multiple= False, choices = [], options={'placeholder' : "taille"})], 151 output_widget('uc_visu_bubble'),152 style = 'width : 100%; height-min : 30vh; height : fit-content; border: 1px solid; border-color : darkgrey; border-radius : 10px; '))153 ),154 155 ),156 style = 'padding-top : 0'157)158 159app_ui = ui.page_fluid(160 # shinyswatch.theme_picker_ui(),161 ui.include_css("./www/css/header.css"),162 ui.tags.head(163 ui.tags.link(rel = "icon", type = "image/png", sizes = "32x32", href = "./img/logo-ISUP.png")),164 ui.page_navbar(ui.nav_spacer(), 165 ui.nav_panel(ui.div("Unité de compte", style = 'width : 120px; text-align : center'), page_uc),166 # ui.nav_panel('debug', page_debug),167 title=ui.div(168 ui.div("Data viz CZSS",style = 'height: 80px; line-height: 80px; text-align: center;'),169 ui.output_image("image", height='80px', width = '80px'),170 style = 'display : flex; width : 230px; flex-direction: row-reverse;'),171 window_title='ISUP: Data viz',172 theme = shinyswatch.theme.sandstone173 174 ),175 style = 'body {padding-left : 100px; padding-right : 0px;}',176 177)178 179def server(input, output, session):180 uc_pg_name = reactive.value([])181 uc_pg_dict = {}182 183 @render.image 184 def image():185 img = {"src": "./www/img/logo-ISUP.png", "width": "80px"} 186 return img 187 188 @render.data_frame189 def uc_grid_data():190 return render.DataGrid(data = uc, filters=True, editable=True , height= '75vh')191 192 193 @render.data_frame194 def uc_pg_add_tmp():195 tmp = uc196 if input.uc_pg_duree():197 tmp = tmp[[f.objectif == i for i in input.uc_pg_duree()],:]198 if input.uc_pg_sri():199 tmp = tmp[(f.sri >= input.uc_pg_sri()[0]) & (f.sri <= input.uc_pg_sri()[1]),:]200 if input.uc_pg_esg():201 tmp = tmp[[f.sfdr== i for i in input.uc_pg_esg()],:]202 203 return render.DataGrid(data = tmp, filters=False, editable=False , height= '75vh;')204 205 @reactive.effect206 @reactive.event(input.uc_pg_add)207 def __():208 tab_pg_add = ui.page_sidebar(209 ui.sidebar(ui.input_text('uc_pg_nom', label=None, placeholder='Nom du marché cible'),210 ui.input_selectize('uc_pg_duree', label=None, options={'placeholder' : "Durée d'investissement"}, choices= list(['Court terme','Moyen terme','Long terme']), multiple=True),211 ui.row(212 ui.column(2,ui.div("SRI", style = 'height: 79px; align-content : center')),213 ui.column(10,ui.input_slider('uc_pg_sri',label=None, ticks=True,min=1, max=7, value=[1,7], step=1))),214 ui.input_selectize("uc_pg_esg", label=None, options={'placeholder' : 'Critères ESG'},choices=["article 6", "article 8", 'article 9','aucune' ], multiple=True),215 bg="#f6f6f6",216 title=None,217 width='30%'),218 'Prévisualisation du Peer-group',219 ui.output_data_frame('uc_pg_add_tmp'))220 221 # tmp = ui.modal( ui.div(ui.navset_tab222 # (ui.nav_panel('marché cible', tab_pg_add),223 # ui.nav_panel('Critères de comparaison',tab_pref )224 tmp = ui.modal( ui.div(tab_pg_add,225 style = 'width : 80 vw;'),226 footer=ui.input_action_button("valider", "Valider"),227 title='Définissez un marché cible UC' ,228 easy_close= True,229 size = 'xl'230 )231 232 ui.modal_show(tmp)233 234 235 @reactive.effect236 @reactive.event(input.uc_score_critere_switch_all)237 def __():238 if input.uc_score_critere_switch_all() :239 ui.update_checkbox_group("uc_score_critere_rdmt_priips_1an",selected=['score_rendement_tension_1an','score_rendement_defavorable_1an','score_rendement_intermediaire_1an','score_rendement_favorable_1an'])240 ui.update_checkbox_group("uc_score_critere_rdmt_priips_ddr",selected=['score_rendement_tension_ddr','score_rendement_defavorable_ddr','score_rendement_intermediaire_ddr','score_rendement_favorable_ddr'])241 ui.update_checkbox_group("uc_score_critere_frais",selected=['score_uc_frais_entree','score_uc_frais_gestion','score_uc_frais_transaction','score_uc_frais_sortie'])242 ui.update_checkbox_group("uc_score_critere_riy",selected=['score_riy_1an','score_riy_ddr'])243 else :244 ui.update_checkbox_group("uc_score_critere_rdmt_priips_1an",selected=[])245 ui.update_checkbox_group("uc_score_critere_rdmt_priips_ddr",selected=[])246 ui.update_checkbox_group("uc_score_critere_frais",selected=[])247 ui.update_checkbox_group("uc_score_critere_riy",selected=[])248 249 250 251 @reactive.effect252 @reactive.event(input.valider)253 def uc_pg_table (): 254 new_pg = {255 "Nom" : input.uc_pg_nom(),256 "Durée": input.uc_pg_duree(),257 "Risque" : input.uc_pg_sri(),258 "ESG" : input.uc_pg_esg()259 }260 261 if input.uc_pg_nom() in uc_pg_name.get():262 tmp = ui.modal(ui.h6("Merci de choisir un autre nom."),263 footer=None,264 title='Nom de marché cible déjà utilisé' ,265 easy_close= True,266 size = 'l')267 ui.modal_show(tmp)268 else :269 score = uc270 if len(input.uc_pg_duree())>0 :271 score = score[[f.objectif == i for i in input.uc_pg_duree()],:]272 if len(input.uc_pg_sri())>0 :273 score = score[(f.sri >= input.uc_pg_sri()[0]) & (f.sri <= input.uc_pg_sri()[1]),:]274 if len(input.uc_pg_esg())>0 :275 score = score[[f.sfdr == i for i in input.uc_pg_esg()],:]276 277 score[:, update(score_rendement_tension_1an = scoring(x = f.rdmt_tension_1an))]278 score[:, update(score_rendement_tension_ddr = scoring(x = f.rdmt_tension_ddr))]279 score[:, update(score_rendement_defavorable_1an = scoring(x = f.rdmt_defa_1an))]280 score[:, update(score_rendement_defavorable_ddr = scoring(x = f.rdmt_defa_ddr))]281 score[:, update(score_rendement_intermediaire_1an = scoring(x = f.rdmt_inter_1an))]282 score[:, update(score_rendement_intermediaire_ddr = scoring(x = f.rdmt_inter_ddr))]283 score[:, update(score_rendement_favorable_1an = scoring(x = f.rdmt_favo_1an))]284 score[:, update(score_rendement_favorable_ddr = scoring(x = f.rdmt_favo_ddr))]285 score[:, update(score_uc_frais_entree = scoring(x = f.uc_frais_entree, order = -1))]286 score[:, update(score_uc_frais_gestion = scoring(x = f.uc_frais_gestion, order = -1))]287 score[:, update(score_uc_frais_transaction = scoring(x = f.uc_frais_transaction, order = -1))]288 score[:, update(score_uc_frais_sortie = scoring(x = f.uc_frais_sortie, order = -1))]289 score[:, update(score_riy_1an = scoring(x = f.riy_1an, order = -1))]290 score[:, update(score_riy_ddr = scoring(x = f.riy_ddr, order = -1))]291 score[:, update(score_rdmt_priips_1an = rowmean([f[item] for item in list(input.uc_score_critere_rdmt_priips_1an())]))]292 score[:, update(score_rdmt_priips_ddr = rowmean([f[item] for item in list(input.uc_score_critere_rdmt_priips_ddr())]))]293 score[:, update(score_frais = rowmean([f[item] for item in list(input.uc_score_critere_frais())]))] 294 score[:, update(score_riy = rowmean([f[item] for item in list(input.uc_score_critere_riy())]))]295 score[:, update(sc_VFM = rowmean(f.score_rdmt_priips_1an, f.score_rdmt_priips_ddr, f.score_frais, f.score_riy ))]296 297 nouvel_ordre = ['isin','compagnie_fonds','sc_VFM','score_rdmt_priips_1an','score_rdmt_priips_ddr','score_frais',298 'score_riy','type_uc','objectif','sri','devise', 'rdmt_min_gar','confo_priips','innovant','complexite',299 'coupon','risque_devise','rdmt_tension_1an','score_rendement_tension_1an','rdmt_defa_1an',300 'score_rendement_defavorable_1an','rdmt_inter_1an','score_rendement_intermediaire_1an','rdmt_favo_1an',301 'score_rendement_favorable_1an', 'rdmt_tension_ddr','score_rendement_tension_ddr','rdmt_defa_ddr',302 'score_rendement_defavorable_ddr','rdmt_inter_ddr','score_rendement_intermediaire_ddr','rdmt_favo_ddr',303 'score_rendement_favorable_ddr','uc_frais_entree','score_uc_frais_entree','uc_frais_gestion',304 'score_uc_frais_gestion','uc_frais_transaction','score_uc_frais_transaction','uc_frais_sortie',305 'score_uc_frais_sortie','riy_1an','score_riy_1an','riy_ddr','score_riy_ddr','sfdr']306 307 308 score = score[:, nouvel_ordre]309 uc_pg_name.set(uc_pg_name.get() + [input.uc_pg_nom()])310 uc_pg_dict[input.uc_pg_nom()] = {'definition' : new_pg,311 # 'critere' : new_critere,312 'score' : score}313 314 ui.modal_remove()315 316 @output317 @render.data_frame318 def uc_grid_pg__():319 pg_list = [uc_pg_dict[pg]['definition'] for pg in uc_pg_dict.keys()]320 ui.update_select("uc_score_pg", choices= uc_pg_name.get())321 ui.update_select("uc_visu_pg", choices= uc_pg_name.get())322 323 324 if pg_list :325 return render.DataGrid(data = pd.DataFrame(pg_list), selection_mode="rows")326 else :327 vide = {328 "Nom" : '',329 "Durée": '',330 "Risque" : '',331 "ESG" : '',332 }333 return render.DataGrid(data = pd.DataFrame(vide,index=[0]))334 335 @render.data_frame336 def uc_pg_selected():337 filters = uc_grid_pg__.data_view(selected=True)338 if np.shape(filters)[0] > 0 : 339 tmp = uc340 if len(filters.iloc[0,1])>0 :341 tmp = tmp[[f.objectif == i for i in filters.iloc[0,1]],:]342 if len(filters.iloc[0,2])>0 :343 tmp = tmp[(f.sri >= filters.iloc[0,2][0]) & (f.sri <= filters.iloc[0,2][1]),:]344 if len(filters.iloc[0,3])>0 :345 tmp = tmp[[f.sfdr == i for i in filters.iloc[0,3]],:]346 347 return render.DataGrid(data= tmp, filters=True)348 349 @render.text350 def uc_pg_selected_name():351 filters = uc_grid_pg__.data_view(selected=True)352 print(np.shape(filters))353 if np.shape(filters)[0] > 0 : 354 name = filters.iloc[0,0] 355 return f"Visualisation du marché cible : {name}"356 else :357 return "Aucun marché cible du Listing n'est selectionné"358 359 @reactive.effect360 @reactive.event(input.uc_pg_del)361 def supp_pg ():362 supp_pg= ui.modal(ui.page_fluid(363 ui.input_selectize("pg_to_delete", "Sélectionnez un marché cible à supprimer:", [], multiple=True),364 ),365 footer=ui.input_action_button("supprimer",'Supprimer'),366 title="Supression d'un marché cible",367 easy_close= True368 )369 370 pg_names = uc_pg_name.get()371 ui.update_select("pg_to_delete", choices=pg_names)372 ui.modal_show(supp_pg)373 374 @reactive.effect375 @reactive.event(input.supprimer)376 def delete_pg():377 if len(uc_pg_name.get()) == 1 :378 tmp = []379 else :380 tmp = uc_pg_name.get()[uc_pg_name.get() != input.pg_to_delete()]381 uc_pg_name.set(tmp)382 print(input.pg_to_delete()[0])383 del uc_pg_dict[input.pg_to_delete()[0]]384 ui.modal_remove()385 386 @render.data_frame387 def uc_score_grid():388 if input.uc_score_pg() :389 tmp = uc_pg_dict[input.uc_score_pg()]['score']390 tmp[:, update(score_rdmt_priips_1an = rowmean([f[item] for item in list(input.uc_score_critere_rdmt_priips_1an())]))]391 tmp[:, update(score_rdmt_priips_ddr = rowmean([f[item] for item in list(input.uc_score_critere_rdmt_priips_ddr())]))]392 tmp[:, update(score_frais = rowmean([f[item] for item in list(input.uc_score_critere_frais())]))] 393 tmp[:, update(score_riy = rowmean([f[item] for item in list(input.uc_score_critere_riy())]))]394 tmp[:, update(sc_VFM = rowmean(f.score_rdmt_priips_1an, f.score_rdmt_priips_ddr, f.score_frais, f.score_riy ))]395 uc_pg_dict[input.uc_score_pg()]['score'] = tmp396 397 # col = list(tmp.to_pandas().select_dtypes(include = 'float64').columns)398 col = list(['objectif', 'sri', 'devise',399 'sc_VFM', 'score_rdmt_priips_1an', 'score_rdmt_priips_ddr', 'score_frais', 'score_riy',400 'rdmt_tension_1an','rdmt_defa_1an','rdmt_inter_1an','rdmt_favo_1an',401 'rdmt_tension_ddr','rdmt_defa_ddr','rdmt_inter_ddr','rdmt_favo_ddr',402 'uc_frais_entree', 'uc_frais_gestion', 'uc_frais_transaction', 'uc_frais_sortie', 403 'riy_1an', 'riy_ddr', 404 'sfdr'])405 406 ui.update_selectize('uc_bubble_abcisse', choices = col)407 ui.update_selectize('uc_bubble_ordonnée', choices = col )408 ui.update_selectize('uc_bubble_taille', choices = col )409 410 return render.DataGrid(data = tmp, filters = True, height='70vh')411 else :412 return 413 uc_score_grid414 415 @output416 @render_widget417 def uc_visu_histo () :418 if input.uc_visu_pg() :419 tmp = uc_pg_dict[input.uc_visu_pg()]['score']420 dt_plot = tmp.to_pandas()421 422 423 if input.uc_visu_boutton() == 'hist' : 424 dt_plot_hist = pd.melt(dt_plot, 425 id_vars = ['isin'],426 var_name = 'type' ,427 value_vars = ['sc_VFM', 'score_rdmt_priips_1an', 'score_rdmt_priips_ddr', 'score_frais', 'score_riy'], 428 value_name = 'score' )429 430 fig = px.histogram(dt_plot_hist, x = "score", color= 'type', marginal = 'rug', range_x=[0,10], hover_data=['isin', 'type', 'score'],431 barmode = 'group',432 opacity = 0.6,433 nbins = 20)434 435 if input.uc_visu_boutton() == 'densite' :436 dt_plot_densite = dt_plot[['isin','sc_VFM', 'score_rdmt_priips_1an', 'score_rdmt_priips_ddr', 'score_frais', 'score_riy']]437 #isin = dt_plot_densite['isin']438 hist_data = [np.array(dt_plot['sc_VFM'].dropna()), np.array(dt_plot['score_rdmt_priips_1an'].dropna()), 439 np.array(dt_plot['score_rdmt_priips_ddr'].dropna()), np.array(dt_plot['score_frais'].dropna()), 440 np.array(dt_plot['score_riy'].dropna())]441 labels = ['sc_VFM', 'score_rdmt_priips_1an', 'score_rdmt_priips_ddr', 'score_frais', 'score_riy']442 fig = ff.create_distplot(hist_data, 443 group_labels= labels,444 #rug_text = isin, 445 show_hist=False)446 447 return fig448 449 @output450 @render_widget451 def uc_visu_bubble () :452 if input.uc_visu_pg() :453 tmp = uc_pg_dict[input.uc_visu_pg()]['score']454 dt_plot = tmp.to_pandas()455 456 457 458 459 fig = px.scatter(dt_plot, x=input.uc_bubble_abcisse(), y=input.uc_bubble_ordonnée(),460 # size=461 color= input.uc_bubble_taille(),462 hover_name="isin", size_max=15)463 464 return fig465 466 @output467 @render_widget468 def uc_visu_box () :469 if input.uc_visu_pg() :470 tmp = uc_pg_dict[input.uc_visu_pg()]['score']471 dt_plot = tmp.to_pandas()472 473 trace_rdmt_1an = np.array(dt_plot['score_rdmt_priips_1an'])474 trace_rdmt_ddr = np.array(dt_plot['score_rdmt_priips_ddr'])475 476 fig = px.box(dt_plot, y=input.uc_visu_boutton_box(), points="all", hover_name= 'isin')477 478 479 return fig480 481app = App(app_ui, server)