diff --git a/CODE/.env.example b/CODE/.env.example index 5b10b48..55d3171 100644 --- a/CODE/.env.example +++ b/CODE/.env.example @@ -1,14 +1,12 @@ # Copy these names into your environment. Do not commit real values. -NBA_SQL_DRIVER=ODBC Driver 18 for SQL Server -NBA_SQL_SERVER=localhost,1433 +NBA_SQL_DRIVER=ODBC Driver 17 for SQL Server +NBA_SQL_SERVER=.\SQLEXPRESS NBA_SQL_DATABASE=NBA_Project -# Docker / SQL authentication (recommended for the reproducible local demo). -NBA_SQL_TRUSTED_CONNECTION=no -NBA_SQL_USER=sa -NBA_SQL_PASSWORD=replace_with_a_local_secret +# Local SQL Server Express / Windows authentication (matches the PBIT source). +NBA_SQL_TRUSTED_CONNECTION=yes NBA_SQL_ENCRYPT=no NBA_SQL_TRUST_SERVER_CERTIFICATE=yes -# Alternative: set NBA_SQL_TRUSTED_CONNECTION=yes and leave user/password unset -# when using a local SQL Server instance with Windows authentication. +# Docker/CI alternative: use localhost,1433, ODBC Driver 18, trusted_connection=no, +# and provide NBA_SQL_USER/NBA_SQL_PASSWORD through the shell or secret manager. diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam.pbit b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam.pbit index d569433..51bec86 100644 Binary files a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam.pbit and b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam.pbit differ diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/relationships.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/relationships.tmdl index b7a592f..3f07168 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/relationships.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/relationships.tmdl @@ -2,12 +2,6 @@ fromColumn: 'analytics dim_season'.decade toColumn: 'analytics vw_q4_ppg_by_decade'.decade -relationship b0426d34-7bfe-4b3c-02aa-e2f288b5893a - crossFilteringBehavior: bothDirections - fromCardinality: one - fromColumn: 'analytics vw_q2_age_vs_current'.team_name - toColumn: 'analytics vw_q1_hist_perf'.team_name - relationship 4b008a12-c759-f4de-7c60-4fe8487c7f6c fromColumn: 'analytics vw_q3_player_context_offense'.team_name toColumn: 'analytics vw_q1_hist_perf'.team_name @@ -20,12 +14,6 @@ relationship ce99328f-730b-1a82-ba7b-a3116104b3b3 fromColumn: 'analytics vw_q7_balance_of_def'.season_id toColumn: 'analytics dim_season'.season_id -relationship 9484f463-a32f-35bb-2a87-249fb1142237 - crossFilteringBehavior: bothDirections - fromCardinality: one - fromColumn: 'analytics vw_q8_longest_win_streak'.team_id - toColumn: 'analytics vw_q10_recent_top'.team_id - relationship 0f32ba4b-2c17-a8fc-6d17-1e5835afd555 isActive: false crossFilteringBehavior: bothDirections diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics dim_season.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics dim_season.tmdl index d718c67..f599994 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics dim_season.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics dim_season.tmdl @@ -40,9 +40,8 @@ table 'analytics dim_season' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_dim_season = NBA_Project{[Schema="analytics",Item="dim_season"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_dim_season = Origen{[Schema="analytics",Item="dim_season"]}[Data] in analytics_dim_season diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_bridge_team_season.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_bridge_team_season.tmdl index 690dc3e..6f87fd1 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_bridge_team_season.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_bridge_team_season.tmdl @@ -22,9 +22,8 @@ table 'analytics vw_bridge_team_season' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_bridge_team_season = NBA_Project{[Schema="analytics",Item="vw_bridge_team_season"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_bridge_team_season = Origen{[Schema="analytics",Item="vw_bridge_team_season"]}[Data] in analytics_vw_bridge_team_season diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q10_recent_top.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q10_recent_top.tmdl index 49d2ced..bbfae2c 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q10_recent_top.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q10_recent_top.tmdl @@ -48,10 +48,8 @@ table 'analytics vw_q10_recent_top' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q10_recent_top = NBA_Project{[Schema="analytics",Item="vw_q10_recent_top"]}[Data], - #"Columnas con nombre cambiado" = Table.RenameColumns(analytics_vw_q10_recent_top,{{"ppg_10y", "Puntos por partido ultimos 10 años"}, {"winrate_10y", "Porcentaje de victorias ultimos 10 años"}}) + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_q10_recent_top = Origen{[Schema="analytics",Item="vw_q10_recent_top"]}[Data] in - #"Columnas con nombre cambiado" + analytics_vw_q10_recent_top diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q1_hist_perf.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q1_hist_perf.tmdl index 8129a68..aa0f5de 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q1_hist_perf.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q1_hist_perf.tmdl @@ -66,9 +66,8 @@ table 'analytics vw_q1_hist_perf' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q1_hist_perf = NBA_Project{[Schema="analytics",Item="vw_q1_hist_perf"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_q1_hist_perf = Origen{[Schema="analytics",Item="vw_q1_hist_perf"]}[Data] in analytics_vw_q1_hist_perf diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q2_age_vs_current.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q2_age_vs_current.tmdl index 0034dda..edeae5c 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q2_age_vs_current.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q2_age_vs_current.tmdl @@ -49,9 +49,7 @@ table 'analytics vw_q2_age_vs_current' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q2_age_vs_current = NBA_Project{[Schema="analytics",Item="vw_q2_age_vs_current"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + Consulta = Value.NativeQuery(Origen, "SELECT team_name, year_founded, franchise_age, winrate_hist, ppg_hist FROM analytics.vw_q2_age_vs_current", null, [EnableFolding=true]) in - analytics_vw_q2_age_vs_current - + Consulta diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q3_player_context_offense.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q3_player_context_offense.tmdl index a99a566..0806a16 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q3_player_context_offense.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q3_player_context_offense.tmdl @@ -48,10 +48,8 @@ table 'analytics vw_q3_player_context_offense' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q3_player_context_offense = NBA_Project{[Schema="analytics",Item="vw_q3_player_context_offense"]}[Data], - #"Columnas con nombre cambiado" = Table.RenameColumns(analytics_vw_q3_player_context_offense,{{"avg_ppg", "Puntos por partido"}, {"avg_fg_pct", "Porcentaje de acierto"}}) + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_q3_player_context_offense = Origen{[Schema="analytics",Item="vw_q3_player_context_offense"]}[Data] in - #"Columnas con nombre cambiado" + analytics_vw_q3_player_context_offense diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q4_ppg_by_decade.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q4_ppg_by_decade.tmdl index 5e17689..5635ba0 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q4_ppg_by_decade.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q4_ppg_by_decade.tmdl @@ -23,9 +23,8 @@ table 'analytics vw_q4_ppg_by_decade' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q4_ppg_by_decade = NBA_Project{[Schema="analytics",Item="vw_q4_ppg_by_decade"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_q4_ppg_by_decade = Origen{[Schema="analytics",Item="vw_q4_ppg_by_decade"]}[Data] in analytics_vw_q4_ppg_by_decade diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q5_consistency.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q5_consistency.tmdl index d6d81d2..7bf1de1 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q5_consistency.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q5_consistency.tmdl @@ -31,9 +31,8 @@ table 'analytics vw_q5_consistency' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q5_consistency = NBA_Project{[Schema="analytics",Item="vw_q5_consistency"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_q5_consistency = Origen{[Schema="analytics",Item="vw_q5_consistency"]}[Data] in analytics_vw_q5_consistency diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q6_home_away_impact.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q6_home_away_impact.tmdl index f7bbccd..3ed2d74 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q6_home_away_impact.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q6_home_away_impact.tmdl @@ -77,12 +77,10 @@ table 'analytics vw_q6_home_away_impact' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q6_home_away_impact = NBA_Project{[Schema="analytics",Item="vw_q6_home_away_impact"]}[Data], - #"Columnas con nombre cambiado" = Table.RenameColumns(analytics_vw_q6_home_away_impact,{{"ppg_home", "Puntos como Local"}, {"ppg_away", "Puntos como visitante"}}) + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_q6_home_away_impact = Origen{[Schema="analytics",Item="vw_q6_home_away_impact"]}[Data] in - #"Columnas con nombre cambiado" + analytics_vw_q6_home_away_impact annotation PBI_NavigationStepName = Navegación diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q7_balance_of_def.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q7_balance_of_def.tmdl index ea9d764..82db88a 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q7_balance_of_def.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q7_balance_of_def.tmdl @@ -28,7 +28,7 @@ table 'analytics vw_q7_balance_of_def' column 'Balones perdidos' dataType: double - formatString: 0.0\ %;-0.0\ %;0.0\ % + formatString: 0.0 sourceProviderType: float summarizeBy: sum sourceColumn: Balones perdidos @@ -49,10 +49,8 @@ table 'analytics vw_q7_balance_of_def' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q7_balance_of_def = NBA_Project{[Schema="analytics",Item="vw_q7_balance_of_def"]}[Data], - #"Columnas con nombre cambiado" = Table.RenameColumns(analytics_vw_q7_balance_of_def,{{"fg_pct_avg", "Eficiencia de tiro"}, {"tov_avg", "Balones perdidos"}}) + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_q7_balance_of_def = Origen{[Schema="analytics",Item="vw_q7_balance_of_def"]}[Data] in - #"Columnas con nombre cambiado" + analytics_vw_q7_balance_of_def diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q8_longest_win_streak.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q8_longest_win_streak.tmdl index c71c134..e5f679f 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q8_longest_win_streak.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q8_longest_win_streak.tmdl @@ -30,9 +30,8 @@ table 'analytics vw_q8_longest_win_streak' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q8_longest_win_streak = NBA_Project{[Schema="analytics",Item="vw_q8_longest_win_streak"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_q8_longest_win_streak = Origen{[Schema="analytics",Item="vw_q8_longest_win_streak"]}[Data] in analytics_vw_q8_longest_win_streak diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q9_physical_profile.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q9_physical_profile.tmdl index b59a04f..a0743b7 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q9_physical_profile.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_q9_physical_profile.tmdl @@ -41,9 +41,8 @@ table 'analytics vw_q9_physical_profile' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_q9_physical_profile = NBA_Project{[Schema="analytics",Item="vw_q9_physical_profile"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_q9_physical_profile = Origen{[Schema="analytics",Item="vw_q9_physical_profile"]}[Data] in analytics_vw_q9_physical_profile diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_team_season_basic.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_team_season_basic.tmdl index 4f0e011..1afa57a 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_team_season_basic.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_team_season_basic.tmdl @@ -31,9 +31,8 @@ table 'analytics vw_team_season_basic' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_team_season_basic = NBA_Project{[Schema="analytics",Item="vw_team_season_basic"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_team_season_basic = Origen{[Schema="analytics",Item="vw_team_season_basic"]}[Data] in analytics_vw_team_season_basic diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_team_season_metrics.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_team_season_metrics.tmdl index 4a8b1f7..70077f7 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_team_season_metrics.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_team_season_metrics.tmdl @@ -79,9 +79,8 @@ table 'analytics vw_team_season_metrics' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_team_season_metrics = NBA_Project{[Schema="analytics",Item="vw_team_season_metrics"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_team_season_metrics = Origen{[Schema="analytics",Item="vw_team_season_metrics"]}[Data] in analytics_vw_team_season_metrics diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_teams.tmdl b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_teams.tmdl index 3f788d6..9cda8de 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_teams.tmdl +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Model/tables/analytics vw_teams.tmdl @@ -30,9 +30,8 @@ table 'analytics vw_teams' mode: directQuery source = let - Origen = Sql.Databases("localhost,1433"), - NBA_Project = Origen{[Name="NBA_Project"]}[Data], - analytics_vw_teams = NBA_Project{[Schema="analytics",Item="vw_teams"]}[Data] + Origen = Sql.Database(".\SQLEXPRESS", "NBA_Project"), + analytics_vw_teams = Origen{[Schema="analytics",Item="vw_teams"]}[Data] in analytics_vw_teams diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/01000_textbox (28d44)/config.json b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/01000_textbox (28d44)/config.json index 09f05c0..743cfb7 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/01000_textbox (28d44)/config.json +++ b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/01000_textbox (28d44)/config.json @@ -24,7 +24,7 @@ { "textRuns": [ { - "value": "Descifrando el Rendimiento y Evolución de las franquicias NBA", + "value": "Rendimiento y evolución de las franquicias NBA", "textStyle": { "fontWeight": "bold", "fontSize": "28pt", diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/05000_Rendimiento en funci\303\263n de la Antiguedad/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/05000_Rendimiento en funci\303\263n de la Antiguedad/config.json" index 0b75b71..661a2a1 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/05000_Rendimiento en funci\303\263n de la Antiguedad/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/05000_Rendimiento en funci\303\263n de la Antiguedad/config.json" @@ -219,7 +219,7 @@ "titleText": { "expr": { "Literal": { - "Value": "'Equipos ->'" + "Value": "'Equipo'" } } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/05000_Rendimiento en funci\303\263n de la Antiguedad/dataTransforms.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/05000_Rendimiento en funci\303\263n de la Antiguedad/dataTransforms.json" index f02c7cf..0cb16fc 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/05000_Rendimiento en funci\303\263n de la Antiguedad/dataTransforms.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/05000_Rendimiento en funci\303\263n de la Antiguedad/dataTransforms.json" @@ -109,7 +109,7 @@ "titleText": { "expr": { "Literal": { - "Value": "'Equipos ->'" + "Value": "'Equipo'" } } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/08000_advancedSlicerVisual (34242)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/08000_advancedSlicerVisual (34242)/config.json" index 9fbc94f..77b5339 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/08000_advancedSlicerVisual (34242)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/08000_advancedSlicerVisual (34242)/config.json" @@ -4,11 +4,11 @@ { "id": 0, "position": { - "x": 962.8571428571429, - "y": 84.28571428571429, + "x": 963, + "y": 85, "z": 15000, - "width": 355.7142857142857, - "height": 292.8571428571429, + "width": 346, + "height": 90, "tabOrder": 8000 } } @@ -138,15 +138,10 @@ "background": [ { "properties": { - "color": { - "solid": { - "color": { - "expr": { - "ThemeDataColor": { - "ColorId": 3, - "Percent": -0.25 - } - } + "show": { + "expr": { + "Literal": { + "Value": "false" } } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/08000_advancedSlicerVisual (34242)/visualContainer.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/08000_advancedSlicerVisual (34242)/visualContainer.json" index e5cac66..d17e40d 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/08000_advancedSlicerVisual (34242)/visualContainer.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/001_An\303\241lisis_1/visualContainers/08000_advancedSlicerVisual (34242)/visualContainer.json" @@ -1,8 +1,8 @@ { - "height": 292.8571428571429, + "height": 90, "tabOrder": 8000, - "width": 355.7142857142857, - "x": 962.8571428571429, - "y": 84.28571428571429, + "width": 346, + "x": 963, + "y": 85, "z": 15000 } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_Subtitulo (4dab6)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_Subtitulo (4dab6)/config.json" index 445c278..26814d2 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_Subtitulo (4dab6)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_Subtitulo (4dab6)/config.json" @@ -24,22 +24,10 @@ { "textRuns": [ { - "value": "Precisión ", + "value": "Eficiencia de tiro", "textStyle": { "fontWeight": "bold" } - }, - { - "value": "de " - }, - { - "value": "tiro ", - "textStyle": { - "fontWeight": "bold" - } - }, - { - "value": "por partido" } ], "horizontalTextAlignment": "center" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_Subtitulo (f70c7)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_Subtitulo (f70c7)/config.json" index d070783..3360904 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_Subtitulo (f70c7)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_Subtitulo (f70c7)/config.json" @@ -24,16 +24,10 @@ { "textRuns": [ { - "value": "Porcentaje de " - }, - { - "value": "balones perdidos ", + "value": "Pérdidas por partido", "textStyle": { "fontWeight": "bold" } - }, - { - "value": "por partido" } ], "horizontalTextAlignment": "center" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_textbox (e4aa8)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_textbox (e4aa8)/config.json" index a66c505..7ae68f9 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_textbox (e4aa8)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/00000_textbox (e4aa8)/config.json" @@ -24,7 +24,7 @@ { "textRuns": [ { - "value": "Eficiencia y Consistencia", + "value": "Eficiencia y consistencia", "textStyle": { "fontWeight": "bold", "fontSize": "20pt", diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/01000_Puntos promedio por partido (481ef)/dataTransforms.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/01000_Puntos promedio por partido (481ef)/dataTransforms.json" index 9f9ee7b..58adeb6 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/01000_Puntos promedio por partido (481ef)/dataTransforms.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/01000_Puntos promedio por partido (481ef)/dataTransforms.json" @@ -242,7 +242,7 @@ "Restatement": "Promedio de Balones perdidos", "Name": "Sum(analytics vw_q7_balance_of_def.tov_avg)", "Type": 1, - "Format": "0.0\\ %;-0.0\\ %;0.0\\ %" + "Format": "0.0" } ] }, @@ -260,7 +260,7 @@ "selects": [ { "displayName": "Promedio de Balones perdidos", - "format": "0.0\\ %;-0.0\\ %;0.0\\ %", + "format": "0.0", "queryName": "Sum(analytics vw_q7_balance_of_def.tov_avg)", "roles": { "Data": true diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/01000_textbox (90110)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/01000_textbox (90110)/config.json" index b668613..36fcaf1 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/01000_textbox (90110)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/01000_textbox (90110)/config.json" @@ -24,7 +24,7 @@ { "textRuns": [ { - "value": "Eficiencia y Consistencia ", + "value": "Eficiencia y consistencia ", "textStyle": { "fontWeight": "bold", "fontSize": "20pt", diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/07000_Eficiencia de Tiro vs P\303\251rdidas de bal\303\263n/dataTransforms.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/07000_Eficiencia de Tiro vs P\303\251rdidas de bal\303\263n/dataTransforms.json" index 5285893..7028c01 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/07000_Eficiencia de Tiro vs P\303\251rdidas de bal\303\263n/dataTransforms.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/07000_Eficiencia de Tiro vs P\303\251rdidas de bal\303\263n/dataTransforms.json" @@ -254,7 +254,7 @@ "Restatement": "Promedio de Balones perdidos", "Name": "Avg(analytics vw_q7_balance_of_def.tov_avg)", "Type": 1, - "Format": "0.0\\ %;-0.0\\ %;0.0\\ %" + "Format": "0.0" }, { "Restatement": "Promedio de Eficiencia de tiro", @@ -293,7 +293,7 @@ "selects": [ { "displayName": "Promedio de Balones perdidos", - "format": "0.0\\ %;-0.0\\ %;0.0\\ %", + "format": "0.0", "queryName": "Avg(analytics vw_q7_balance_of_def.tov_avg)", "roles": { "Y": true diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/config.json" index d3f7c48..8391027 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/config.json" @@ -4,11 +4,11 @@ { "id": 0, "position": { - "x": 941.6666666666667, - "y": 226.66666666666669, + "x": 942, + "y": 227, "z": 13000, - "width": 366.6666666666667, - "height": 258.33333333333337, + "width": 367, + "height": 90, "tabOrder": 9000 } } @@ -64,7 +64,7 @@ "showBlankAs": { "expr": { "Literal": { - "Value": "'Equipos ->'" + "Value": "'Equipo'" } } } @@ -105,15 +105,10 @@ "background": [ { "properties": { - "color": { - "solid": { - "color": { - "expr": { - "ThemeDataColor": { - "ColorId": 3, - "Percent": -0.25 - } - } + "show": { + "expr": { + "Literal": { + "Value": "false" } } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/dataTransforms.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/dataTransforms.json" index 8b4b95e..9639ae8 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/dataTransforms.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/dataTransforms.json" @@ -11,7 +11,7 @@ "showBlankAs": { "expr": { "Literal": { - "Value": "'Equipos ->'" + "Value": "'Equipo'" } } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/visualContainer.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/visualContainer.json" index 551be2b..0ca43e0 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/visualContainer.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/09000_advancedSlicerVisual (fa73f)/visualContainer.json" @@ -1,8 +1,8 @@ { - "height": 258.33333333333337, + "height": 90, "tabOrder": 9000, - "width": 366.6666666666667, - "x": 941.6666666666667, - "y": 226.66666666666669, + "width": 367, + "x": 942, + "y": 227, "z": 13000 } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/10000_advancedSlicerVisual (b0ea8)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/10000_advancedSlicerVisual (b0ea8)/config.json" index d57d691..90b8a8d 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/10000_advancedSlicerVisual (b0ea8)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/10000_advancedSlicerVisual (b0ea8)/config.json" @@ -7,8 +7,8 @@ "x": 995, "y": 85, "z": 17000, - "width": 313.75, - "height": 132.5, + "width": 314, + "height": 90, "tabOrder": 10000 } } @@ -100,15 +100,10 @@ "background": [ { "properties": { - "color": { - "solid": { - "color": { - "expr": { - "ThemeDataColor": { - "ColorId": 3, - "Percent": -0.25 - } - } + "show": { + "expr": { + "Literal": { + "Value": "false" } } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/10000_advancedSlicerVisual (b0ea8)/visualContainer.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/10000_advancedSlicerVisual (b0ea8)/visualContainer.json" index a3cc1bf..7dbb7ff 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/10000_advancedSlicerVisual (b0ea8)/visualContainer.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/002_An\303\241lisis_2/visualContainers/10000_advancedSlicerVisual (b0ea8)/visualContainer.json" @@ -1,7 +1,7 @@ { - "height": 132.5, + "height": 90, "tabOrder": 10000, - "width": 313.75, + "width": 314, "x": 995, "y": 85, "z": 17000 diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/00000_Subtitulo (66065)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/00000_Subtitulo (66065)/config.json" index 6f45896..db1c156 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/00000_Subtitulo (66065)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/00000_Subtitulo (66065)/config.json" @@ -24,21 +24,13 @@ { "textRuns": [ { - "value": "Total de " - }, - { - "value": "jugadores ", + "value": "Mayor muestra de ", "textStyle": { "fontWeight": "bold" } - } - ], - "horizontalTextAlignment": "center" - }, - { - "textRuns": [ + }, { - "value": "fichados" + "value": "jugadores por equipo" } ], "horizontalTextAlignment": "center" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/03000_Perfil f\303\255sico promedio de los equipos NBA/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/03000_Perfil f\303\255sico promedio de los equipos NBA/config.json" index d530a4f..94f5392 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/03000_Perfil f\303\255sico promedio de los equipos NBA/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/03000_Perfil f\303\255sico promedio de los equipos NBA/config.json" @@ -4,11 +4,11 @@ { "id": 0, "position": { - "x": 15.714285714285715, - "y": 500.00000000000006, + "x": 16, + "y": 500, "z": 7000, - "width": 530, - "height": 248.57142857142858, + "width": 900, + "height": 249, "tabOrder": 3000 } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/03000_Perfil f\303\255sico promedio de los equipos NBA/visualContainer.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/03000_Perfil f\303\255sico promedio de los equipos NBA/visualContainer.json" index 28c7ef7..14c5b6e 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/03000_Perfil f\303\255sico promedio de los equipos NBA/visualContainer.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/03000_Perfil f\303\255sico promedio de los equipos NBA/visualContainer.json" @@ -1,8 +1,8 @@ { - "height": 248.57142857142858, + "height": 249, "tabOrder": 3000, - "width": 530, - "x": 15.714285714285715, + "width": 900, + "x": 16, "y": 500, "z": 7000 } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/05000_Eficiencia ofensiva de equipos NBA/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/05000_Eficiencia ofensiva de equipos NBA/config.json" index cc42852..10f1c6d 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/05000_Eficiencia ofensiva de equipos NBA/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/05000_Eficiencia ofensiva de equipos NBA/config.json" @@ -4,11 +4,11 @@ { "id": 0, "position": { - "x": 15.714285714285715, - "y": 161.42857142857144, + "x": 16, + "y": 161, "z": 9000, - "width": 727.1428571428572, - "height": 324.28571428571433, + "width": 1279, + "height": 324, "tabOrder": 5000 } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/05000_Eficiencia ofensiva de equipos NBA/visualContainer.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/05000_Eficiencia ofensiva de equipos NBA/visualContainer.json" index 3130cb5..b081afc 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/05000_Eficiencia ofensiva de equipos NBA/visualContainer.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/05000_Eficiencia ofensiva de equipos NBA/visualContainer.json" @@ -1,8 +1,8 @@ { - "height": 324.28571428571433, + "height": 324, "tabOrder": 5000, - "width": 727.1428571428572, - "x": 15.714285714285715, - "y": 161.42857142857144, + "width": 1279, + "x": 16, + "y": 161, "z": 9000 } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/config.json" index 3e748b1..5c80dd1 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/config.json" @@ -4,11 +4,11 @@ { "id": 0, "position": { - "x": 975.5555555555555, + "x": 930, "y": 500, "z": 14000, - "width": 333.3333333333333, - "height": 248.88888888888889, + "width": 365, + "height": 90, "tabOrder": 8000 } } @@ -59,7 +59,7 @@ "showBlankAs": { "expr": { "Literal": { - "Value": "'Equipos ->'" + "Value": "'Equipo'" } } } @@ -100,15 +100,10 @@ "background": [ { "properties": { - "color": { - "solid": { - "color": { - "expr": { - "ThemeDataColor": { - "ColorId": 3, - "Percent": -0.25 - } - } + "show": { + "expr": { + "Literal": { + "Value": "false" } } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/dataTransforms.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/dataTransforms.json" index 8b4b95e..9639ae8 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/dataTransforms.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/dataTransforms.json" @@ -11,7 +11,7 @@ "showBlankAs": { "expr": { "Literal": { - "Value": "'Equipos ->'" + "Value": "'Equipo'" } } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/visualContainer.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/visualContainer.json" index e8efc25..474f2eb 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/visualContainer.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/08000_advancedSlicerVisual (a910c)/visualContainer.json" @@ -1,8 +1,8 @@ { - "height": 248.88888888888889, + "height": 90, "tabOrder": 8000, - "width": 333.3333333333333, - "x": 975.5555555555555, + "width": 365, + "x": 930, "y": 500, "z": 14000 } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/config.json" index f259cb1..a72e831 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/config.json" @@ -23,7 +23,7 @@ ], "Category": [ { - "queryRef": "analytics vw_teams.team_name", + "queryRef": "analytics vw_q8_longest_win_streak.team_name", "active": true } ] @@ -35,11 +35,6 @@ "Name": "a", "Entity": "analytics vw_q8_longest_win_streak", "Type": 0 - }, - { - "Name": "a1", - "Entity": "analytics vw_teams", - "Type": 0 } ], "Select": [ @@ -64,12 +59,12 @@ "Column": { "Expression": { "SourceRef": { - "Source": "a1" + "Source": "a" } }, "Property": "team_name" }, - "Name": "analytics vw_teams.team_name", + "Name": "analytics vw_q8_longest_win_streak.team_name", "NativeReferenceName": "team_name" } ], diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/dataTransforms.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/dataTransforms.json" index ea5d62e..a641f8e 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/dataTransforms.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/dataTransforms.json" @@ -189,7 +189,7 @@ "projectionActiveItems": { "Category": [ { - "queryRef": "analytics vw_teams.team_name", + "queryRef": "analytics vw_q8_longest_win_streak.team_name", "suppressConcat": false } ] @@ -204,7 +204,7 @@ }, { "Restatement": "team_name", - "Name": "analytics vw_teams.team_name", + "Name": "analytics vw_q8_longest_win_streak.team_name", "Type": 2048 } ] @@ -272,7 +272,7 @@ }, { "displayName": "team_name", - "queryName": "analytics vw_teams.team_name", + "queryName": "analytics vw_q8_longest_win_streak.team_name", "roles": { "Category": true }, @@ -284,7 +284,7 @@ "Column": { "Expression": { "SourceRef": { - "Entity": "analytics vw_teams" + "Entity": "analytics vw_q8_longest_win_streak" } }, "Property": "team_name" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/query.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/query.json" index e663831..01e0818 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/query.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/004_Insights/visualContainers/11000_Racha hist\303\263rica/query.json" @@ -9,11 +9,6 @@ "Name": "a", "Entity": "analytics vw_q8_longest_win_streak", "Type": 0 - }, - { - "Name": "a1", - "Entity": "analytics vw_teams", - "Type": 0 } ], "Select": [ @@ -38,12 +33,12 @@ "Column": { "Expression": { "SourceRef": { - "Source": "a1" + "Source": "a" } }, "Property": "team_name" }, - "Name": "analytics vw_teams.team_name", + "Name": "analytics vw_q8_longest_win_streak.team_name", "NativeReferenceName": "team_name" } ], diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/04000_textbox (76d01)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/04000_textbox (76d01)/config.json" index d30fb27..7b1f7e3 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/04000_textbox (76d01)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/04000_textbox (76d01)/config.json" @@ -4,11 +4,11 @@ { "id": 0, "position": { - "x": 0, - "y": 350, + "x": 120, + "y": 215, "z": 0, - "width": 1320, - "height": 408.5714285714286, + "width": 1080, + "height": 450, "tabOrder": 4000 } } @@ -27,7 +27,7 @@ "value": "Fuente: seis CSV públicos versionados; 30.638.984 bytes y 161.111 filas de entrada.", "textStyle": { "fontWeight": "bold", - "fontSize": "12pt", + "fontSize": "15pt", "color": "#e6e6e6" } } @@ -39,7 +39,19 @@ "value": "Cobertura: 65.642 partidos únicos entre 1946 y 2022; análisis descriptivo.", "textStyle": { "fontWeight": "bold", - "fontSize": "12pt", + "fontSize": "15pt", + "color": "#e6e6e6" + } + } + ] + }, + { + "textRuns": [ + { + "value": "Alcance visual: 30 franquicias actuales; rivales internacionales, All-Star y equipos sin mapear permanecen auditables en el núcleo, pero no alteran los rankings comparativos.", + "textStyle": { + "fontWeight": "bold", + "fontSize": "15pt", "color": "#e6e6e6" } } @@ -51,7 +63,7 @@ "value": "Calidad: 155 duplicados en cuarentena y 53 equipos históricos sin nombre actual representados explícitamente.", "textStyle": { "fontWeight": "bold", - "fontSize": "12pt", + "fontSize": "15pt", "color": "#e6e6e6" } } @@ -63,7 +75,7 @@ "value": "Reproducibilidad: contrato v1.0.0, manifiestos SHA-256, reconciliación SQL y pruebas automatizadas.", "textStyle": { "fontWeight": "bold", - "fontSize": "12pt", + "fontSize": "15pt", "color": "#e6e6e6" } } @@ -75,7 +87,7 @@ "value": "Límite: la muestra no es 22 GB, no contiene datos sintéticos y no predice resultados ni retornos financieros.", "textStyle": { "fontWeight": "bold", - "fontSize": "12pt", + "fontSize": "15pt", "color": "#e6e6e6" } } @@ -84,10 +96,10 @@ { "textRuns": [ { - "value": "Última validación integral: 28/08/2026.", + "value": "Última validación integral: 10/09/2026.", "textStyle": { "fontWeight": "bold", - "fontSize": "12pt", + "fontSize": "15pt", "color": "#e6e6e6" } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/04000_textbox (76d01)/visualContainer.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/04000_textbox (76d01)/visualContainer.json" index e19acef..b23c27a 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/04000_textbox (76d01)/visualContainer.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/04000_textbox (76d01)/visualContainer.json" @@ -1,8 +1,8 @@ { - "height": 408.5714285714286, + "height": 450, "tabOrder": 4000, - "width": 1320, - "x": 0, - "y": 350, + "width": 1080, + "x": 120, + "y": 215, "z": 0 } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/10000_textbox (dc975)/config.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/10000_textbox (dc975)/config.json" index a26455b..3dcc145 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/10000_textbox (dc975)/config.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/10000_textbox (dc975)/config.json" @@ -4,11 +4,11 @@ { "id": 0, "position": { - "x": 0, - "y": 221.42857142857144, + "x": 120, + "y": 105, "z": 12000, - "width": 985.7142857142858, - "height": 180, + "width": 1080, + "height": 85, "tabOrder": 10000 } } @@ -24,10 +24,10 @@ { "textRuns": [ { - "value": "San Antonio Spurs — perfil histórico", + "value": "Metodología y evidencia", "textStyle": { "fontWeight": "bold", - "fontSize": "60pt", + "fontSize": "32pt", "color": "#ffffff" } } diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/10000_textbox (dc975)/visualContainer.json" "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/10000_textbox (dc975)/visualContainer.json" index 83aa335..c67c08c 100644 --- "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/10000_textbox (dc975)/visualContainer.json" +++ "b/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/10000_textbox (dc975)/visualContainer.json" @@ -1,8 +1,8 @@ { - "height": 180, + "height": 85, "tabOrder": 10000, - "width": 985.7142857142858, - "x": 0, - "y": 221.42857142857144, + "width": 1080, + "x": 120, + "y": 105, "z": 12000 } diff --git a/CODE/Dashboard - POWERBI/README.md b/CODE/Dashboard - POWERBI/README.md index c294d4f..433fe46 100644 --- a/CODE/Dashboard - POWERBI/README.md +++ b/CODE/Dashboard - POWERBI/README.md @@ -16,8 +16,8 @@ I use built-in dropdown slicers and descriptive conclusions only. I do not claim ## Refresh 1. Run the ETL and SQL loader from the root README. -2. Confirm that `NBA_Project` is available at `localhost,1433`. -3. Open the PBIT in Power BI Desktop and provide the same local SQL authentication method. +2. Confirm that `NBA_Project` is available at `.\SQLEXPRESS`. +3. Open the PBIT in Power BI Desktop and select Windows authentication. 4. Refresh every page. 5. Compare visible KPIs with `CODE/SQL/30_reconciliation.sql` before capturing evidence. diff --git a/CODE/README.md b/CODE/README.md index f3c8e47..68ba374 100644 --- a/CODE/README.md +++ b/CODE/README.md @@ -8,7 +8,7 @@ I keep the executable assets in this folder while the installable Python package 2. The ETL writes immutable run directories with canonical data, quarantined rows, JSONL logs, checksums and reconciliation. 3. `SQL/script.sql` creates the database, canonical model, analytical views and independent reconciliation queries. 4. The transactional loader inserts the completed run and verifies the 15 SQL objects consumed by Power BI. -5. The PBIT connects to `NBA_Project` on `localhost,1433` through DirectQuery. +5. The PBIT connects to `NBA_Project` on `.\SQLEXPRESS` through DirectQuery and Windows authentication. Canonical outputs: diff --git a/CODE/SQL/20_analytics_views.sql b/CODE/SQL/20_analytics_views.sql index 3a4a6ad..50c2c72 100644 --- a/CODE/SQL/20_analytics_views.sql +++ b/CODE/SQL/20_analytics_views.sql @@ -52,7 +52,8 @@ GO CREATE OR ALTER VIEW analytics.vw_teams AS SELECT t.team_id, t.full_name AS team_name, t.abbreviation -FROM core.dim_team AS t; +FROM core.dim_team AS t +WHERE t.is_historical_unmapped = 0; GO CREATE OR ALTER VIEW analytics.vw_q1_hist_perf AS @@ -84,7 +85,8 @@ SELECT teams.full_name AS team_name, teams.year_founded, recent.winrate_hist, recent.ppg_hist FROM recent JOIN core.dim_team AS teams ON teams.team_id = recent.team_id -CROSS JOIN reference_season; +CROSS JOIN reference_season +WHERE teams.is_historical_unmapped = 0; GO CREATE OR ALTER VIEW analytics.vw_q3_player_context_offense AS @@ -99,7 +101,7 @@ SELECT players.player_id, players.full_name AS player_name, teams.team_name, performance.avg_fg_pct AS [Porcentaje de acierto] FROM core.dim_player AS players JOIN core.dim_player_profile AS profile ON profile.player_id = players.player_id -LEFT JOIN analytics.vw_teams AS teams ON teams.team_id = profile.team_id +JOIN analytics.vw_teams AS teams ON teams.team_id = profile.team_id LEFT JOIN team_performance AS performance ON performance.team_id = profile.team_id WHERE profile.nba_flag = 1; GO @@ -107,14 +109,16 @@ GO CREATE OR ALTER VIEW analytics.vw_q4_ppg_by_decade AS SELECT (tg.season_id / 10) * 10 AS decade, AVG(CAST(tg.pts AS FLOAT)) AS league_ppg FROM analytics.vw_team_game AS tg +WHERE tg.team_id BETWEEN 1610610000 AND 1610612766 + AND tg.opponent_team_id BETWEEN 1610610000 AND 1610612766 GROUP BY (tg.season_id / 10) * 10; GO CREATE OR ALTER VIEW analytics.vw_q5_consistency AS SELECT teams.team_name, - CAST(100.0 * STDEV(CAST(metrics.winrate AS FLOAT)) / + CAST(STDEV(CAST(metrics.winrate AS FLOAT)) / NULLIF(AVG(CAST(metrics.winrate AS FLOAT)), 0) AS DECIMAL(24, 12)) AS var_winrate_pct, - CAST(100.0 * STDEV(CAST(metrics.avg_ppg AS FLOAT)) / + CAST(STDEV(CAST(metrics.avg_ppg AS FLOAT)) / NULLIF(AVG(CAST(metrics.avg_ppg AS FLOAT)), 0) AS DECIMAL(24, 12)) AS var_ppg_pct FROM analytics.vw_team_season_metrics AS metrics JOIN analytics.vw_teams AS teams ON teams.team_id = metrics.team_id @@ -164,7 +168,7 @@ CREATE OR ALTER VIEW analytics.vw_q9_physical_profile AS SELECT teams.team_name, COUNT_BIG(*) AS n_players, AVG(profile.height_cm) AS avg_height, AVG(profile.weight) AS avg_weight FROM core.dim_player_profile AS profile -LEFT JOIN analytics.vw_teams AS teams ON teams.team_id = profile.team_id +JOIN analytics.vw_teams AS teams ON teams.team_id = profile.team_id WHERE profile.nba_flag = 1 GROUP BY teams.team_name, profile.team_id; GO diff --git a/CODE/SQL/30_reconciliation.sql b/CODE/SQL/30_reconciliation.sql index 188085f..9c1dc9a 100644 --- a/CODE/SQL/30_reconciliation.sql +++ b/CODE/SQL/30_reconciliation.sql @@ -2,7 +2,10 @@ SELECT (SELECT COUNT_BIG(*) FROM core.fact_game) AS fact_game_rows, (SELECT COUNT_BIG(*) FROM analytics.vw_team_game) AS team_game_rows, + (SELECT COUNT_BIG(*) FROM analytics.vw_team_game AS tg + JOIN analytics.vw_teams AS teams ON teams.team_id = tg.team_id) AS current_team_game_rows, (SELECT COUNT_BIG(*) FROM core.dim_team) AS dim_team_rows, + (SELECT COUNT_BIG(*) FROM analytics.vw_teams) AS analytics_team_rows, (SELECT COUNT_BIG(*) FROM core.dim_team WHERE is_historical_unmapped = 1) AS unresolved_team_rows, (SELECT COUNT_BIG(*) FROM core.dim_player) AS dim_player_rows, (SELECT COUNT_BIG(*) FROM core.dim_player_profile) AS dim_player_profile_rows, diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/00000_textbox (e6685)/config.json b/DOCS/archive/powerbi_pre_i4_visuals/000_Inicio/00000_textbox (e6685)/config.json similarity index 94% rename from CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/00000_textbox (e6685)/config.json rename to DOCS/archive/powerbi_pre_i4_visuals/000_Inicio/00000_textbox (e6685)/config.json index 5e6b499..abf3e0a 100644 --- a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/00000_textbox (e6685)/config.json +++ b/DOCS/archive/powerbi_pre_i4_visuals/000_Inicio/00000_textbox (e6685)/config.json @@ -32,7 +32,7 @@ } }, { - "value": "Descifrando el Rendimiento y Evolución de las franquicias NBA", + "value": "Rendimiento y evolución de las franquicias NBA", "textStyle": { "fontWeight": "bold", "fontSize": "28pt", diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/00000_textbox (e6685)/filters.json b/DOCS/archive/powerbi_pre_i4_visuals/000_Inicio/00000_textbox (e6685)/filters.json similarity index 100% rename from CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/00000_textbox (e6685)/filters.json rename to DOCS/archive/powerbi_pre_i4_visuals/000_Inicio/00000_textbox (e6685)/filters.json diff --git a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/00000_textbox (e6685)/visualContainer.json b/DOCS/archive/powerbi_pre_i4_visuals/000_Inicio/00000_textbox (e6685)/visualContainer.json similarity index 100% rename from CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/000_Inicio/visualContainers/00000_textbox (e6685)/visualContainer.json rename to DOCS/archive/powerbi_pre_i4_visuals/000_Inicio/00000_textbox (e6685)/visualContainer.json diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/10000_textbox (849f8)/config.json" "b/DOCS/archive/powerbi_pre_i4_visuals/003_An\303\241lisis_3/10000_textbox (849f8)/config.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/10000_textbox (849f8)/config.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/003_An\303\241lisis_3/10000_textbox (849f8)/config.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/10000_textbox (849f8)/filters.json" "b/DOCS/archive/powerbi_pre_i4_visuals/003_An\303\241lisis_3/10000_textbox (849f8)/filters.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/10000_textbox (849f8)/filters.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/003_An\303\241lisis_3/10000_textbox (849f8)/filters.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/10000_textbox (849f8)/visualContainer.json" "b/DOCS/archive/powerbi_pre_i4_visuals/003_An\303\241lisis_3/10000_textbox (849f8)/visualContainer.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/003_An\303\241lisis_3/visualContainers/10000_textbox (849f8)/visualContainer.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/003_An\303\241lisis_3/10000_textbox (849f8)/visualContainer.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/05000_Subtitulo/config.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/05000_Subtitulo/config.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/05000_Subtitulo/config.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/05000_Subtitulo/config.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/05000_Subtitulo/filters.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/05000_Subtitulo/filters.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/05000_Subtitulo/filters.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/05000_Subtitulo/filters.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/05000_Subtitulo/visualContainer.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/05000_Subtitulo/visualContainer.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/05000_Subtitulo/visualContainer.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/05000_Subtitulo/visualContainer.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/06000_Subtitulo/config.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/06000_Subtitulo/config.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/06000_Subtitulo/config.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/06000_Subtitulo/config.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/06000_Subtitulo/filters.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/06000_Subtitulo/filters.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/06000_Subtitulo/filters.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/06000_Subtitulo/filters.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/06000_Subtitulo/visualContainer.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/06000_Subtitulo/visualContainer.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/06000_Subtitulo/visualContainer.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/06000_Subtitulo/visualContainer.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/07000_Subtitulo/config.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/07000_Subtitulo/config.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/07000_Subtitulo/config.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/07000_Subtitulo/config.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/07000_Subtitulo/filters.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/07000_Subtitulo/filters.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/07000_Subtitulo/filters.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/07000_Subtitulo/filters.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/07000_Subtitulo/visualContainer.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/07000_Subtitulo/visualContainer.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/07000_Subtitulo/visualContainer.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/07000_Subtitulo/visualContainer.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/08000_Subtitulo/config.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/08000_Subtitulo/config.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/08000_Subtitulo/config.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/08000_Subtitulo/config.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/08000_Subtitulo/filters.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/08000_Subtitulo/filters.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/08000_Subtitulo/filters.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/08000_Subtitulo/filters.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/08000_Subtitulo/visualContainer.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/08000_Subtitulo/visualContainer.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/08000_Subtitulo/visualContainer.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/08000_Subtitulo/visualContainer.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/09000_Subtitulo/config.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/09000_Subtitulo/config.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/09000_Subtitulo/config.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/09000_Subtitulo/config.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/09000_Subtitulo/filters.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/09000_Subtitulo/filters.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/09000_Subtitulo/filters.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/09000_Subtitulo/filters.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/09000_Subtitulo/visualContainer.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/09000_Subtitulo/visualContainer.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/09000_Subtitulo/visualContainer.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/09000_Subtitulo/visualContainer.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/16000_actionButton (a6ab6)/config.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/16000_actionButton (a6ab6)/config.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/16000_actionButton (a6ab6)/config.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/16000_actionButton (a6ab6)/config.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/16000_actionButton (a6ab6)/filters.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/16000_actionButton (a6ab6)/filters.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/16000_actionButton (a6ab6)/filters.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/16000_actionButton (a6ab6)/filters.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/16000_actionButton (a6ab6)/visualContainer.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/16000_actionButton (a6ab6)/visualContainer.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/16000_actionButton (a6ab6)/visualContainer.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/16000_actionButton (a6ab6)/visualContainer.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/17000_actionButton (4e465)/config.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/17000_actionButton (4e465)/config.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/17000_actionButton (4e465)/config.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/17000_actionButton (4e465)/config.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/17000_actionButton (4e465)/filters.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/17000_actionButton (4e465)/filters.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/17000_actionButton (4e465)/filters.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/17000_actionButton (4e465)/filters.json" diff --git "a/CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/17000_actionButton (4e465)/visualContainer.json" "b/DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/17000_actionButton (4e465)/visualContainer.json" similarity index 100% rename from "CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam/Report/sections/006_Conclusi\303\263n/visualContainers/17000_actionButton (4e465)/visualContainer.json" rename to "DOCS/archive/powerbi_pre_i4_visuals/006_Conclusi\303\263n/17000_actionButton (4e465)/visualContainer.json" diff --git a/DOCS/i1_i4_verification.md b/DOCS/i1_i4_verification.md index f49bc5d..0060e70 100644 --- a/DOCS/i1_i4_verification.md +++ b/DOCS/i1_i4_verification.md @@ -1,6 +1,6 @@ # NBA-I1 to NBA-I4 verification -Verification date: **28/08/2026 (America/Argentina/Buenos_Aires)** +Verification date: **10/09/2026 (America/Argentina/Buenos_Aires)** ## Real ETL run @@ -33,19 +33,21 @@ SQL integration evidence from [GitHub Actions run 33223853500](https://github.co - 1946–2022 coverage, 53 explicit historical-team records and zero null, duplicate or missing team keys; - committed result: [`sql_reconciliation.json`](../evidence/NBA-I1-I4/ci-sql/sql_reconciliation.json). +The same load was repeated against local SQL Server 2022 Express on 10/09/2026. It selected the same 15 objects and 65 columns, retained 65,642 games, limited comparison views to 30 current franchises and reconciled all integrity checks to zero. Evidence: [`local-sql-express/sql_reconciliation.json`](../evidence/NBA-I1-I4/local-sql-express/sql_reconciliation.json). + ## Power BI artifact - File: `CODE/Dashboard - POWERBI/Analisis_NBA_BestTeam.pbit`. - Versionable source: adjacent pbi-tools project. - Compiler: pbi-tools Core 1.2.0 on .NET 10 with major roll-forward. -- Power BI Desktop available during compilation: 2.157.879.0. -- Size: **6,374,566 bytes**. -- SHA-256: `18B49F8F2EE420D470358F08A08504C82EAB2CD34040ADD6A5D96756058478F5`. +- Power BI Desktop installed during compilation: 2.157.1354.0. +- Size: **6,372,749 bytes**. +- SHA-256: `16AA1CD74E54334D3D481A780AEEA153D3825231F22C70576623070B436F010F`. - ZIP integrity: compiled successfully with `Report/Layout`, `DataModelSchema` and required package metadata. - Pages: six, ordered from `Inicio` to `Metodología y cierre`. -- SQL source: only `localhost,1433/NBA_Project`; no personal host is embedded. +- SQL source: only `.\SQLEXPRESS/NBA_Project`; no personal host or credential is embedded. -Compilation proves that the extracted report and model produce a valid PBIT package. It does not, by itself, prove a successful DirectQuery refresh. The screenshot protocol therefore requires a loaded local SQL instance and an explicit refresh before publication. +Compilation proves that the extracted report and model produce a valid PBIT package. On **15/09/2026**, the compiled report was opened in Power BI Desktop against the local `.\SQLEXPRESS` instance: the native `SELECT` used by the age-versus-current view was accepted, all six pages rendered, and the streak visual returned the expected ranked values (Lakers 33, Warriors 25, Rockets 22, Spurs 20, Hawks 19). This is local Windows evidence of a successful DirectQuery session; it does not claim a hosted Power BI refresh or a 22 GB synthetic dataset. ## Repeatable commands diff --git a/DOCS/s1_s4_verification.md b/DOCS/s1_s4_verification.md index 625cca9..d04373b 100644 --- a/DOCS/s1_s4_verification.md +++ b/DOCS/s1_s4_verification.md @@ -1,6 +1,6 @@ # NBA-S1 to NBA-S4 verification -Verification date: **10/08/2026** +Verification date: **10/09/2026** ## Scope @@ -13,12 +13,12 @@ Verification date: **10/08/2026** - Format: Power BI template (`Analisis_NBA_BestTeam.pbit`). - Versionable source: adjacent pbi-tools project (`Analisis_NBA_BestTeam/`). -- Size: **6,374,230 bytes**. -- SHA-256: `1D0C1EC57C70E910E3217629926C35615D9D31BEF76DF44E6F166F063265EBBA`. -- Pages: **6**, ordered from `Inicio` through `Conclusión`. +- Size: **6,372,771 bytes**. +- SHA-256: `FDD8498F49F70150D9CB33D20B8080B1A35DD545D91D4C915C7DF2091578F98A`. +- Pages: **6**, ordered from `Inicio` through `Metodología y cierre`. - Converted filters: **4** built-in dropdown slicers. -The PBIT was compiled with pbi-tools Core 1.2.0 and recognized by Power BI Desktop 2.156.951.0. A complete visual refresh could not be performed because the original local SQL Server was unavailable and the current SQL script still lacks model dependencies documented for NBA-I3. +The S4 cleanup is preserved inside the current NBA-I4 artifact. I compiled the PBIT with pbi-tools Core 1.2.0 while Power BI Desktop 2.157.1354.0 was installed. The current SQL model is complete: a local SQL Server 2022 Express load on 10/09/2026 selected all 15 Power BI objects and 65 columns and reconciled integrity to zero. See the current [`NBA-I1 to NBA-I4 verification`](i1_i4_verification.md) for the expanded model and connection evidence. ## Repeatable validation diff --git a/DOCS/technical_documentation.md b/DOCS/technical_documentation.md index 61d1663..455367b 100644 --- a/DOCS/technical_documentation.md +++ b/DOCS/technical_documentation.md @@ -71,7 +71,7 @@ The loader obtains every connection value from environment variables, validates ## 5. Power BI -The semantic model reads 15 objects from the `analytics` schema at `localhost,1433/NBA_Project`. I validate that each TMDL object exists in SQL and that every referenced column can be selected. +The semantic model reads 15 objects from the `analytics` schema at `.\SQLEXPRESS/NBA_Project`. I use this generic local named instance so the published template matches the documented SQL Server Express setup; CI continues to override the loader connection with its isolated container endpoint. I validate that each TMDL object exists in SQL and that every referenced column can be selected. I restructured the report into six pages: @@ -92,6 +92,6 @@ The versioned test factory creates a small, deterministic and clearly synthetic CI also processes the six real committed CSV files, loads their outputs into an ephemeral SQL Server 2022 container, runs independent SQL reconciliation and uploads lightweight evidence. Synthetic fixture results are never presented as the real portfolio volume. -## 7. Remaining operational boundary +## 7. Desktop evidence boundary -Power BI Desktop refresh is a Windows, stateful step. The repository supplies a compiled PBIT, the complete SQL model, a CI-proven database load and a screenshot protocol. A screenshot may be published only after Power BI refreshes against a locally loaded SQL instance; a successful compile alone is not described as a refreshed report. +Power BI Desktop refresh is a Windows, stateful step. The repository supplies a compiled PBIT, the complete SQL model, CI reconciliation and a repeated local SQL Server 2022 Express load. I keep the screenshot protocol separate from package compilation: the PBIT hash proves the exact artifact, while a future screenshot set must also show a completed DirectQuery refresh against the loaded local instance. I do not treat compilation alone as visual refresh evidence. diff --git a/README.md b/README.md index 51a1af5..b6ea8b1 100644 --- a/README.md +++ b/README.md @@ -86,19 +86,19 @@ python -m pytest --cov=nba_pipeline --cov-report=term-missing Copy the variable names from [`CODE/.env.example`](CODE/.env.example) into your own environment and provide a local secret. I do not commit credentials. ```powershell -$env:NBA_SQL_DRIVER = "ODBC Driver 18 for SQL Server" -$env:NBA_SQL_SERVER = "localhost,1433" +$env:NBA_SQL_DRIVER = "ODBC Driver 17 for SQL Server" +$env:NBA_SQL_SERVER = ".\SQLEXPRESS" $env:NBA_SQL_DATABASE = "NBA_Project" -$env:NBA_SQL_TRUSTED_CONNECTION = "no" -$env:NBA_SQL_USER = "sa" -$env:NBA_SQL_PASSWORD = "" +$env:NBA_SQL_TRUSTED_CONNECTION = "yes" +$env:NBA_SQL_ENCRYPT = "no" +$env:NBA_SQL_TRUST_SERVER_CERTIFICATE = "yes" python -m nba_pipeline load-sql ` --run-dir .artifacts\my-first-run ` --evidence-dir evidence\my-first-sql-load ``` -The loader applies the idempotent schema, loads all canonical tables in one transaction, creates the analytical views and verifies every object and column required by Power BI. CI repeats this against an ephemeral SQL Server 2022 container. +The loader applies the idempotent schema, loads all canonical tables in one transaction, creates the analytical views and verifies every object and column required by Power BI. The published PBIT uses the same generic `.\SQLEXPRESS` source. CI overrides these local values and repeats the integration against an ephemeral SQL Server 2022 container. ## 📊 Power BI @@ -122,6 +122,7 @@ Every analytical title states its period or sample and unit. The final page reco - [Versioned contract](contracts/schema_v1.0.0.json) - [Real-run evidence](evidence/NBA-I1-I4/real-run-lf/manifest.json) - [CI SQL reconciliation](evidence/NBA-I1-I4/ci-sql/sql_reconciliation.json) +- [Local SQL Express reconciliation](evidence/NBA-I1-I4/local-sql-express/sql_reconciliation.json) - [Security review](DOCS/security_review.md) ## ⚠️ Boundaries @@ -129,7 +130,7 @@ Every analytical title states its period or sample and unit. The final page reco - The committed dataset is a historical analytical sample, not an official complete NBA warehouse. - The 53 generated team records make historical identifiers explicit; they do not invent franchise metadata. - Duplicate rows remain inspectable in `rejects/`; they are not silently discarded. -- Power BI uses DirectQuery to `localhost,1433`, so you must load SQL Server before refreshing it. +- Power BI uses DirectQuery to `.\SQLEXPRESS`, so you must load SQL Server Express before refreshing it. - Source access, redistribution terms and NBA-related rights must be checked before reuse. ## 👥 Authorship diff --git a/evidence/NBA-I1-I4/local-sql-express/sql_reconciliation.json b/evidence/NBA-I1-I4/local-sql-express/sql_reconciliation.json new file mode 100644 index 0000000..8b435ec --- /dev/null +++ b/evidence/NBA-I1-I4/local-sql-express/sql_reconciliation.json @@ -0,0 +1,43 @@ +{ + "database": "NBA_Project", + "inserted_rows": { + "dim_player": 4831, + "dim_player_profile": 4171, + "dim_team": 83, + "fact_game": 65642, + "fact_game_summary": 58021, + "fact_other_stats": 28261 + }, + "loaded_at_utc": "2026-09-10T17:45:18.085394Z", + "powerbi_contract": { + "columns": 65, + "objects": 15 + }, + "reconciliation": { + "integrity": { + "duplicate_game_keys": 0, + "missing_away_team_keys": 0, + "missing_home_team_keys": 0, + "null_game_keys": 0 + }, + "kpis": { + "analytics_team_rows": 30, + "current_team_game_rows": 128764, + "dim_player_profile_rows": 4171, + "dim_player_rows": 4831, + "dim_team_rows": 83, + "fact_game_rows": 65642, + "fact_game_summary_rows": 58021, + "fact_other_stats_rows": 28261, + "first_season": 1946, + "games_without_result": 2, + "last_season": 2022, + "q1_total_team_games": 128764, + "season_rows": 77, + "team_game_rows": 131284, + "unresolved_team_rows": 53 + } + }, + "run_id": "nba-20260829T002154Z-0af8b4ab23", + "status": "passed" +} diff --git a/scripts/update_powerbi_project_i4.py b/scripts/update_powerbi_project_i4.py index 73fedd7..8a0a0ed 100644 --- a/scripts/update_powerbi_project_i4.py +++ b/scripts/update_powerbi_project_i4.py @@ -21,6 +21,14 @@ } REPLACEMENTS = { + "Descifrando el Rendimiento y Evolución de las franquicias NBA": ( + "Rendimiento y evolución de las franquicias NBA" + ), + "Eficiencia y Consistencia": "Eficiencia y consistencia", + "Porcentaje de balones perdidos por partido": "Pérdidas por partido", + "Total de jugadores fichados": "Mayor muestra de jugadores por equipo", + "Equipos ->": "Equipo", + "Equipo ->": "Equipo", "📈 1- Rendimiento histórico": "1 · Historia y evolución", "🧮 2- Eficiencia y consistencia": "2 · Eficiencia y consistencia", "💪 3- Talento moderno": "3 · Talento y perfil", @@ -92,6 +100,35 @@ def replace_strings(value: object) -> object: return value +def remove_redundant_power_query_renames(text: str) -> str: + """Use the final SQL aliases directly instead of renaming obsolete source columns.""" + lines = text.splitlines() + for index, line in enumerate(lines): + if '"Columnas con nombre cambiado" = Table.RenameColumns' not in line: + continue + if index == 0 or " = NBA_Project{" not in lines[index - 1]: + raise RuntimeError("No se pudo identificar el paso SQL previo al renombrado.") + source_step = lines[index - 1].strip().split(" =", 1)[0] + del lines[index] + for return_index in range(index, min(index + 4, len(lines))): + if '#"Columnas con nombre cambiado"' in lines[return_index]: + indent = lines[return_index][: len(lines[return_index]) - len(lines[return_index].lstrip())] + lines[return_index] = f"{indent}{source_step}" + break + else: + raise RuntimeError("No se encontró la salida del paso de renombrado.") + break + for index, line in enumerate(lines): + if line.strip() != "in": + continue + previous = index - 1 + while previous >= 0 and not lines[previous].strip(): + previous -= 1 + if previous >= 0 and lines[previous].rstrip().endswith(","): + lines[previous] = lines[previous].rstrip()[:-1] + return "\n".join(lines) + "\n" + + def set_position(directory: Path, *, x: float, y: float, width: float, height: float) -> None: config_path = directory / "config.json" config = read_json(config_path) @@ -106,6 +143,62 @@ def set_position(directory: Path, *, x: float, y: float, width: float, height: f write_json(container_path, container) +def update_column_format(path: Path, column_name: str, format_string: str) -> None: + lines = path.read_text(encoding="utf-8-sig").splitlines() + column_markers = {f"column {column_name}", f"column '{column_name}'"} + for index, line in enumerate(lines): + if line.strip() not in column_markers: + continue + block_end = next( + ( + position + for position in range(index + 1, len(lines)) + if lines[position].lstrip().startswith(("column ", "measure ", "partition ")) + ), + len(lines), + ) + for position in range(index + 1, block_end): + if lines[position].strip().startswith("formatString:"): + indent = lines[position][: len(lines[position]) - len(lines[position].lstrip())] + lines[position] = f"{indent}formatString: {format_string}" + path.write_text("\n".join(lines) + "\n", encoding="utf-8", newline="\n") + return + raise RuntimeError(f"La columna {column_name} no tiene formato en {path.name}.") + raise RuntimeError(f"No se encontró la columna {column_name} en {path.name}.") + + +def update_turnover_visual_formats() -> None: + page = SECTIONS / "002_Análisis_2" / "visualContainers" + for directory_name in ( + "01000_Puntos promedio por partido (481ef)", + "07000_Eficiencia de Tiro vs Pérdidas de balón", + ): + path = page / directory_name / "dataTransforms.json" + payload = read_json(path) + for item in payload.get("queryMetadata", {}).get("Select", []): + if "tov_avg" in item.get("Name", ""): + item["Format"] = "0.0" + for item in payload.get("selects", []): + if "tov_avg" in item.get("queryName", ""): + item["format"] = "0.0" + write_json(path, payload) + + +def make_slicer_backgrounds_transparent() -> None: + for path in sorted((PROJECT / "Report" / "sections").rglob("config.json")): + config = read_json(path) + if config.get("singleVisual", {}).get("visualType") != "slicer": + continue + config["singleVisual"].setdefault("vcObjects", {})["background"] = [ + { + "properties": { + "show": {"expr": {"Literal": {"Value": "false"}}} + } + } + ] + write_json(path, config) + + def move_once(source: Path, destination: Path) -> None: if source.exists() and destination.exists(): raise RuntimeError(f"Existen origen y destino: {source} / {destination}") @@ -122,17 +215,164 @@ def update_methodology() -> None: paragraphs = [ "Fuente: seis CSV públicos versionados; 30.638.984 bytes y 161.111 filas de entrada.", "Cobertura: 65.642 partidos únicos entre 1946 y 2022; análisis descriptivo.", + "Alcance visual: 30 franquicias actuales; rivales internacionales, All-Star y equipos sin mapear permanecen auditables en el núcleo, pero no alteran los rankings comparativos.", "Calidad: 155 duplicados en cuarentena y 53 equipos históricos sin nombre actual representados explícitamente.", "Reproducibilidad: contrato v1.0.0, manifiestos SHA-256, reconciliación SQL y pruebas automatizadas.", "Límite: la muestra no es 22 GB, no contiene datos sintéticos y no predice resultados ni retornos financieros.", - "Última validación integral: 28/08/2026.", + "Última validación integral: 10/09/2026.", ] - style = {"fontWeight": "bold", "fontSize": "12pt", "color": "#e6e6e6"} + style = {"fontWeight": "bold", "fontSize": "15pt", "color": "#e6e6e6"} config["singleVisual"]["objects"]["general"][0]["properties"]["paragraphs"] = [ {"textRuns": [{"value": value, "textStyle": style}]} for value in paragraphs ] write_json(path, config) + set_position(path.parent, x=120, y=215, width=1080, height=450) + + title_path = SECTIONS / "006_Conclusión" / "visualContainers" / "10000_textbox (dc975)" + title = read_json(title_path / "config.json") + title["singleVisual"]["objects"]["general"][0]["properties"]["paragraphs"] = [ + { + "textRuns": [ + { + "value": "Metodología y evidencia", + "textStyle": { + "fontWeight": "bold", + "fontSize": "32pt", + "color": "#ffffff", + }, + } + ], + "horizontalTextAlignment": "center", + } + ] + write_json(title_path / "config.json", title) + set_position(title_path, x=120, y=105, width=1080, height=85) + + +def update_player_sample_label() -> None: + path = ( + SECTIONS + / "003_Análisis_3" + / "visualContainers" + / "00000_Subtitulo (66065)" + / "config.json" + ) + config = read_json(path) + config["singleVisual"]["objects"]["general"][0]["properties"]["paragraphs"] = [ + { + "textRuns": [ + {"value": "Mayor muestra de ", "textStyle": {"fontWeight": "bold"}}, + {"value": "jugadores por equipo"}, + ], + "horizontalTextAlignment": "center", + } + ] + write_json(path, config) + + +def update_efficiency_card_labels() -> None: + page = SECTIONS / "002_Análisis_2" / "visualContainers" + labels = { + "00000_Subtitulo (f70c7)": "Pérdidas por partido", + "00000_Subtitulo (4dab6)": "Eficiencia de tiro", + } + for directory_name, label in labels.items(): + path = page / directory_name / "config.json" + config = read_json(path) + config["singleVisual"]["objects"]["general"][0]["properties"]["paragraphs"] = [ + { + "textRuns": [{"value": label, "textStyle": {"fontWeight": "bold"}}], + "horizontalTextAlignment": "center", + } + ] + write_json(path, config) + + +def normalize_streak_visual_source() -> None: + """Keep the streak chart self-contained so it does not depend on a missing model path. + + The analytical view already exposes ``team_name``. Referencing that column + directly avoids a second, unrelated ``vw_teams`` source in the visual query + (and the resulting blank visual in DirectQuery mode). + """ + + directory = SECTIONS / "004_Insights" / "visualContainers" / "11000_Racha histórica" + + def normalize(value: object) -> object: + if isinstance(value, str): + return value.replace( + "analytics vw_teams.team_name", + "analytics vw_q8_longest_win_streak.team_name", + ) + if isinstance(value, list): + return [normalize(item) for item in value] + if isinstance(value, dict): + updated = {key: normalize(item) for key, item in value.items()} + if updated.get("Entity") == "analytics vw_teams": + updated["Entity"] = "analytics vw_q8_longest_win_streak" + if updated.get("Source") == "a1": + updated["Source"] = "a" + return updated + return value + + for filename in ("query.json", "config.json", "dataTransforms.json"): + path = directory / filename + payload = normalize(read_json(path)) + for query in _streak_queries(payload): + sources = query.get("From") + if isinstance(sources, list): + query["From"] = [source for source in sources if source.get("Name") != "a1"] + write_json(path, payload) + + +def _streak_queries(payload: object) -> list[dict]: + """Return query dictionaries nested in the three report JSON shapes.""" + + queries: list[dict] = [] + + def visit(value: object) -> None: + if isinstance(value, dict): + if isinstance(value.get("From"), list): + queries.append(value) + for item in value.values(): + visit(item) + elif isinstance(value, list): + for item in value: + visit(item) + + visit(payload) + return queries + + +def use_native_query_for_q2() -> None: + """Avoid Power Query metadata recursion for the age/current analytical view.""" + + path = PROJECT / "Model" / "tables" / "analytics vw_q2_age_vs_current.tmdl" + text = path.read_text(encoding="utf-8-sig") + if "Value.NativeQuery(Origen" in text: + return + marker = "\tpartition 'analytics vw_q2_age_vs_current' = m" + partition_start = text.find(marker) + if partition_start < 0: + raise RuntimeError("No se encontró la partición M de q2.") + source_start = text.find("\t\t\t\tlet\n", partition_start) + if source_start < 0: + raise RuntimeError("No se encontró el bloque M de q2.") + output_marker = "\n\t\t\t\t analytics_vw_q2_age_vs_current\n" + source_end = text.find(output_marker, source_start) + if source_end < 0: + raise RuntimeError("No se encontró la salida M de q2.") + source_end += len(output_marker) + native = ( + "\t\t\t\tlet\n" + "\t\t\t\t Origen = Sql.Database(\".\\SQLEXPRESS\", \"NBA_Project\"),\n" + "\t\t\t\t Consulta = Value.NativeQuery(Origen, \"SELECT team_name, year_founded, franchise_age, winrate_hist, ppg_hist FROM analytics.vw_q2_age_vs_current\", null, [EnableFolding=true])\n" + "\t\t\t\tin\n" + "\t\t\t\t Consulta\n" + ) + path.write_text(text[:source_start] + native + text[source_end:], encoding="utf-8", newline="\n") + def main() -> int: for folder, display_name in PAGES.items(): @@ -168,18 +408,111 @@ def main() -> int: for name in ("05000_Subtitulo", "07000_textbox (9fccf)"): move_once(target_visuals / name, ARCHIVE / "004_Insights" / name) + move_once( + SECTIONS + / "000_Inicio" + / "visualContainers" + / "00000_textbox (e6685)", + ARCHIVE / "000_Inicio" / "00000_textbox (e6685)", + ) + + conclusion_visuals = SECTIONS / "006_Conclusión" / "visualContainers" + for name in ( + "05000_Subtitulo", + "06000_Subtitulo", + "07000_Subtitulo", + "08000_Subtitulo", + "09000_Subtitulo", + "16000_actionButton (a6ab6)", + "17000_actionButton (4e465)", + ): + move_once(conclusion_visuals / name, ARCHIVE / "006_Conclusión" / name) + + move_once( + source_visuals / "10000_textbox (849f8)", + ARCHIVE / "003_Análisis_3" / "10000_textbox (849f8)", + ) + for path in sorted((PROJECT / "Report").rglob("*.json")): write_json(path, replace_strings(read_json(path))) for path in sorted((PROJECT / "Model" / "tables").glob("*.tmdl")): text = path.read_text(encoding="utf-8-sig") - updated = text.replace( - 'Sql.Databases("100.74.116.125,1433")', 'Sql.Databases("localhost,1433")' + updated = text + for previous_server in ("100.74.116.125,1433", "localhost,1433"): + updated = updated.replace( + f'Sql.Databases("{previous_server}")', + 'Sql.Database(".\\SQLEXPRESS", "NBA_Project")', + ) + updated = updated.replace( + 'Origen = Sql.Databases(".\\SQLEXPRESS"),\n' + ' NBA_Project = Origen{[Name="NBA_Project"]}[Data],', + 'Origen = Sql.Database(".\\SQLEXPRESS", "NBA_Project"),', ) + updated = updated.replace('= NBA_Project{[Schema=', '= Origen{[Schema=') + updated = remove_redundant_power_query_renames(updated) if updated != text: path.write_text(updated, encoding="utf-8", newline="\n") + update_column_format( + PROJECT / "Model" / "tables" / "analytics vw_q7_balance_of_def.tmdl", + "Balones perdidos", + "0.0", + ) + update_turnover_visual_formats() + make_slicer_backgrounds_transparent() + + set_position( + SECTIONS + / "001_Análisis_1" + / "visualContainers" + / "08000_advancedSlicerVisual (34242)", + x=963, + y=85, + width=346, + height=90, + ) + set_position( + SECTIONS / "002_Análisis_2" / "visualContainers" / "10000_advancedSlicerVisual (b0ea8)", + x=995, + y=85, + width=314, + height=90, + ) + set_position( + SECTIONS / "002_Análisis_2" / "visualContainers" / "09000_advancedSlicerVisual (fa73f)", + x=942, + y=227, + width=367, + height=90, + ) + set_position( + source_visuals / "05000_Eficiencia ofensiva de equipos NBA", + x=16, + y=161, + width=1279, + height=324, + ) + set_position( + source_visuals / "03000_Perfil físico promedio de los equipos NBA", + x=16, + y=500, + width=900, + height=249, + ) + set_position( + source_visuals / "08000_advancedSlicerVisual (a910c)", + x=930, + y=500, + width=365, + height=90, + ) + update_methodology() + update_player_sample_label() + update_efficiency_card_labels() + normalize_streak_visual_source() + use_native_query_for_q2() print("I4 aplicado: seis páginas, dos visuales redistribuidos y origen SQL local.") return 0 diff --git a/scripts/validate_i1_i4.py b/scripts/validate_i1_i4.py index 3f422e1..c163b5e 100644 --- a/scripts/validate_i1_i4.py +++ b/scripts/validate_i1_i4.py @@ -11,7 +11,9 @@ ROOT = Path(__file__).resolve().parents[1] EVIDENCE = ROOT / "evidence" / "NBA-I1-I4" / "real-run-lf" -SQL_EVIDENCE = ROOT / "evidence" / "NBA-I1-I4" / "ci-sql" / "sql_reconciliation.json" +SQL_EVIDENCE = ( + ROOT / "evidence" / "NBA-I1-I4" / "local-sql-express" / "sql_reconciliation.json" +) PBIT = ROOT / "CODE" / "Dashboard - POWERBI" / "Analisis_NBA_BestTeam.pbit" PROJECT = ROOT / "CODE" / "Dashboard - POWERBI" / "Analisis_NBA_BestTeam" EXPECTED_TOTALS = { @@ -30,8 +32,8 @@ "Metodología y cierre": 5, } EXPECTED_PBIT = { - "bytes": 6_374_566, - "sha256": "18B49F8F2EE420D470358F08A08504C82EAB2CD34040ADD6A5D96756058478F5", + "bytes": 6_372_749, + "sha256": "16AA1CD74E54334D3D481A780AEEA153D3825231F22C70576623070B436F010F", } @@ -83,11 +85,15 @@ def validate_model_files() -> None: require(len(tables) == 15, "Power BI does not expose 15 TMDL objects") for path in tables: text = path.read_text(encoding="utf-8") - require('Sql.Databases("localhost,1433")' in text, f"Non-portable source: {path.name}") + require( + 'Sql.Database(".\\SQLEXPRESS", "NBA_Project")' in text, + f"Unexpected source: {path.name}", + ) require("100.74.116.125" not in text, f"Former personal host remains: {path.name}") + require("Table.RenameColumns" not in text, f"Stale Power Query rename: {path.name}") sql_evidence = read_json(SQL_EVIDENCE) - require(sql_evidence["status"] == "passed", "CI SQL load is not passed") + require(sql_evidence["status"] == "passed", "Local SQL Express load is not passed") require(sum(sql_evidence["inserted_rows"].values()) == 161_009, "SQL loaded rows changed") require( sql_evidence["powerbi_contract"] == {"columns": 65, "objects": 15}, @@ -100,6 +106,11 @@ def validate_model_files() -> None: sql_evidence["reconciliation"]["kpis"]["team_game_rows"] == 131_284, "Team-game grain changed", ) + kpis = sql_evidence["reconciliation"]["kpis"] + require(kpis["analytics_team_rows"] == 30, "Analytical franchise scope changed") + require(kpis["current_team_game_rows"] == 128_764, "Current-team grain changed") + require(kpis["q1_total_team_games"] == 128_764, "Q1 visual grain changed") + require(kpis["fact_game_rows"] == 65_642, "Unique-game total changed") def validate_report() -> None: @@ -118,9 +129,20 @@ def validate_report() -> None: "2013–2022", "30.638.984 bytes", "155 duplicados", - "Última validación integral", + "Última validación integral: 10/09/2026.", + "Pérdidas por partido", + "Eficiencia de tiro", ): require(required in report_text, f"Report methodology/title evidence missing: {required}") + require( + not ( + sections + / "000_Inicio" + / "visualContainers" + / "00000_textbox (e6685)" + ).exists(), + "Duplicate cover title layer remains active", + ) require(PBIT.stat().st_size == EXPECTED_PBIT["bytes"], "PBIT byte size changed") digest = hashlib.sha256(PBIT.read_bytes()).hexdigest().upper() diff --git a/scripts/validate_s1_s4.py b/scripts/validate_s1_s4.py index f0d6585..d3a4ceb 100644 --- a/scripts/validate_s1_s4.py +++ b/scripts/validate_s1_s4.py @@ -120,10 +120,14 @@ def validate_security(check: Check) -> None: if line and not line.startswith("#") and "=" in line for key, value in (line.split("=", 1),) } - check.require(env_lines.get("NBA_SQL_USER") == "sa", ".env.example lacks the local demo username") check.require( - env_lines.get("NBA_SQL_PASSWORD") == "replace_with_a_local_secret", - ".env.example does not use the expected password placeholder", + env_lines.get("NBA_SQL_TRUSTED_CONNECTION") == "yes", + ".env.example does not use local Windows authentication", + ) + check.require("NBA_SQL_USER" not in env_lines, ".env.example must not define a demo username") + check.require( + "NBA_SQL_PASSWORD" not in env_lines, + ".env.example must not define or suggest a committed password value", ) audit_log = read(ROOT / "CODE" / "etl_audit_log.txt") @@ -150,7 +154,8 @@ def validate_powerbi_source(check: Check) -> None: payloads.append(json.loads(read(path))) except json.JSONDecodeError as exc: check.failures.append(f"Invalid JSON: {path.relative_to(ROOT)} ({exc})") - check.require(len(json_files) >= 850, f"Power BI extraction looks incomplete: {len(json_files)} JSON files") + # I4 intentionally archives obsolete visual containers outside the active project. + check.require(len(json_files) >= 840, f"Power BI extraction looks incomplete: {len(json_files)} JSON files") sections = PROJECT / "Report" / "sections" page_dirs = sorted(path for path in sections.iterdir() if path.is_dir()) diff --git a/src/nba_pipeline/model_validation.py b/src/nba_pipeline/model_validation.py index 0ef5671..e96f48a 100644 --- a/src/nba_pipeline/model_validation.py +++ b/src/nba_pipeline/model_validation.py @@ -22,18 +22,21 @@ def powerbi_contract() -> dict[str, dict[str, Any]]: text = path.read_text(encoding="utf-8-sig") table_match = re.search(r"(?m)^table\s+(.+)$", text) object_match = re.search(r'\[Schema="([^"]+)",Item="([^"]+)"\]', text) - if not table_match or not object_match: + native_object_match = re.search(r"(?i)\bFROM\s+analytics\.([A-Za-z0-9_]+)", text) + if not table_match or (not object_match and not native_object_match): raise ValueError(f"TMDL incompleto: {path.relative_to(ROOT)}") table = table_match.group(1).strip().strip("'") + schema = object_match.group(1) if object_match else "analytics" + object_name = object_match.group(2) if object_match else native_object_match.group(1) columns = [ match.group(1).strip().strip("'") for match in re.finditer(r"(?m)^\s*column\s+(.+)$", text) ] - servers = sorted(set(re.findall(r'Sql\.Databases\("([^"]+)"\)', text))) + servers = sorted(set(re.findall(r'Sql\.Database\("([^"]+)"\s*,\s*"NBA_Project"\)', text))) objects[table] = { "file": path.relative_to(ROOT).as_posix(), - "schema": object_match.group(1), - "object": object_match.group(2), + "schema": schema, + "object": object_name, "columns": columns, "servers": servers, } @@ -66,10 +69,15 @@ def validate_static_model() -> dict[str, Any]: marker = f"CREATE OR ALTER VIEW analytics.{details['object']}" if marker.lower() not in sql.lower(): raise ValueError(f"El SQL no crea el objeto requerido: {details['object']}") - if details["servers"] != ["localhost,1433"]: + if details["servers"] != [r".\SQLEXPRESS"]: raise ValueError( f"Origen Power BI no portable en {details['file']}: {details['servers']}" ) + tmdl = (ROOT / details["file"]).read_text(encoding="utf-8-sig") + if "Table.RenameColumns" in tmdl: + raise ValueError( + f"Power Query todavía renombra columnas que el SQL ya publica: {details['file']}" + ) if re.search(r"(?im)^\s*DELETE\s+FROM\s+(?:\[?core\]?|\[?analytics\]?)", sql): raise ValueError("El modelo analítico contiene un borrado silencioso.") return {"powerbi_objects": len(objects), "contract_version": SCHEMA_VERSION} diff --git a/src/nba_pipeline/sql_loader.py b/src/nba_pipeline/sql_loader.py index 8cd0ce9..861edc3 100644 --- a/src/nba_pipeline/sql_loader.py +++ b/src/nba_pipeline/sql_loader.py @@ -247,8 +247,10 @@ def load_sql_server(run_dir: Path, evidence_dir: Path | None = None) -> dict[str integrity = sql_reconciliation["integrity"] if int(kpis["team_game_rows"]) != int(kpis["fact_game_rows"]) * 2: raise RuntimeError("La vista equipo-partido no reconcilia 2 filas por juego.") - if int(kpis["q1_total_team_games"]) != int(kpis["team_game_rows"]): - raise RuntimeError("La pregunta histórica no reconcilia con equipo-partido.") + if int(kpis["analytics_team_rows"]) != 30: + raise RuntimeError("La capa analítica no contiene las 30 franquicias actuales.") + if int(kpis["q1_total_team_games"]) != int(kpis["current_team_game_rows"]): + raise RuntimeError("La pregunta histórica no reconcilia con las franquicias actuales.") if any(int(value or 0) for value in integrity.values()): raise RuntimeError(f"Integridad SQL incumplida: {integrity}")