├── fonts ├── fa-solid-900.ttf ├── fa-brands-400.ttf └── fa-regular-400.ttf ├── R ├── 2024 │ ├── week_09 │ │ ├── dificultades.csv │ │ └── README.md │ ├── week_07 │ │ └── README.md │ ├── week_08 │ │ └── README.md │ ├── week_01 │ │ ├── README.md │ │ └── eolica.csv │ ├── week_03 │ │ ├── README.md │ │ └── 2024_w03_calendar.R │ ├── week_05 │ │ ├── README.md │ │ └── salarios.csv │ ├── week_02 │ │ ├── README.md │ │ ├── eco_farms_poland.csv │ │ └── 2024_w02_lego_map.R │ ├── week_04 │ │ └── README.md │ ├── week_10 │ │ ├── README.md │ │ └── gender_pay_gap_2022.csv │ ├── week_11 │ │ └── README.md │ ├── week_06 │ │ ├── README.md │ │ └── median_net_wealth_by_age.csv │ ├── week_12 │ │ ├── README.md │ │ ├── portfolio.csv │ │ └── 2024_w12_portfolio.R │ ├── week_47 │ │ └── forecast_11_2024.csv │ └── week_49 │ │ └── 2024_w47.R ├── 30DayChartChallenge2024 │ ├── day_18 │ │ ├── KIDB.xlsx │ │ ├── exchange.csv │ │ └── day_18_asian_development_bank.R │ ├── theme │ │ ├── fa-brands-400.ttf │ │ ├── fa-solid-900.ttf │ │ └── styles.R │ ├── day_14 │ │ ├── no2_calendar_data.csv │ │ └── day_14_heatmap.R │ ├── day_08 │ │ ├── pm10_mean_zona_2001.RDS │ │ └── day_8_circular.R │ ├── day_03 │ │ ├── Public_Awareness_Around_Antibiotic_Resistance.png │ │ └── day_3_makeover.R │ ├── day_22 │ │ └── rail_passengers.csv │ ├── day_02 │ │ ├── death-rates-from-energy-production-per-twh.csv │ │ └── day_02_neo.R │ ├── day_13 │ │ ├── storks.csv │ │ └── day_13_family.R │ ├── day_10 │ │ ├── physical.csv │ │ └── day_10_physical.R │ ├── day_27 │ │ ├── forecast.csv │ │ └── day_27_GoodBad.R │ ├── day_21 │ │ ├── energy.csv │ │ └── day_21_green_energy.R │ ├── day_26 │ │ ├── ai.csv │ │ └── day_26_AI.R │ ├── day_07 │ │ ├── hectares_burned_spain.csv │ │ └── day_7_hazards.R │ ├── day_29 │ │ └── day_29_black_n_white.R │ ├── day_17 │ │ └── day_17_networks.R │ ├── day_01 │ │ └── day_01_part_to_whole.R │ ├── day_24 │ │ └── day_24_ILO_Africa.R │ ├── day_09 │ │ └── day_9_major_minor.R │ ├── day_19 │ │ ├── multiTimeline.csv │ │ └── day_19_dinosaurs.R │ ├── day_05 │ │ └── day_5_diverging.R │ ├── cfg │ │ └── plots.yml │ ├── day_15 │ │ └── day_15_historical.R │ ├── day_20 │ │ └── day_20_correlation.R │ └── day_28 │ │ └── trend_tourist.csv └── 30DayChartChallenge2025 │ ├── data │ ├── day_1.csv │ ├── day_4.csv │ ├── ipca_mensual.csv │ ├── epa_paro_ccaa.csv │ ├── ipv_trimestral.csv │ ├── salario_modal.csv │ └── Distritos │ │ ├── DISTRITOS.sbn │ │ └── DISTRITOS.sbx │ ├── category_4_timeseries │ ├── day_22_stars │ │ └── day_22.R │ ├── day_19_smooth │ │ └── day_19.R │ ├── day_23_logscale │ │ └── day_23.R │ └── day_24_who │ │ └── day_24.R │ ├── category_1_comparisons │ ├── day_1_fractions │ │ └── day_1.R │ └── day_5_ranking │ │ └── day_5.R │ ├── category_3_relationships │ ├── day_15_complicated │ │ └── day_15.R │ └── day_18_el_pais │ │ └── day_18.R │ ├── utils.R │ ├── category_2_distributions │ └── day_11_stripes │ │ └── day_11.R │ ├── 30DayChartChallenge2025.yml │ └── category_5_uncertainties │ └── day_28_inclusion │ └── day_28.R ├── dataviz.Rproj ├── LICENSE ├── .gitignore └── README.md /fonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/fonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /fonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/fonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /fonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/fonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /R/2024/week_09/dificultades.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/2024/week_09/dificultades.csv -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_18/KIDB.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2024/day_18/KIDB.xlsx -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/data/day_1.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2025/data/day_1.csv -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/data/day_4.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2025/data/day_4.csv -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/data/ipca_mensual.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2025/data/ipca_mensual.csv -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/theme/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2024/theme/fa-brands-400.ttf -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/theme/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2024/theme/fa-solid-900.ttf -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/data/epa_paro_ccaa.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2025/data/epa_paro_ccaa.csv -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/data/ipv_trimestral.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2025/data/ipv_trimestral.csv -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/data/salario_modal.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2025/data/salario_modal.csv -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_14/no2_calendar_data.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2024/day_14/no2_calendar_data.csv -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/data/Distritos/DISTRITOS.sbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2025/data/Distritos/DISTRITOS.sbn -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/data/Distritos/DISTRITOS.sbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2025/data/Distritos/DISTRITOS.sbx -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_08/pm10_mean_zona_2001.RDS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2024/day_08/pm10_mean_zona_2001.RDS -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_03/Public_Awareness_Around_Antibiotic_Resistance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michal0091/dataviz/HEAD/R/30DayChartChallenge2024/day_03/Public_Awareness_Around_Antibiotic_Resistance.png -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_22/rail_passengers.csv: -------------------------------------------------------------------------------- 1 | year;rail_passengers 2 | 2015;375.713 3 | 2016;384.335 4 | 2017;394.142 5 | 2018;400.427 6 | 2019;413.923 7 | 2020;223.668 8 | 2021;260.715 9 | 2022;393.376 10 | -------------------------------------------------------------------------------- /dataviz.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | -------------------------------------------------------------------------------- /R/2024/week_07/README.md: -------------------------------------------------------------------------------- 1 | # dataviz: week 7 2 | 3 | cci 4 | -------------------------------------------------------------------------------- /R/2024/week_08/README.md: -------------------------------------------------------------------------------- 1 | # dataviz: week 8 2 | 3 | iris 4 | -------------------------------------------------------------------------------- /R/2024/week_01/README.md: -------------------------------------------------------------------------------- 1 | # dataviz 2024: week 1 2 | 3 | eolica 4 | -------------------------------------------------------------------------------- /R/2024/week_03/README.md: -------------------------------------------------------------------------------- 1 | # dataviz: week 3 2 | 3 | calendar_2024 4 | -------------------------------------------------------------------------------- /R/2024/week_05/README.md: -------------------------------------------------------------------------------- 1 | # dataviz: week 5 2 | 3 | choropleth_map 4 | -------------------------------------------------------------------------------- /R/2024/week_02/README.md: -------------------------------------------------------------------------------- 1 | # dataviz: week 2 2 | 3 | eco_farms_poland 4 | -------------------------------------------------------------------------------- /R/2024/week_04/README.md: -------------------------------------------------------------------------------- 1 | # dataviz: week 4 2 | 3 | ideology_gap_spain 4 | -------------------------------------------------------------------------------- /R/2024/week_10/README.md: -------------------------------------------------------------------------------- 1 | # dataviz 2024: week 10 2 | 3 | gender_pay_gap 4 | -------------------------------------------------------------------------------- /R/2024/week_11/README.md: -------------------------------------------------------------------------------- 1 | # dataviz 2024: week 11 2 | 3 | rainfall_retiro 4 | -------------------------------------------------------------------------------- /R/2024/week_06/README.md: -------------------------------------------------------------------------------- 1 | # dataviz: week 6 2 | 3 | wealth_age_head_family 4 | -------------------------------------------------------------------------------- /R/2024/week_12/README.md: -------------------------------------------------------------------------------- 1 | # dataviz 2024: week 12 2 | 3 | portfolio_distr_plot 4 | -------------------------------------------------------------------------------- /R/2024/week_09/README.md: -------------------------------------------------------------------------------- 1 | # dataviz 2024: week 9 2 | 3 | end_of_month_difficulties 4 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_02/death-rates-from-energy-production-per-twh.csv: -------------------------------------------------------------------------------- 1 | Entity,Code,Year,Deaths per TWh of electricity production 2 | Biomass,,2021,4.63 3 | Brown coal,,2021,32.72 4 | Coal,,2021,24.62 5 | Gas,,2021,2.821 6 | Hydropower,,2021,1.3 7 | Nuclear,,2021,0.03 8 | Oil,,2021,18.43 9 | Solar,,2021,0.019 10 | Wind,,2021,0.035 -------------------------------------------------------------------------------- /R/2024/week_01/eolica.csv: -------------------------------------------------------------------------------- 1 | CCAA,2012,2022 2 | Castilla y León,11350,13796 3 | Aragón,4447,10200 4 | Galicia,8066,9720 5 | Castilla La-Mancha,7944,8360 6 | Andalucía,5731,6980 7 | Navarra,2678,3203 8 | Cataluña,2647,2455 9 | Comunidad Valenciana,2548,1995 10 | Asturias,883,1422 11 | Canarias,362,1369 12 | La Rioja,1006,849 13 | Región de Murcia,401,410 14 | País Vasco,340,320 15 | Extremadura,0,123 16 | Cantabria,62,79 17 | Islas Baleares,6,2 18 | Comunidad de Madrid,0,0 19 | -------------------------------------------------------------------------------- /R/2024/week_02/eco_farms_poland.csv: -------------------------------------------------------------------------------- 1 | NAME_1,farms,eco_farms 2 | Dolnośląskie,55993,761 3 | Kujawsko-Pomorskie,63830,420 4 | Łódzkie,179994,1926 5 | Lubelskie,20236,1139 6 | Lubuskie,124032,538 7 | Małopolskie,139923,634 8 | Mazowieckie,212917,2393 9 | Opolskie,26919,74 10 | Podkarpackie,132851,886 11 | Podlaskie,81181,4047 12 | Pomorskie,39049,586 13 | Śląskie,54503,139 14 | Świętokrzyskie,85308,571 15 | Warmińsko-Mazurskie,43165,3654 16 | Wielkopolskie,121157,848 17 | Zachodniopomorskie,29646,2577 18 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_13/storks.csv: -------------------------------------------------------------------------------- 1 | Country,Area,Storks,Humans,Birth 2 | Albania,28750,100,3.2,83 Austria,83860,300,7.6,87 Belgium,30520,1,9.9,118 Bulgaria,111000,5000,9.0,117 Denmark,43100,9,5.1,59 France,544000,140,56,774 Germany,357000,3300,78,901 Greece,132000,2500,10,106 Holland,41900,4,15,188 Hungary,93000,5000,11,124 Italy,301280,5,57,551 Poland,312680,30000,38,610 Portugal,92390,1500,10,120 Romania,237500,5000,23,367 Spain,504750,8000,39,439 Switzerland,41290,150,6.7,82 Turkey,779450,25000,56,1576 -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_10/physical.csv: -------------------------------------------------------------------------------- 1 | date;position;week;year 2 | 1981-10-03;66;1;1981 3 | 1981-10-10;47;2;1981 4 | 1981-10-17;31;3;1981 5 | 1981-10-24;26;4;1981 6 | 1981-10-31;23;5;1981 7 | 1981-11-07;14;6;1981 8 | 1981-11-14;3;7;1981 9 | 1981-11-21;1;8;1981 10 | 1981-11-28;1;9;1981 11 | 1981-12-05;1;10;1981 12 | 1981-12-12;1;11;1981 13 | 1981-12-19;1;12;1981 14 | 1981-12-26;1;13;1981 15 | 1982-01-02;1;14;1982 16 | 1982-01-09;1;15;1982 17 | 1982-01-16;1;16;1982 18 | 1982-01-23;1;17;1982 19 | 1982-01-30;4;18;1982 20 | 1982-02-06;7;19;1982 21 | 1982-02-13;8;20;1982 22 | 1982-02-20;9;21;1982 23 | 1982-02-27;17;22;1982 24 | 1982-03-06;31;23;1982 25 | 1982-03-13;46;24;1982 26 | 1982-03-20;56;25;1982 27 | 1982-03-27;95;26;1982 28 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_27/forecast.csv: -------------------------------------------------------------------------------- 1 | previsiones;pib_2024;pib_2025 2 | Analistas Financieros Internacionales (AFI);1,8;1,8 3 | BBVA Research;2,1;2 4 | CaixaBank Research;1,9;2,2 5 | Cámara de Comercio de España;2;1,9 6 | Centro de Estudios Economía de Madrid (CEEM-URJC);1,9;2,3 7 | Centro de Predicción Económica (CEPREDE-UAM);2,1;2,4 8 | CEOE;1,8;2 9 | Equipo Económico (Ee);2,1;2 10 | EthiFinance Ratings;1,9;2 11 | Funcas;1,8;2 12 | Instituto Complutense de Análisis Económico (ICAE-UCM);2,1;2 13 | Instituto de Estudios Económicos (IEE);1,7;1,9 14 | Intermoney;1,8;1,7 15 | Mapfre Economics;1,4;1,8 16 | Metyis;2;2 17 | Oxford Economics;2,1;1,7 18 | Repsol;1,5;2,3 19 | Santander;1,8;2 20 | Universidad Loyola Andalucía;1,8;1,5 21 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_21/energy.csv: -------------------------------------------------------------------------------- 1 | year;Portugal;Italy;Greece;Spain;EU27 2 | 2004;27,39;16,086;7,842;19,018;15,871 3 | 2005;27,703;16,293;8,213;19,166;16,402 4 | 2006;29,308;15,926;8,924;20,027;16,879 5 | 2007;32,285;15,954;9,33;21,718;17,647 6 | 2008;34,063;16,645;9,646;23,777;18,526 7 | 2009;37,562;18,807;11,016;27,882;20,654 8 | 2010;40,608;20,091;12,307;29,748;21,283 9 | 2011;45,78;23,546;13,81;31,53;23,3 10 | 2012;47,505;27,42;16,364;33,438;25,138 11 | 2013;49,101;31,302;21,241;36,027;26,769 12 | 2014;52,054;33,42;21,923;37,128;28,601 13 | 2015;52,616;33,459;22,089;36,972;29,655 14 | 2016;53,99;34,012;22,657;36,676;30,172 15 | 2017;54,168;34,104;24,464;36,465;31,104 16 | 2018;52,186;33,93;26,001;35,236;32,134 17 | 2019;53,774;34,969;31,295;37,131;34,086 18 | 2020;58,032;38,081;35,856;42,944;37,408 19 | 2021;58,433;35,996;35,934;46,001;37,754 20 | 2022;60,959;37,102;42,408;50,902;41,174 21 | -------------------------------------------------------------------------------- /R/2024/week_47/forecast_11_2024.csv: -------------------------------------------------------------------------------- 1 | previsiones;pib_2024_04_2024;pib_2025_04_2024;pib_2024_11_2024;pib_2025_11_2024 2 | Analistas Financieros Internacionales (AFI);1,8;1,8;3,1;2,6 3 | BBVA Research;2,1;2;2,9;2,4 4 | CaixaBank Research;1,9;2,2;2,8;2,3 5 | Cámara de Comercio de España;2;1,9;3,1;2,1 6 | Centro de Estudios Economía de Madrid (CEEM-URJC);1,9;2,3;3,2;3,1 7 | Centro de Predicción Económica (CEPREDE-UAM);2,1;2,4;3;2,3 8 | CEOE;1,8;2;3,1;2,3 9 | Equipo Económico (Ee);2,1;2;3,1;2,2 10 | EthiFinance Ratings;1,9;2;3;2,3 11 | Funcas;1,8;2;3;2,1 12 | Instituto Complutense de Análisis Económico (ICAE-UCM);2,1;2;3;2,4 13 | Instituto de Estudios Económicos (IEE);1,7;1,9;3;2,1 14 | Intermoney;1,8;1,7;2,9;2,1 15 | Mapfre Economics;1,4;1,8;2,9;2,1 16 | Metyis;2;2;3,1;2,4 17 | Oxford Economics;2,1;1,7;3,1;2,4 18 | Repsol;1,5;2,3;3;2,3 19 | Santander;1,8;2;2,9;2,4 20 | Universidad Loyola Andalucía;1,8;1,5;2,9;2,5 21 | -------------------------------------------------------------------------------- /R/2024/week_05/salarios.csv: -------------------------------------------------------------------------------- 1 | id,country,gross,net,coin,city,rental_one_bedroom,pe 2 | UK,United Kingdom,40518,32733,"1,1589",London,1800,"0,65988" 3 | FR,France,30833,24144,1,Paris,1880,"0,93439" 4 | ES,Spain,21638,17559,1,Madrid,1350,"0,9226" 5 | DE,Germany,43842,28128,1,Berlin,1600,"0,68259" 6 | IT,Italy,25000,20000,1,Rome,1950,"1,17" 7 | PL,Poland,15162,11214,"0,2216",Warsaw,730,"0,78117" 8 | NL,Netherlands,44000,35092,1,Amsterdam,2300,"0,7865" 9 | SE,Sweden,36250,25628,"0,088329",Stockholm,1325,"0,62042" 10 | BE,Belgium,42084,33796,1,Brussels,1200,"0,42609" 11 | NO,Norway,49656,32957,"0,086787",Oslo,1300,"0,47334" 12 | IE,Ireland,45537,36513,1,Dublin,1650,"0,54227" 13 | AT,Austria,30635,20381,1,Vienna,1200,"0,70654" 14 | DK,Danmark,37411,25253,"0,13409",Copenhagen,1200,"0,57023" 15 | RO,Romania,19618,11477,"0,20109",Bucharest,400,"0,41823" 16 | FI,Finland,38736,23895,1,Helsinki,1340,"0,67294" 17 | CZ,Czech Republic,16970,13706,"0,040705",Prague,950,"0,83175" 18 | PT,Portugal,11512,10236,1,Lisbon,1300,"1,52403" 19 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_18/exchange.csv: -------------------------------------------------------------------------------- 1 | country;exchange_rate;region 2 | Brunei Darussalam;1,40;Southeast Asia 3 | Cambodia;4118,00;Southeast Asia 4 | Indonesia;15731,00;Southeast Asia 5 | Lao People’s Democratic Republic;16600,00;Southeast Asia 6 | Malaysia;4,40;Southeast Asia 7 | Myanmar;1329,10;Southeast Asia 8 | Philippines;56,10;Southeast Asia 9 | Singapore;1,34;Southeast Asia 10 | Thailand;34,56;Southeast Asia 11 | Viet Nam;23612,00;Southeast Asia 12 | Bangladesh;99,00;South Asia 13 | India;82,80;South Asia 14 | Nepal;131,90;South Asia 15 | Pakistan;226,50;South Asia 16 | Sri Lanka;363,10;South Asia 17 | Armenia;393,60;Central and West Asia 18 | Azerbaijan;1,70;Central and West Asia 19 | Georgia;2,70;Central and West Asia 20 | Kazakhstan;462,70;Central and West Asia 21 | Kyrgyz Rep.;85,70;Central and West Asia 22 | Tajikistan;10,20;Central and West Asia 23 | Uzbekistan;11225,50;Central and West Asia 24 | Fiji, Rep. of;2,20;Pacific Islands 25 | Papua New Guinea;3,50;Pacific Islands 26 | Samoa;2,70;Pacific Islands 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Michal Kinel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_26/ai.csv: -------------------------------------------------------------------------------- 1 | Type;Group;Hardly ever or never;Some of the time or occasionally;Often or always 2 | All;All adults;33;50;17 3 | Sex;Women;38;49;13 4 | Sex;Men;29;50;21 5 | Age;Aged 16 to 29;20;49;31 6 | Age;Aged 30 to 49;27;55;18 7 | Age;Aged 50 to 69;37;51;12 8 | Age;Aged 70 and over;55;36;8 9 | Ethnic group;Asian or Asian British;33;47;20 10 | Ethnic group;Black African Caribbean or Black British;33;42;25 11 | Ethnic group;Mixed or Multiple ethnic groups;20;43;36 12 | Ethnic group;White;34;50;16 13 | Ethnic group;Any other ethnic group;30;57;12 14 | Disabled;Disabled;38;47;15 15 | Disabled;Non-disabled;31;51;18 16 | Degree ;Degree or equivalent;20;58;22 17 | Degree ;No degree;39;46;15 18 | Occupation;Managers directors and senior officials;25;58;17 19 | Occupation;Professional occupations;18;58;24 20 | Occupation;Associate professional occupations;21;59;21 21 | Occupation;Administrative and secretarial occupations;35;52;14 22 | Occupation;Skilled trades occupations;32;51;18 23 | Occupation;Caring leisure and other service occupations;44;46;11 24 | Occupation;Sales and customer service occupations;32;54;14 25 | Occupation;Process plant and machine operatives;36;52;12 26 | Occupation;Elementary occupations;36;46;18 27 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_07/hectares_burned_spain.csv: -------------------------------------------------------------------------------- 1 | year,hectares_burned 2 | 1961,46251 3 | 1962,55482 4 | 1963,22679 5 | 1964,31398 6 | 1965,38018 7 | 1966,49354 8 | 1967,76575 9 | 1968,55702 10 | 1969,"53171,6" 11 | 1970,"87438,5" 12 | 1971,"34312,4" 13 | 1972,"55920,1" 14 | 1973,"95072,5" 15 | 1974,"139927,5" 16 | 1975,"180136,9" 17 | 1976,"121514,1" 18 | 1977,"68870,9" 19 | 1978,"424957,9" 20 | 1979,"197655,05" 21 | 1980,"261514,8" 22 | 1981,"291417,1" 23 | 1982,"149077,1" 24 | 1983,107551 25 | 1984,"164166,1" 26 | 1985,"484475,2" 27 | 1986,"264787,4" 28 | 1987,"147340,4" 29 | 1988,"137272,6" 30 | 1989,"407122,1" 31 | 1990,"203641,4" 32 | 1991,260303 33 | 1992,"105277,6" 34 | 1993,"89331,1" 35 | 1994,"437602,5" 36 | 1995,"141082,17" 37 | 1996,"58919,27" 38 | 1997,"98503,17" 39 | 1998,"132892,34" 40 | 1999,"81680,67" 41 | 2000,"187567,06" 42 | 2001,"93297,54" 43 | 2002,"107464,05" 44 | 2003,"148172,47" 45 | 2004,"134192,64" 46 | 2005,"188697,49" 47 | 2006,"155344,83" 48 | 2007,"86122,03" 49 | 2008,"50322,09" 50 | 2009,"120094,21" 51 | 2010,"54769,88" 52 | 2011,"102161,33" 53 | 2012,"218956,59" 54 | 2013,"61690,61" 55 | 2014,"48717,83" 56 | 2015,"109782,85" 57 | 2016,"68121,05" 58 | 2017,"178482,38" 59 | 2018,"23911,89" 60 | 2019,"84060,89" 61 | 2020,"65923,08" 62 | 2023,"66063,51" 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | .RDataTmp 8 | 9 | # Plots 10 | *.png 11 | *.svg 12 | *.tiff 13 | *.gif 14 | 15 | # User-specific files 16 | .Ruserdata 17 | *.pdf 18 | *.zip 19 | *.tif 20 | *.ovr 21 | *.rds 22 | *.cpp 23 | *.qs 24 | *.xlsx 25 | *.xls 26 | *.shp 27 | *.shx 28 | *.dbf 29 | *.prj 30 | *.cpg 31 | 32 | 33 | 34 | # Example code in package build process 35 | *-Ex.R 36 | 37 | # Output files from R CMD build 38 | /*.tar.gz 39 | 40 | # Output files from R CMD check 41 | /*.Rcheck/ 42 | 43 | # RStudio files 44 | .Rproj.user/ 45 | 46 | # produced vignettes 47 | vignettes/*.html 48 | vignettes/*.pdf 49 | 50 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 51 | .httr-oauth 52 | 53 | # knitr and R markdown default cache directories 54 | *_cache/ 55 | /cache/ 56 | 57 | # Temporary files created by R markdown 58 | *.utf8.md 59 | *.knit.md 60 | 61 | # R Environment Variables 62 | .Renviron 63 | 64 | # pkgdown site 65 | docs/ 66 | 67 | # translation temp files 68 | po/*~ 69 | 70 | # RStudio Connect folder 71 | rsconnect/ 72 | R/30DayChartChallenge2025/data/poblacion_municipios_ine.csv 73 | R/30DayChartChallenge2025/data/pand-c-shp/pand_c.shp.xml 74 | R/30DayChartChallenge2025/data/pand-p-shp/pand_p.shp.xml 75 | -------------------------------------------------------------------------------- /R/2024/week_10/gender_pay_gap_2022.csv: -------------------------------------------------------------------------------- 1 | country;employment_F;wanting_work_care_F;F_manager;gender_pay_gap_2012;gender_pay_gap_2022 2 | European Union - 27 countries (from 2020);69,3;18,5;35,0604757036208;16,4;12,7 3 | Belgium;68,1;8,7;36,377789309808;8,3;5 4 | Bulgaria;71,8;10,7;40,8492822966507;15,1;13 5 | Czechia;73,7;27,3;26,8246802106847;22,5;17,9 6 | Denmark;77,4;4,9;29,2326431181486;16,8;13,9 7 | Germany;76,8;25,4;28,9057162377591;22,7;17,7 8 | Estonia;80,4;18,2;40,2298850574713;29,9;21,3 9 | Ireland;72,6;30,4;38,1894736842105;12,2;9,3 10 | Spain;64,1;20,2;34,7131608548931;18,7;8,7 11 | France;71,2;17,6;39,8867474667197;15,6;13,9 12 | Italy;55;14,8;27,8745242763234;6,5;4,3 13 | Cyprus;72,1;29,1;22,8070175438596;15,6;10,2 14 | Latvia;75,5;;45,0110864745011;14,9;17,1 15 | Lithuania;78,6;17,1;38,5832705350415;11,9;12 16 | Luxembourg;71,5;12,3;25,531914893617;7;-0,7 17 | Hungary;75,3;20,7;37,5423318819545;20,1;17,5 18 | Malta;74,1;;33,6391437308869;9,5;10,2 19 | Netherlands;79;9,6;28,4187611320008;18;13 20 | Austria;73,4;21,6;33,4353146853147;22,9;18,4 21 | Poland;70,2;32;42,9086321859795;6,4;7,8 22 | Portugal;74,3;16,1;36,7416496250852;15;12,5 23 | Romania;59,1;11,3;33,0387205387205;6,9;4,5 24 | Slovenia;74,3;19,7;34,7721822541966;4,5;8,2 25 | Slovakia;72,6;25,3;38,0405405405405;20,8;17,7 26 | Finland;77,8;;36,2876254180602;19,2;15,5 27 | Sweden;79,2;3,8;41,6642250219748;15,5;11,1 28 | Iceland;82,1;;39,5522388059702;17,7;9,3 29 | Norway;78;;33,1745344304894;14,7;14,4 30 | Switzerland;77,8;22;30,6666666666667;17,4;17,9 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :chart_with_upwards_trend: dataviz 2 | Repositorio de GitHub con scripts de visualizaciones de datos en R. Incluye gráficos de barras, líneas, dispersión, anillos, mapas, árboles, burbujas, caja y probabilidad. 3 | 4 | :star: Incluye gráficos de barras, líneas, dispersión, anillos, mapas, árboles, burbujas, caja y probabilidad. 5 | 6 | :pencil: Los scripts están documentados y fáciles de usar. 7 | 8 | 9 | ## :point_up: Antes de nada... 10 | Para el fastidio de muchos suelo utilizar fuentes personalizadas para los gráficos. 11 | La fuente que suelo usar es la Lato disponible en las fonts de Google: 12 | * Para descargar: [font Lato](https://fonts.google.com/specimen/Lato) 13 | * Para instalar basata con descargar la familia, desempaquetar el .zip e instalar una apriendo los ficheros 14 | * Las variantes que más uso: `"Lato-Regular"` y `"Lato-Black"` 15 | 16 | 17 | Para instalar las fuentes del pc (windows) en R: 18 | 19 | ```{r} 20 | # Install 21 | install.packages("extrafont") 22 | library(extrafont) 23 | 24 | # Load fonts 25 | font_import() 26 | loadfonts(device = "win") 27 | ``` 28 | 29 | 30 | ## :deciduous_tree: Estructura del proyecto 31 | 32 | ``` 33 | 📦 scouting 34 | ┣ 📂 R # R scripts 35 | ┃ ┗ 📂 2024 # R scripts of data visualizations in 2024 36 | ┃ ┗ 📂 week_01 # R script of visualization of the first week 37 | ┃ ┣ 📜 2024_w01_lollipop_eolica.R # R R script thats makes a 🍭 lollipop plot of eolica data 38 | ┃ ┗ 📄 eolica.csv # Input data csv file 39 | ┣ 📜 .gitignore 40 | ┣ 📜 README.md 41 | ┣ 📜 dataviz.Rproj # R project file 42 | 43 | ``` 44 | 45 | ## :raised_hands: Contribuciones 46 | 47 | :fire: Se aceptan contribuciones al repositorio. Si tiene un script de visualización de datos en R que desea compartir, envíe un pull request. 48 | 49 | ## :postbox: Contacto 50 | Si tiene alguna pregunta o comentario, envíe un correo electrónico al propietario del repositorio. 51 | * :mailbox: michal.kinel@gmail.com 52 | * :octocat: [michal0091](https://github.com/michal0091) 53 | 54 | ## :copyright: Licencia 55 | 56 | :copyright: El repositorio está licenciado bajo la licencia MIT. 57 | 58 | -------------------------------------------------------------------------------- /R/2024/week_12/portfolio.csv: -------------------------------------------------------------------------------- 1 | name,type,prp 2 | Alemania,pais,"4,372148448" 3 | Arabia Saudita,pais,"0,3375508149" 4 | Australia,pais,"0,234917192" 5 | Austria,pais,"0,1016591076" 6 | Bélgica,pais,"0,4120039073" 7 | Brasil,pais,"0,4068816801" 8 | Bulgaria,pais,"0,001184502868" 9 | Canadá,pais,"0,8619165035" 10 | Chile,pais,"0,04379179984" 11 | China,pais,"2,764477935" 12 | Colombia,pais,"0,0218709575" 13 | Corea,pais,"1,141961732" 14 | Croacia,pais,"0,001184502868" 15 | Dinamarca,pais,"1,355408731" 16 | Egipto,pais,"0,004872587419" 17 | Emiratos Árabes Unidos,pais,"0,09314066893" 18 | Eslovaquia,pais,"0,008291520076" 19 | Eslovenia,pais,"0,003553508604" 20 | España,pais,"1,127079558" 21 | Estados Unidos,pais,"57,98013063" 22 | Filipinas,pais,"0,04573387355" 23 | Finlandia,pais,"0,8351356396" 24 | Francia,pais,"4,429582331" 25 | Grecia,pais,"0,05159490097" 26 | Holanda,pais,"1,89650863" 27 | Hong Kong,pais,"0,004249592521" 28 | Hungría,pais,"0,02618203695" 29 | India,pais,"1,213970351" 30 | Indonesia,pais,"0,1774863203" 31 | Irlanda,pais,"0,8627923663" 32 | Israel,pais,"0,2992389537" 33 | Italia,pais,"1,299739458" 34 | Japón,pais,"3,789414435" 35 | Kuwait,pais,"0,06473580428" 36 | Letonia,pais,"0,001184502868" 37 | Lituania,pais,"0,001184502868" 38 | Luxemburgo,pais,"0,003553508604" 39 | Malasia,pais,"0,1400938516" 40 | México,pais,"0,237899443" 41 | Noruega,pais,"0,2670045634" 42 | Nueva Zelanda,pais,"0,02013654876" 43 | Panamá,pais,"0,002369005736" 44 | Perú,pais,"0,02819719968" 45 | Polonia,pais,"0,1297251362" 46 | Portugal,pais,"0,05113435198" 47 | Qatar,pais,"0,06975456974" 48 | Reino Unido,pais,"5,16994458" 49 | República Checa,pais,"0,02243246547" 50 | Rumania,pais,"0,01421403442" 51 | Singapur,pais,"0,02724356596" 52 | Sudáfrica,pais,"0,2018643359" 53 | Suecia,pais,"1,544253649" 54 | Suiza,pais,"3,148179924" 55 | Supranacional,pais,"0,2369005736" 56 | Tailandia,pais,"0,1638952807" 57 | Taiwán,pais,"2,09743001" 58 | Turquía,pais,"0,06125538469" 59 | Unión Europea,pais,"0,08857353032" 60 | Uruguay,pais,"0,001184502868" 61 | Bonos públicos,sector,"1,756699681" 62 | Bonos privados,sector,"1,088573874" 63 | Bonos del Tesoro,sector,"6,512112299" 64 | Comunicación,sector,"5,591839005" 65 | Consumo discrecional,sector,"8,648230778" 66 | Cuidado de la Salud,sector,"9,941197779" 67 | Efectivo y Derivados,sector,"1,240863219" 68 | Energía,sector,"2,160674863" 69 | Financieros,sector,"12,04559344" 70 | Industriales,sector,"11,67572367" 71 | Inmobiliario,sector,"1,470909351" 72 | Materiales,sector,"2,809669807" 73 | Productos básicos de consumo,sector,"3,158536105" 74 | Servicios,sector,"1,431206743" 75 | Tecnología de la Información,sector,"30,46816939" -------------------------------------------------------------------------------- /R/2024/week_49/2024_w47.R: -------------------------------------------------------------------------------- 1 | # Libraries --------------------------------------------------------------- 2 | library(data.table) 3 | library(tidyverse) 4 | library(ggforce) 5 | library(ggtext) 6 | library(ggrepel) 7 | library(emojifont) 8 | library(sysfonts) 9 | library(showtext) 10 | library(ggplot2) 11 | library(tidyverse) 12 | library(mlmhelpr) 13 | library(sysfonts) 14 | library(showtext) 15 | 16 | 17 | # Source ------------------------------------------------------------------ 18 | source("R/30DayChartChallenge2024/theme/styles.R") 19 | source("R/30DayChartChallenge2024/theme/theme.R") 20 | 21 | # Font Awesome 22 | font_add(family = "fa-brands", regular = "fonts/fa-brands-400.ttf") 23 | showtext_auto() 24 | 25 | # Functions --------------------------------------------------------------- 26 | new_caption_text <- function(viz_author = "Michal Kinel", 27 | source_text, 28 | color_text_1 = "#352725", 29 | color_text_2 = "#3f68e3", 30 | github_icon = '', 31 | github_username = "michal0091", 32 | twitter_icon = "", 33 | twitter_username = "nico_kinel", 34 | linkedin_icon = "", 35 | linkedin_username = "michal-kinel", 36 | bluesky_icon = "", 37 | bluesky_username = "mikipe", 38 | bluesky_server = "bsky.sociall") { 39 | 40 | social_caption <- glue::glue( 41 | " 42 | Data Visualization: {viz_author} 43 | Source: {source_text}
44 | {github_icon}; 45 | {github_username} 46 | {twitter_icon}; 47 | {twitter_username} 48 | {linkedin_icon}; 49 | {linkedin_username} 50 | {bluesky_icon}; 51 | {bluesky_username}.{bluesky_server} 52 | " 53 | ) 54 | 55 | social_caption 56 | 57 | } 58 | 59 | 60 | # Data -------------------------------------------------------------------- -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_13/day_13_family.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_13_family 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(patchwork) 13 | 14 | # Source ------------------------------------------------------------------ 15 | source("R/30DayChartChallenge2024/theme/styles.R") 16 | source("R/30DayChartChallenge2024/theme/theme.R") 17 | 18 | 19 | # Config ------------------------------------------------------------------ 20 | cfg <- 21 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 22 | cfg_day_13 <- cfg$day_13 23 | 24 | 25 | # Data -------------------------------------------------------------------- 26 | storks <- read.csv("R/30DayChartChallenge2024/day_13/storks.csv") %>% 27 | as.data.table() 28 | 29 | 30 | # Plot -------------------------------------------------------------------- 31 | 32 | plot <- storks[, ggplot(.SD, aes(x = Storks, y = Birth)) + 33 | geom_smooth(method = "lm", color = c3_color_accent_1, se = FALSE) + 34 | geom_point(color = c3_color_accent_2, size = 2) + 35 | scale_x_log10() + 36 | scale_y_log10() + 37 | # Add correlation label 38 | geom_text( 39 | aes(x = 20000, y = 220, label = paste0("Correlation: ", round(cor(Storks, Birth), 3))), 40 | family = "redhat_light", 41 | color = c3_color_text_1, 42 | size = rel(6), 43 | hjust = 1, 44 | vjust = 1 45 | ) + 46 | labs( 47 | title = "Storks Deliver Babies?", 48 | subtitle = "Correlation is not causation", 49 | x = "Number of storks breeding pairs", 50 | y = "Birth rate (thousands per year)", 51 | caption = caption_text( 52 | source_text = cfg_day_13$source, 53 | day_type = cfg_day_13$category, 54 | day_hashtag = cfg_day_13$theme, 55 | day = cfg_day_13$day, 56 | color_text_1 = c3_color_text_2, 57 | color_text_2 = c3_color_text_1 58 | ) 59 | ) + 60 | theme_my( 61 | font_regular = "redhat_regular", 62 | font_bold = "redhat_bold", 63 | font_light = "redhat_light", 64 | color_text_1 = c3_color_text_2, 65 | color_text_2 = c3_color_text_1, 66 | color_background = c3_color_background, 67 | title_size = 36 68 | ) + 69 | theme( 70 | plot.margin = margin(25, 5, 5, 10, "pt"), 71 | plot.caption = element_textbox_simple( 72 | size = 13, 73 | lineheight = .5, 74 | padding = margin(5, 5, 5, 5, "pt"), 75 | margin = margin(10, 0, 0, 0, "pt"), 76 | ))] 77 | 78 | 79 | # Save -------------------------------------------------------------------- 80 | ggsave( 81 | filename = "day_13_family.png", 82 | path = normalizePath("R/30DayChartChallenge2024/day_13"), 83 | plot = plot, 84 | device = "png", 85 | units = "px", 86 | width = 1080, 87 | height = 1080, 88 | dpi = 320 89 | ) 90 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_07/day_7_hazards.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_7_hazards 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(ggplot2) 6 | library(ggforce) 7 | library(ggtext) 8 | library(emojifont) 9 | library(sysfonts) 10 | library(showtext) 11 | library(patchwork) 12 | 13 | 14 | # Source ------------------------------------------------------------------ 15 | source("R/30DayChartChallenge2024/theme/styles.R") 16 | source("R/30DayChartChallenge2024/theme/theme.R") 17 | 18 | 19 | # Config ------------------------------------------------------------------ 20 | cfg <- 21 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 22 | cfg_day_7 <- cfg$day_7 23 | 24 | 25 | #'Métrica":"Hectáreas quemadas 26 | #'Fuente":"Ministerio de Agricultura y Pesca, Alimentación y Medio Ambiente 27 | #'Clasificación":" "Unidad":"Hectáreas afectadas 28 | #'Escala":"Unidades 29 | 30 | 31 | # Data -------------------------------------------------------------------- 32 | hbs <- read.csv("R/30DayChartChallenge2024/day_07/hectares_burned_spain.csv", 33 | dec = ",") %>% 34 | as.data.table() 35 | 36 | 37 | # Plot -------------------------------------------------------------------- 38 | plot <- hbs[, ggplot(.SD, aes(hectares_burned)) + 39 | geom_histogram(bins = round(sqrt(.N)), fill = c2_color_accent_2, 40 | color = c2_color_accent_2) + 41 | scale_x_continuous(labels = scales::comma) + 42 | scale_y_continuous(breaks = seq(0, 30, 5), limits = c(0, 30)) + 43 | labs( 44 | title = "Wildfires in Spain", 45 | subtitle = "Number of hectares burned between 1961 and 2023", 46 | x = "ha burned", 47 | y = "Frequency", 48 | caption = caption_text( 49 | source_text = cfg_day_7$source, 50 | day_type = cfg_day_7$category, 51 | day_hashtag = cfg_day_7$theme, 52 | day = cfg_day_7$day, 53 | color_text_1 = c2_color_text_1, 54 | color_text_2 = c2_color_text_2 55 | ) 56 | ) + 57 | theme_my(font_regular = "roboto_regular", 58 | font_bold = "roboto_bold", 59 | font_light = "roboto_light", 60 | color_text_1 = c2_color_text_1, 61 | color_text_2 = c2_color_text_2, 62 | color_background = c2_color_background, 63 | title_size = 30) + 64 | theme(plot.margin = margin(25, 5, 5, 5, "pt")) 65 | ] 66 | 67 | 68 | # Save -------------------------------------------------------------------- 69 | ggsave( 70 | filename = "day_7_hazards.png", 71 | path = normalizePath("R/30DayChartChallenge2024/day_07"), 72 | plot = plot, 73 | device = "png", 74 | units = "px", 75 | width = 1080, 76 | height = 1080, 77 | dpi = 320 78 | ) 79 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_29/day_29_black_n_white.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_29_black_n_white 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(primes) 7 | 8 | 9 | # Source ------------------------------------------------------------------ 10 | source("R/30DayChartChallenge2024/theme/styles.R") 11 | source("R/30DayChartChallenge2024/theme/theme.R") 12 | 13 | 14 | # Config ------------------------------------------------------------------ 15 | cfg <- 16 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 17 | cfg_day_29 <- cfg$day_29 18 | 19 | 20 | # Data -------------------------------------------------------------------- 21 | 22 | # Prime numbers 23 | set.seed(16011991) 24 | n <- 365 25 | r <- 2000 26 | 27 | random <- function(n) { 28 | if (is_prime(n)) return(n / 2) 29 | return(2 * n - 1) 30 | } 31 | dt <- data.table(x = rep(1:n, r), 32 | y = as.vector(replicate(r, cumsum( 33 | sapply(sample(1:30, n, TRUE), random) * sample(c(-1, 1), n, TRUE) 34 | ))), 35 | id = rep(1:r, each = n)) 36 | 37 | # Plot -------------------------------------------------------------------- 38 | 39 | plot <- ggplot(dt, aes(x = x, y = y, group = id)) + 40 | geom_line(color = "white", alpha = 0.03) + 41 | scale_x_continuous(expand = c(0, 0)) + 42 | labs( 43 | title = "Random walk simulation", 44 | subtitle = "2.000 random walks using prime numbers as a rule\nif n is prime, n/2, otherwise 2n-1", 45 | caption = caption_text( 46 | source_text = cfg_day_29$source, 47 | day_type = cfg_day_29$category, 48 | day_hashtag = cfg_day_29$theme, 49 | day = cfg_day_29$day, 50 | color_text_1 = "white", 51 | color_text_2 = "white" 52 | ) 53 | ) + 54 | theme_void() + 55 | theme( 56 | plot.margin = margin(35, 0, 0, 0, "pt"), 57 | plot.background = element_rect(fill = "black"), 58 | panel.background = element_rect(fill = "black"), 59 | plot.title = element_text( 60 | size = 56, 61 | family = "roboto_bold", 62 | color = "white", 63 | face = "bold", 64 | hjust = 0, 65 | vjust = 4.5, 66 | lineheight = .34, 67 | margin = margin(5, 5, 5, 35, "pt") 68 | ), 69 | plot.subtitle = element_text( 70 | size = 42, 71 | family = "roboto_bold", 72 | color = "white", 73 | hjust = 0, 74 | vjust = 3, 75 | lineheight = .3, 76 | margin = margin(5, 5, 5, 35, "pt") 77 | ), 78 | plot.caption = element_textbox_simple( 79 | size = 26, 80 | lineheight = .5, 81 | padding = margin(3, 3, 3, 3, "pt"), 82 | margin = margin(15, 10, 15, 35, "pt"), 83 | ), 84 | plot.title.position = "plot", 85 | plot.caption.position = "plot" 86 | ) 87 | 88 | 89 | 90 | # Save -------------------------------------------------------------------- 91 | ggsave( 92 | "R/30DayChartChallenge2024/day_29/day_29_black_n_white.png", 93 | plot, 94 | width = 1920, 95 | height = 1920, 96 | units = "px", 97 | dpi = 320, limitsize = F 98 | ) 99 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_17/day_17_networks.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_17_networks 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(patchwork) 13 | library(lubridate) 14 | library(geomnet) 15 | library(ggnetwork) 16 | library(igraph) 17 | 18 | 19 | # Source ------------------------------------------------------------------ 20 | source("R/30DayChartChallenge2024/theme/styles.R") 21 | source("R/30DayChartChallenge2024/theme/theme.R") 22 | 23 | 24 | # Config ------------------------------------------------------------------ 25 | cfg <- 26 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 27 | cfg_day_17 <- cfg$day_17 28 | 29 | 30 | # Data -------------------------------------------------------------------- 31 | blood_igraph <- graph_from_data_frame(d = blood$edges, directed = TRUE) 32 | data <- 33 | ggnetwork(blood.igraph, 34 | layout = layout_in_circle(blood_igraph), 35 | arrow.gap = 0.05) 36 | 37 | 38 | # Plot -------------------------------------------------------------------- 39 | 40 | plot <- ggplot(data = data, aes( 41 | x = x, 42 | y = y, 43 | xend = xend, 44 | yend = yend 45 | )) + 46 | geom_edges( 47 | linewidth = 0.5, 48 | curvature = 0.05, 49 | colour = c3_color_text_2, 50 | arrow = arrow(length = unit(2, "pt"), type = "closed", angle = 25) 51 | ) + 52 | geom_nodes(color = c3_color_accent_1, 53 | size = 4, 54 | show.legend = FALSE) + 55 | geom_nodetext( 56 | aes(label = name), 57 | color = c3_color_text_1, 58 | family = "redhat_bold", 59 | fontface = "bold", 60 | show.legend = FALSE, 61 | size = rel(7) 62 | ) + 63 | theme_net() + 64 | labs( 65 | title = "Blood donation diagram", 66 | x = NULL, 67 | y = NULL, 68 | color = NULL, 69 | fill = NULL, 70 | caption = caption_text( 71 | source_text = cfg_day_17$source, 72 | day_type = cfg_day_17$category, 73 | day_hashtag = cfg_day_17$theme, 74 | day = cfg_day_17$day, 75 | color_text_1 = c3_color_text_2, 76 | color_text_2 = c3_color_text_1 77 | ) 78 | ) + 79 | theme_my( 80 | font_regular = "redhat_regular", 81 | font_bold = "redhat_bold", 82 | font_light = "redhat_light", 83 | color_text_1 = c3_color_text_1, 84 | color_text_2 = c3_color_text_2, 85 | color_background = c3_color_background, 86 | title_size = 46 87 | ) + 88 | theme(panel.grid.major = element_blank(), 89 | axis.text = element_blank(), 90 | plot.caption = element_textbox_simple( 91 | size = 13, 92 | lineheight = .5, 93 | padding = margin(1, 1, 1, 1, "pt"), 94 | margin = margin(25, 0, 0, 0, "pt"), 95 | )) 96 | 97 | 98 | 99 | # Save -------------------------------------------------------------------- 100 | ggsave( 101 | filename = "R/30DayChartChallenge2024/day_17/day_17_networks.png", 102 | plot = plot, 103 | width = 1080, 104 | height = 1296, 105 | units = "px", 106 | dpi = 320 107 | ) 108 | 109 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_01/day_01_part_to_whole.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_01_part_to_whole 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(ggplot2) 6 | library(ggtext) 7 | library(emojifont) 8 | library(sysfonts) 9 | library(showtext) 10 | 11 | 12 | # Source ------------------------------------------------------------------ 13 | source("R/30DayChartChallenge2024/theme/styles.R") 14 | source("R/30DayChartChallenge2024/theme/theme.R") 15 | 16 | # Config ------------------------------------------------------------------ 17 | cfg <- yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 18 | cfg_day_1 <- cfg$day_1 19 | 20 | # Data -------------------------------------------------------------------- 21 | data <- data.table( 22 | dependency = c("Number of crops", "Crop production"), 23 | value = c(.75, .35), 24 | comment = c( 25 | "Three-quarters of crops get a little help from their buzzing buddies", 26 | "75% of crops need a pollinator's help, but only ⅓ of our food actually depends on them!\nWhy? Cereals and other heavy hitters don't need the buzz." 27 | ) 28 | ) 29 | 30 | data[, dependency := factor(dependency, levels = c("Number of crops", "Crop production"))] 31 | 32 | 33 | # Plot -------------------------------------------------------------------- 34 | plot <- data %>% 35 | ggplot(aes(value, dependency)) + 36 | geom_col(fill = color_set_1, just = 1) + 37 | facet_wrap( ~ dependency, ncol = 1, scales = "free_y") + 38 | geom_text( 39 | aes(label = paste0(" ", sprintf("%2.0f", 100 * value), "% "), 40 | hjust = 1.1, vjust = 3), 41 | color = color_background, 42 | size = rel(10), 43 | fontface = "bold", 44 | family = "inter_regular" 45 | ) + 46 | geom_text( 47 | aes(x = I(0), y = I(1.4), label = comment), 48 | color = color_text_1, 49 | size = rel(6), 50 | hjust = 0, 51 | family = "inter_light", 52 | lineheight = 0.4 53 | ) + 54 | 55 | scale_x_continuous( 56 | name = NULL, 57 | expand = c(0, 0), 58 | limits = c(0, 1), 59 | guide = "none" 60 | ) + 61 | scale_y_discrete(guide = "none") + 62 | scale_color_manual(values = c(color_text_1, color_background), 63 | guide = "none") + 64 | labs(title = "Without a Buzz, No Brussels Sprouts: How Pollinators Keep Our Plates Full", 65 | subtitle = "Percentage of Food We Owe to Busy Bees (and Their Buddies)", 66 | x = NULL, 67 | y = NULL, 68 | caption = caption_text( 69 | source_text = cfg_day_1$source, 70 | day_type = cfg_day_1$category, 71 | day_hashtag = cfg_day_1$theme, 72 | day = cfg_day_1$day 73 | )) + 74 | 75 | theme_my(title_size = 36) + 76 | theme( 77 | strip.background = element_rect(fill = color_background, color = color_background), 78 | strip.text = element_text( 79 | color = color_text_2, 80 | family = "inter_regular", 81 | hjust = 0, 82 | margin = margin(1, 1, 1, 1), 83 | face = "bold" 84 | ), 85 | panel.grid.major = element_blank(), 86 | panel.spacing = unit(1, "lines") 87 | ) 88 | 89 | 90 | # Save -------------------------------------------------------------------- 91 | ggsave( 92 | filename = "day_01_part_to_whole.png", 93 | path = normalizePath("R/30DayChartChallenge2024/day_01"), 94 | plot = plot, 95 | device = "png", 96 | units = "px", 97 | width = 1920, 98 | height = 1080, 99 | dpi = 320 100 | ) 101 | 102 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_10/day_10_physical.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_10_physical 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(ggplot2) 6 | library(ggforce) 7 | library(ggtext) 8 | library(emojifont) 9 | library(sysfonts) 10 | library(showtext) 11 | library(patchwork) 12 | 13 | 14 | # Source ------------------------------------------------------------------ 15 | source("R/30DayChartChallenge2024/theme/styles.R") 16 | source("R/30DayChartChallenge2024/theme/theme.R") 17 | 18 | 19 | # Config ------------------------------------------------------------------ 20 | cfg <- 21 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 22 | cfg_day_10 <- cfg$day_10 23 | 24 | 25 | # Data -------------------------------------------------------------------- 26 | dt <- fread("R/30DayChartChallenge2024/day_10/physical.csv") 27 | dt[, date := as.Date(date)] 28 | 29 | # Plot -------------------------------------------------------------------- 30 | plot <- dt[, ggplot(.SD, aes(date, position)) + 31 | geom_hline( 32 | yintercept = 1, 33 | color = c2_color_text_2, 34 | linetype = "dashed", 35 | linewidth = 0.10 36 | ) + 37 | geom_line(color = c2_color_set_1, linewidth = 0.5) + 38 | geom_ribbon(aes(date, ymin = position, ymax = 100), 39 | fill = c2_color_set_1, 40 | alpha = .25) + 41 | 42 | scale_y_reverse(limits = c(100,-10), 43 | breaks = c(1, 5, seq(10, 100, 10))) + 44 | scale_x_date(breaks = .SD[seq(1, 26, 3), date], date_labels = "%d %b %y") + 45 | labs( 46 | title = "Physical by Olivia Newton-John", 47 | subtitle = "weeks on top of the Billboard Hot 100 chart in 1981/82", 48 | x = NULL, 49 | y = "position", 50 | caption = caption_text( 51 | source_text = cfg_day_10$source, 52 | day_type = cfg_day_10$category, 53 | day_hashtag = cfg_day_10$theme, 54 | day = cfg_day_10$day, 55 | color_text_1 = c2_color_text_1, 56 | color_text_2 = c2_color_text_2 57 | ) 58 | ) + 59 | theme_my( 60 | font_regular = "roboto_regular", 61 | font_bold = "roboto_bold", 62 | font_light = "roboto_light", 63 | color_text_1 = c2_color_text_1, 64 | color_text_2 = c2_color_text_2, 65 | color_background = c2_color_background, 66 | title_size = 36 67 | ) + 68 | theme( 69 | plot.margin = margin(25, 10, 0, 15, "pt"), 70 | panel.grid.major = element_blank(), 71 | axis.text.y = element_text( 72 | size = 14, 73 | family = "roboto_bold", 74 | color = c2_color_text_2 75 | ), 76 | axis.text.x = element_text( 77 | size = 12, 78 | hjust = 0, 79 | family = "roboto_bold" 80 | ) 81 | )] 82 | 83 | # Save -------------------------------------------------------------------- 84 | ggsave( 85 | filename = "day_10_physical.png", 86 | path = normalizePath("R/30DayChartChallenge2024/day_10"), 87 | plot = plot, 88 | device = "png", 89 | units = "px", 90 | width = 1440, 91 | height = 1080, 92 | dpi = 320 93 | ) 94 | 95 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_26/day_26_AI.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_26_AI 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(ggplot2) 13 | library(tidyverse) 14 | library(mlmhelpr) 15 | 16 | 17 | # Source ------------------------------------------------------------------ 18 | source("R/30DayChartChallenge2024/theme/styles.R") 19 | source("R/30DayChartChallenge2024/theme/theme.R") 20 | 21 | 22 | # Config ------------------------------------------------------------------ 23 | cfg <- 24 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 25 | cfg_day_26 <- cfg$day_26 26 | 27 | 28 | # Data -------------------------------------------------------------------- 29 | dt <- fread("R/30DayChartChallenge2024/day_26/ai.csv") 30 | 31 | dt <- melt(dt, id.vars = c("Type", "Group")) 32 | 33 | 34 | 35 | # Plot -------------------------------------------------------------------- 36 | 37 | 38 | plot <- ggplot(data = dt, aes(x = Group, y = value, fill = variable)) + 39 | 40 | scale_fill_manual(values = c("#00f1bc", "#81d8d0", "#ea899a")) + 41 | labs( 42 | title = "Awareness of AI use in UK", 43 | subtitle = "Proportion of adults reporting how often they think\nthey can recognise when they are using AI\nGreat Britain, 26 July to 1 October 2023", 44 | x = NULL, 45 | y = "Proportion (%)", 46 | fill = "Frequency", 47 | caption = caption_text( 48 | source = cfg_day_26$source, 49 | day_type = cfg_day_26$category, 50 | day_hashtag = cfg_day_26$theme, 51 | day = cfg_day_26$day, 52 | color_text_1 = c2_color_text_1, 53 | color_text_2 = c2_color_text_2 54 | ) 55 | ) + 56 | 57 | # Stacked bar chart 58 | geom_bar(stat = "identity", position = position_fill()) + 59 | 60 | # Display data labels within bars (optional) 61 | geom_text( 62 | aes(label = paste0(value, "%")), 63 | stat = "identity", 64 | position = position_fill(vjust = .5), 65 | vjust = 0.5, 66 | size = rel(7) 67 | ) + 68 | 69 | # Avoid overlapping x-axis labels if needed (consider rotating or wrapping) 70 | coord_flip() + # Flips x and y axes for better readability 71 | facet_grid(Type ~ ., scales = "free", space = "free") + 72 | scale_y_continuous(labels = scales::percent_format()) + 73 | guides(fill = guide_legend(nrow = 3, theme = theme(legend.byrow = TRUE))) + 74 | theme_my( 75 | font_regular = "roboto_regular", 76 | font_bold = "roboto_bold", 77 | font_light = "roboto_light", 78 | color_text_1 = c2_color_text_1, 79 | color_text_2 = c2_color_text_2, 80 | color_background = c2_color_background, 81 | title_size = 48 82 | ) + 83 | theme( 84 | legend.position = "bottom", 85 | axis.text = element_text(family = "roboto_regular", 86 | size = 26, hjust = 1), 87 | plot.margin = margin(25, 45, 25, 25, "pt"), 88 | plot.title.position = "plot", 89 | plot.caption.position = "plot", 90 | plot.caption = element_textbox_simple( 91 | size = 26, 92 | lineheight = .5, 93 | padding = margin(0, 0, 0, 0, "pt"), 94 | margin = margin(25, 0, 0, 0, "pt"), 95 | ) 96 | 97 | 98 | ) 99 | 100 | 101 | # Save -------------------------------------------------------------------- 102 | ggsave( 103 | "R/30DayChartChallenge2024/day_26/day_26_AI.png", 104 | plot, 105 | width = 1920, 106 | height = 2560, 107 | units = "px", 108 | dpi = 320 109 | ) 110 | 111 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_24/day_24_ILO_Africa.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_24_ILO_Africa 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(patchwork) 13 | library(lubridate) 14 | library(zoo) 15 | library(terra) 16 | library(tidyterra) 17 | library(giscoR) 18 | library(sf) 19 | # devtools::install_github("mtennekes/tmaptools") 20 | library(tmaptools) 21 | 22 | 23 | # Source ------------------------------------------------------------------ 24 | source("R/30DayChartChallenge2024/theme/styles.R") 25 | source("R/30DayChartChallenge2024/theme/theme.R") 26 | 27 | 28 | # Config ------------------------------------------------------------------ 29 | cfg <- 30 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 31 | cfg_day_24 <- cfg$day_24 32 | 33 | 34 | # Data -------------------------------------------------------------------- 35 | dt <- fread("R/30DayChartChallenge2024/day_24/ilo_poverty.csv") 36 | dt <- dt[!(ref_area.label %in% c("World", "Africa"))] 37 | 38 | # Plot -------------------------------------------------------------------- 39 | 40 | plot <- dt[, ggplot(.SD, aes(time, obs_value / 100, color = ref_area.label )) + 41 | geom_line(linewidth = 1) + 42 | theme_my( 43 | font_regular = "josefin_regular", 44 | font_bold = "josefin_bold", 45 | font_light = "josefin_light", 46 | color_text_1 = c4_color_text_1, 47 | color_text_2 = c4_color_text_2, 48 | color_background = c4_color_background, 49 | title_size = 50 50 | ) + 51 | scale_color_manual(values = c4_col_set) + 52 | scale_y_continuous(labels = scales::percent_format(accuracy = 1)) + 53 | labs( 54 | title = "Working poverty rate in African Regions", 55 | subtitle = "% of employed adults and youth (15+) living below US$2.15 PPP", 56 | caption = caption_text( 57 | source_text = cfg_day_24$source, 58 | day_type = cfg_day_24$category, 59 | day_hashtag = cfg_day_24$theme, 60 | day = cfg_day_24$day, 61 | color_text_1 = c4_color_text_1, 62 | color_text_2 = c4_color_text_2 63 | ), 64 | x = NULL, 65 | y = "Working poverty rate (%)", 66 | color = NULL 67 | ) + 68 | theme( 69 | legend.position = "bottom", 70 | plot.margin = margin(25, 0, 15, 0, "pt"), 71 | plot.title = element_text( 72 | margin = margin(5, 5, 5, 0, "pt") 73 | ), 74 | plot.subtitle = element_text( 75 | margin = margin(5, 5, 5, 5, "pt") 76 | ), 77 | axis.text = element_text( 78 | size = rel(2), 79 | family = "josefin_bold", 80 | color = c4_color_text_2, 81 | margin = margin(2, 2, 2, 0, "pt") 82 | ), 83 | axis.title.y = element_text( 84 | size = 32, 85 | family = "josefin_bold", 86 | color = c4_color_text_2, 87 | margin = margin(5, 5, 5, 5, "pt"), 88 | angle = 90 89 | ), 90 | panel.grid.major = element_line( 91 | color = c4_color_text_2, 92 | linetype = "dotted", 93 | linewidth = .3, 94 | ) 95 | )] 96 | 97 | 98 | # Save -------------------------------------------------------------------- 99 | ggsave( 100 | filename = "R/30DayChartChallenge2024/day_24/day_24_ILO_Africa.png", 101 | plot = plot, 102 | width = 2688, 103 | height = 1920, 104 | units = "px", 105 | dpi = 320 106 | ) 107 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_09/day_9_major_minor.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_9_major_minor 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(ggplot2) 6 | library(ggforce) 7 | library(ggtext) 8 | library(emojifont) 9 | library(sysfonts) 10 | library(showtext) 11 | library(patchwork) 12 | 13 | 14 | # Source ------------------------------------------------------------------ 15 | source("R/30DayChartChallenge2024/theme/styles.R") 16 | source("R/30DayChartChallenge2024/theme/theme.R") 17 | 18 | 19 | # Config ------------------------------------------------------------------ 20 | cfg <- 21 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 22 | cfg_day_9 <- cfg$day_9 23 | 24 | 25 | # Data -------------------------------------------------------------------- 26 | dt <- fread("R/30DayChartChallenge2024/day_09/symphonies_by_key.csv") 27 | dt <- dt[, .N, .(note, key)] %>% dcast(note ~ key, value.var = "N") 28 | 29 | cols <- c("major", "minor") 30 | dt <- dt[, (cols) := lapply(.SD, nafill, fill = 0), .SDcols = cols] 31 | dt <- dt[order(major, minor, decreasing = TRUE)] 32 | dt <- melt(dt, id.vars = "note", variable.name = "key", value.name = "count") 33 | dt[, perc := round(count / sum(count) * 100, 1), by = note] 34 | dt <- dt[order(key, perc)] 35 | dt[, note := factor(note, levels = .SD[key == "major", note])] 36 | dt[, my_hjust := fifelse(key == "major", 1.1, -0.1)] 37 | 38 | 39 | # Plot -------------------------------------------------------------------- 40 | 41 | plot <- dt[, ggplot(.SD, aes( 42 | x = note, 43 | y = fifelse(key == "major", perc, -perc), 44 | fill = key 45 | )) + 46 | geom_bar(stat = "identity") + 47 | geom_text( 48 | aes( 49 | label = paste0(" ", sprintf("%2.0f", perc), "% "), 50 | hjust = my_hjust 51 | ), 52 | color = c2_color_text_1, 53 | size = rel(5), 54 | family = "roboto_bold" 55 | ) + 56 | scale_fill_manual(breaks = c("minor", "major"), 57 | values = c("major" = "#13ae8c", 58 | "minor" = c2_color_accent_2), 59 | labels = c("Minor", "Major")) + 60 | labs( 61 | title = "Symphonies by Key", 62 | subtitle = "Major and Minor", 63 | x = NULL, 64 | y = NULL, 65 | fill = NULL, 66 | caption = caption_text( 67 | source_text = cfg_day_9$source, 68 | day_type = cfg_day_9$category, 69 | day_hashtag = cfg_day_9$theme, 70 | day = cfg_day_9$day, 71 | color_text_1 = c2_color_text_1, 72 | color_text_2 = c2_color_text_2 73 | ) 74 | ) + 75 | coord_flip() + 76 | scale_y_continuous(guide = "none") + 77 | theme_my( 78 | font_regular = "roboto_regular", 79 | font_bold = "roboto_bold", 80 | font_light = "roboto_light", 81 | color_text_1 = c2_color_text_1, 82 | color_text_2 = c2_color_text_2, 83 | color_background = c2_color_background, 84 | title_size = 28 85 | ) + 86 | theme( 87 | plot.margin = margin(25, 10, 0, 15, "pt"), 88 | legend.position = "bottom", 89 | legend.margin = margin(0, 0, 0, 0, "pt"), 90 | legend.spacing = unit(5, "pt"), 91 | legend.key.spacing = unit(5, "pt"), 92 | legend.key.height = unit(6, 'pt'), 93 | legend.key.width = unit(9.708, 'pt'), 94 | axis.text.y = element_text( 95 | size = 12, 96 | family = "roboto_bold", 97 | color = c2_color_text_2 98 | ) 99 | )] 100 | 101 | # Save -------------------------------------------------------------------- 102 | ggsave( 103 | filename = "day_9_major_minor.png", 104 | path = normalizePath("R/30DayChartChallenge2024/day_09"), 105 | plot = plot, 106 | device = "png", 107 | units = "px", 108 | width = 1080, 109 | height = 1080, 110 | dpi = 320 111 | ) 112 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_19/multiTimeline.csv: -------------------------------------------------------------------------------- 1 | Categoría: Todas las categorías 2 | 3 | Mes,dinosaurs: (Todo el mundo) 4 | 2005-01,56 5 | 2005-02,65 6 | 2005-03,64 7 | 2005-04,67 8 | 2005-05,61 9 | 2005-06,47 10 | 2005-07,42 11 | 2005-08,42 12 | 2005-09,48 13 | 2005-10,51 14 | 2005-11,57 15 | 2005-12,51 16 | 2006-01,60 17 | 2006-02,57 18 | 2006-03,56 19 | 2006-04,55 20 | 2006-05,55 21 | 2006-06,44 22 | 2006-07,41 23 | 2006-08,46 24 | 2006-09,36 25 | 2006-10,44 26 | 2006-11,48 27 | 2006-12,46 28 | 2007-01,49 29 | 2007-02,50 30 | 2007-03,47 31 | 2007-04,46 32 | 2007-05,50 33 | 2007-06,47 34 | 2007-07,49 35 | 2007-08,47 36 | 2007-09,48 37 | 2007-10,48 38 | 2007-11,51 39 | 2007-12,49 40 | 2008-01,54 41 | 2008-02,52 42 | 2008-03,57 43 | 2008-04,55 44 | 2008-05,52 45 | 2008-06,46 46 | 2008-07,46 47 | 2008-08,46 48 | 2008-09,62 49 | 2008-10,51 50 | 2008-11,54 51 | 2008-12,48 52 | 2009-01,48 53 | 2009-02,51 54 | 2009-03,60 55 | 2009-04,64 56 | 2009-05,66 57 | 2009-06,77 58 | 2009-07,87 59 | 2009-08,74 60 | 2009-09,62 61 | 2009-10,67 62 | 2009-11,63 63 | 2009-12,55 64 | 2010-01,59 65 | 2010-02,66 66 | 2010-03,68 67 | 2010-04,60 68 | 2010-05,59 69 | 2010-06,49 70 | 2010-07,54 71 | 2010-08,48 72 | 2010-09,50 73 | 2010-10,49 74 | 2010-11,54 75 | 2010-12,50 76 | 2011-01,49 77 | 2011-02,55 78 | 2011-03,55 79 | 2011-04,58 80 | 2011-05,57 81 | 2011-06,45 82 | 2011-07,45 83 | 2011-08,40 84 | 2011-09,53 85 | 2011-10,54 86 | 2011-11,54 87 | 2011-12,51 88 | 2012-01,59 89 | 2012-02,64 90 | 2012-03,57 91 | 2012-04,55 92 | 2012-05,58 93 | 2012-06,55 94 | 2012-07,55 95 | 2012-08,52 96 | 2012-09,70 97 | 2012-10,57 98 | 2012-11,57 99 | 2012-12,60 100 | 2013-01,57 101 | 2013-02,62 102 | 2013-03,65 103 | 2013-04,68 104 | 2013-05,62 105 | 2013-06,55 106 | 2013-07,60 107 | 2013-08,55 108 | 2013-09,52 109 | 2013-10,54 110 | 2013-11,62 111 | 2013-12,84 112 | 2014-01,81 113 | 2014-02,67 114 | 2014-03,71 115 | 2014-04,66 116 | 2014-05,64 117 | 2014-06,54 118 | 2014-07,59 119 | 2014-08,54 120 | 2014-09,55 121 | 2014-10,51 122 | 2014-11,57 123 | 2014-12,52 124 | 2015-01,56 125 | 2015-02,56 126 | 2015-03,58 127 | 2015-04,58 128 | 2015-05,63 129 | 2015-06,100 130 | 2015-07,71 131 | 2015-08,60 132 | 2015-09,58 133 | 2015-10,58 134 | 2015-11,62 135 | 2015-12,63 136 | 2016-01,63 137 | 2016-02,61 138 | 2016-03,58 139 | 2016-04,60 140 | 2016-05,61 141 | 2016-06,51 142 | 2016-07,54 143 | 2016-08,48 144 | 2016-09,49 145 | 2016-10,49 146 | 2016-11,48 147 | 2016-12,52 148 | 2017-01,56 149 | 2017-02,57 150 | 2017-03,59 151 | 2017-04,56 152 | 2017-05,53 153 | 2017-06,49 154 | 2017-07,49 155 | 2017-08,47 156 | 2017-09,49 157 | 2017-10,47 158 | 2017-11,48 159 | 2017-12,52 160 | 2018-01,51 161 | 2018-02,54 162 | 2018-03,54 163 | 2018-04,53 164 | 2018-05,55 165 | 2018-06,71 166 | 2018-07,79 167 | 2018-08,67 168 | 2018-09,56 169 | 2018-10,54 170 | 2018-11,55 171 | 2018-12,50 172 | 2019-01,49 173 | 2019-02,50 174 | 2019-03,55 175 | 2019-04,56 176 | 2019-05,48 177 | 2019-06,45 178 | 2019-07,44 179 | 2019-08,43 180 | 2019-09,43 181 | 2019-10,42 182 | 2019-11,41 183 | 2019-12,43 184 | 2020-01,44 185 | 2020-02,45 186 | 2020-03,43 187 | 2020-04,48 188 | 2020-05,47 189 | 2020-06,48 190 | 2020-07,47 191 | 2020-08,48 192 | 2020-09,48 193 | 2020-10,46 194 | 2020-11,43 195 | 2020-12,46 196 | 2021-01,50 197 | 2021-02,52 198 | 2021-03,45 199 | 2021-04,47 200 | 2021-05,46 201 | 2021-06,47 202 | 2021-07,43 203 | 2021-08,43 204 | 2021-09,42 205 | 2021-10,39 206 | 2021-11,40 207 | 2021-12,47 208 | 2022-01,46 209 | 2022-02,46 210 | 2022-03,45 211 | 2022-04,51 212 | 2022-05,52 213 | 2022-06,57 214 | 2022-07,51 215 | 2022-08,46 216 | 2022-09,45 217 | 2022-10,41 218 | 2022-11,39 219 | 2022-12,40 220 | 2023-01,44 221 | 2023-02,49 222 | 2023-03,48 223 | 2023-04,45 224 | 2023-05,41 225 | 2023-06,41 226 | 2023-07,44 227 | 2023-08,43 228 | 2023-09,42 229 | 2023-10,43 230 | 2023-11,44 231 | 2023-12,41 232 | 2024-01,43 233 | 2024-02,45 234 | 2024-03,42 235 | 2024-04,41 236 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/theme/styles.R: -------------------------------------------------------------------------------- 1 | # libs ----------------------------------------------------------------------- 2 | library(sysfonts) 3 | library(showtext) 4 | library(ggplot2) 5 | 6 | 7 | # Colors ------------------------------------------------------------------ 8 | color_background <- "#fbfdfe" 9 | color_text_1 <- "#352725" 10 | color_text_2 <- "#3f68e3" 11 | color_set_1 <- "#2a668a" 12 | color_set_2 <- "#f9ad0d" 13 | color_set_3 <- "#67deb0" 14 | 15 | 16 | c2_color_background <- "#0e0204" 17 | c2_color_text_1 <- "#f1f2f4" 18 | c2_color_text_2 <- "#d2f796" 19 | c2_color_accent_1 <- "#00f1bc" 20 | c2_color_accent_2 <- "#fe686c" 21 | c2_color_set_1 <- "#992696" 22 | c2_color_set_2 <- "#ba3339" 23 | c2_color_set_3 <- "#636567" 24 | 25 | 26 | 27 | c3_color_background <- "#1A7070" 28 | c3_color_text_1 <- "#FFE44D" 29 | c3_color_text_2 <- "#DEEDF9" 30 | c3_color_accent_1 <- "#d6762c" 31 | c3_color_accent_2 <- "#451a70" 32 | c3_color_set_1 <- "#869b97" 33 | c3_color_set_2 <- "#ff9a9b" 34 | c3_color_set_3 <- "#44bcc6" 35 | 36 | 37 | 38 | c4_color_background <- "#cddfe0" 39 | c4_color_text_1 <- "#0e130b" 40 | c4_color_text_2 <- "#103c43" 41 | 42 | 43 | c4_color_set_1 <- "#db4726" 44 | c4_color_set_2 <- "#4170ab" 45 | c4_color_set_3 <- "#f4c14c" 46 | c4_color_set_4 <- "#e7c2ba" 47 | 48 | c4_col_set <- c( 49 | "#387c2b", "#fa6400", 50 | "#ffa100", "#949494", 51 | "#0099c4", "#6e3ab7" 52 | ) 53 | 54 | 55 | c4_color_accent_1 <- "#18984b" 56 | c4_color_accent_2 <- "#e6c51b" 57 | c4_color_accent_3 <- "#ed0c29" 58 | 59 | 60 | 61 | 62 | # ** pallettes ------------------------------------------------------------ 63 | gradient <- 64 | c(color_set_1, 65 | "#0089a4", 66 | "#00aba9", 67 | "#40cb9b", 68 | "#9ce582", 69 | "#f9f871") 70 | 71 | main <- 72 | c(color_set_1, 73 | "#6399c0", 74 | color_set_2, 75 | "#b6ab00", 76 | color_set_3, 77 | "#384b42") 78 | 79 | 80 | 81 | # ** aux colors ----------------------------------------------------------- 82 | white <- "#F0F0F0" 83 | light_gray <- "#fcfcfd" 84 | medium_gray <- "#d2d2d2" 85 | dark_gray <- "#3c3c3c" 86 | 87 | 88 | 89 | # Fonts ------------------------------------------------------------------- 90 | font_add_google(name = "Inter", family = "inter_regular", regular.wt = 400, bold.wt = 700) 91 | font_add_google(name = "Inter", family = "inter_bold", regular.wt = 700, bold.wt = 900) 92 | font_add_google(name = "Inter", family = "inter_light", regular.wt = 300, bold.wt = 400) 93 | font_add_google(name = "Inter", family = "inter_thin", regular.wt = 100, bold.wt = 200) 94 | 95 | # Roboto 96 | font_add_google(name = "Roboto", family = "roboto_regular", regular.wt = 400, bold.wt = 700) 97 | font_add_google(name = "Roboto", family = "roboto_bold", regular.wt = 700, bold.wt = 900) 98 | font_add_google(name = "Roboto", family = "roboto_light", regular.wt = 300, bold.wt = 400) 99 | font_add_google(name = "Roboto", family = "roboto_thin", regular.wt = 100, bold.wt = 200) 100 | 101 | # Red Hat Mono 102 | font_add_google(name = "Red Hat Mono", family = "redhat_regular", regular.wt = 500, bold.wt = 600) 103 | font_add_google(name = "Red Hat Mono", family = "redhat_bold", regular.wt = 700, bold.wt = 900) 104 | font_add_google(name = "Red Hat Mono", family = "redhat_light", regular.wt = 400, bold.wt = 500) 105 | 106 | # Josefin Sans 107 | font_add_google(name = "Josefin Sans", family = "josefin_regular", regular.wt = 400, bold.wt = 700) 108 | font_add_google(name = "Josefin Sans", family = "josefin_bold", regular.wt = 700, bold.wt = 900) 109 | font_add_google(name = "Josefin Sans", family = "josefin_light", regular.wt = 300, bold.wt = 400) 110 | font_add_google(name = "Josefin Sans", family = "josefin_thin", regular.wt = 100, bold.wt = 200) 111 | 112 | 113 | 114 | 115 | # Font Awesome 116 | font_add(family = "fa-brands", regular = "R/30DayChartChallenge2024/theme/fa-brands-400.ttf") 117 | font_add(family = "fa-solid", regular = "R/30DayChartChallenge2024/theme/fa-solid-900.ttf") 118 | showtext_auto() 119 | 120 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_14/day_14_heatmap.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_14_heatmap 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(patchwork) 13 | library(lubridate) 14 | 15 | 16 | # Source ------------------------------------------------------------------ 17 | source("R/30DayChartChallenge2024/theme/styles.R") 18 | source("R/30DayChartChallenge2024/theme/theme.R") 19 | 20 | 21 | # Config ------------------------------------------------------------------ 22 | cfg <- 23 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 24 | cfg_day_14 <- cfg$day_14 25 | 26 | 27 | # Data -------------------------------------------------------------------- 28 | dt <- fread("R/30DayChartChallenge2024/day_14/no2_calendar_data.csv", encoding = "Latin-1") 29 | 30 | # Update to english 31 | Sys.setlocale("LC_TIME", "English") 32 | 33 | dt[, wday := factor(wday(fecha, label = TRUE), 34 | levels = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"))] 35 | dt[, month := factor( 36 | month(fecha, label = TRUE), 37 | levels = c( 38 | "Jan", 39 | "Feb", 40 | "Mar", 41 | "Apr", 42 | "May", 43 | "Jun", 44 | "Jul", 45 | "Aug", 46 | "Sep", 47 | "Oct", 48 | "Nov", 49 | "Dec" 50 | ) 51 | )] 52 | 53 | 54 | # Plot -------------------------------------------------------------------- 55 | 56 | plot <- dt[, 57 | ggplot(.SD, aes( 58 | x = wmonth, 59 | y = reorder(wday, -as.numeric(wday)), 60 | fill = valor_promedio 61 | )) + 62 | geom_tile(colour = "white") + 63 | facet_grid(year ~ month) + 64 | scale_x_continuous(breaks = 1:5, limits = c(0, 6)) + 65 | scale_fill_gradient(low = "#fedbd2", high = "#C20000", ) + 66 | labs( 67 | x = "Week of the month", 68 | y = NULL, 69 | title = "Nitrogen dioxide concentration in the city of Madrid", 70 | subtitle = "Average concentration of NO2 in the air by day of the week", 71 | fill = paste(unique(nom_abv), unique(ud_med)), 72 | caption = caption_text( 73 | source_text = cfg_day_14$source, 74 | day_type = cfg_day_14$category, 75 | day_hashtag = cfg_day_14$theme, 76 | day = cfg_day_14$day, 77 | color_text_1 = c2_color_text_1, 78 | color_text_2 = c2_color_text_2 79 | ) 80 | ) + 81 | theme_my( 82 | font_regular = "redhat_regular", 83 | font_bold = "redhat_bold", 84 | font_light = "redhat_light", 85 | color_text_1 = c3_color_text_1, 86 | color_text_2 = c3_color_text_2, 87 | color_background = c3_color_background, 88 | title_size = 56 89 | ) + 90 | theme( 91 | plot.margin = margin(15, 15, 5, 15, "pt"), 92 | plot.caption = element_textbox_simple( 93 | size = 26, 94 | lineheight = .5, 95 | padding = margin(5, 5, 5, 5, "pt"), 96 | margin = margin(10, 0, 0, 0, "pt"), 97 | ), 98 | legend.position = "bottom", 99 | legend.spacing = unit(5, "pt"), 100 | legend.key.spacing = unit(5, "pt"), 101 | legend.key.height= unit(10, 'pt'), 102 | legend.key.width = unit(16.18, 'pt'), 103 | panel.grid.major = element_line( 104 | colour = c3_color_text_2, 105 | linetype = "solid", 106 | linewidth = .3 107 | ), 108 | axis.text = element_text( 109 | size = rel(1.6), 110 | family = "redhat_regular", 111 | color = c3_color_text_2, 112 | margin = margin(2, 2, 2, 0, "pt") 113 | ) 114 | ) 115 | 116 | ] 117 | 118 | 119 | # Save -------------------------------------------------------------------- 120 | ggsave( 121 | filename = "R/30DayChartChallenge2024/day_14/day_14_heatmap.png", 122 | plot = plot, 123 | width = 2560, 124 | height = 2560, 125 | units = "px", 126 | dpi = 320) 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_05/day_5_diverging.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_5_diverging 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(ggplot2) 6 | library(ggstats) 7 | library(ggtext) 8 | library(sysfonts) 9 | library(showtext) 10 | 11 | # Source ------------------------------------------------------------------ 12 | source("R/30DayChartChallenge2024/theme/styles.R") 13 | source("R/30DayChartChallenge2024/theme/theme.R") 14 | 15 | 16 | # Config ------------------------------------------------------------------ 17 | cfg <- 18 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 19 | cfg_day_5 <- cfg$day_5 20 | 21 | 22 | # Data -------------------------------------------------------------------- 23 | dt <- fread("R/30DayChartChallenge2024/day_05/ideo.csv") 24 | dt[, position := fcase( 25 | position %in% c("1 Izquierda", "2"), 26 | "Left", 27 | position %in% c("3", "4"), 28 | "Center-Left", 29 | position %in% c("5", "6"), 30 | "Center", 31 | position %in% c("7", "8"), 32 | "Center-Right", 33 | position %in% c("9", "10 Derecha"), 34 | "Right" 35 | )] 36 | dt[, position := factor(position, 37 | levels = c("Right", "Center-Right", "Center", "Center-Left", "Left"))] 38 | 39 | dt[, age := factor(age, 40 | levels = c("18-24", "25-34", "35-44", "45-54", "55-64", "65-74", "75+"))] 41 | 42 | dt_mw <- 43 | melt(dt[, .(age, position, m, w)], id.vars = c("position", "age")) 44 | dt_mw <- 45 | dt_mw[, .(value = sum(value)), by = .(position, age, variable)] 46 | dt_mw[, pct := value / sum(value), by = .(age, variable)] 47 | dt_mw[, variable := factor(variable, 48 | labels = c("Men", "Women"), 49 | levels = c("m", "w"))] 50 | 51 | 52 | # Plot -------------------------------------------------------------------- 53 | custom_label <- function(x) { 54 | p <- scales::percent(x, accuracy = 1) 55 | p[x < .075] <- "" 56 | p 57 | } 58 | 59 | colors <- c("#d93328", "#f05d5d", "#999999", "#5da7f0", "#3366cc") 60 | 61 | plot <- 62 | dt_mw[, ggplot(.SD, aes(variable, pct, fill = reorder(position,-as.numeric(position)))) + 63 | geom_bar(stat = "identity", position = "likert") + 64 | geom_text( 65 | aes( 66 | label = paste0(" ", sprintf("%2.0f", 100 * pct), "% "), 67 | hjust = fifelse(position == "Right", .65, 0.5), 68 | ), 69 | color = color_background, 70 | size = rel(5), 71 | family = "inter_regular", 72 | position = position_likert(vjust = 0.5) 73 | ) + 74 | scale_fill_manual(values = colors) + 75 | facet_wrap( ~ age, scales = "fixed", ncol = 1) + 76 | coord_flip() + 77 | scale_y_continuous(limits = c(-.70, .70), guide = "none") + 78 | labs( 79 | title = "Ideological self-positioning in Spain (2023)", 80 | subtitle = "Percentage by age group and sex", 81 | x = NULL, 82 | y = NULL, 83 | fill = NULL, 84 | caption = caption_text( 85 | source_text = cfg_day_5$source, 86 | day_type = cfg_day_5$category, 87 | day_hashtag = cfg_day_5$theme, 88 | day = cfg_day_5$day 89 | ) 90 | ) + 91 | theme_my() + 92 | theme( 93 | legend.position = "bottom", 94 | legend.spacing = unit(5, "pt"), 95 | legend.key.spacing = unit(5, "pt"), 96 | legend.key.height = unit(6, 'pt'), 97 | legend.key.width = unit(9.708, 'pt'), 98 | panel.grid.major = element_blank(), 99 | plot.margin = margin(25, 15, 15, 20, "pt") 100 | )] 101 | 102 | 103 | # Save -------------------------------------------------------------------- 104 | ggsave( 105 | filename = "day_5_diverging.png", 106 | path = normalizePath("R/30DayChartChallenge2024/day_05"), 107 | plot = plot, 108 | device = "png", 109 | units = "px", 110 | width = 1080, 111 | height = 1747.44, 112 | dpi = 320 113 | ) 114 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/cfg/plots.yml: -------------------------------------------------------------------------------- 1 | default: 2 | day_1: 3 | day: 1 4 | theme: part-to-whole 5 | category: Comparisons 6 | source: [Marcelo Aizen et al. (2019) and Alexandra-Maria Klein et al. (2006). | WorldinData.org] 7 | day_2: 8 | day: 2 9 | theme: neo 10 | category: Comparisons 11 | source: [Markandya & Wilkinson (2007); Sovacool et al. (2016); UNSCEAR (2008; & 2018) | OurWorldInData.org/energy] 12 | day_3: 13 | day: 3 14 | theme: makeover 15 | link: https://www.kff.org/other/issue-brief/data-note-public-awareness-antibiotic-resistance/ 16 | figure: Figure 8- Most Of The Public Unaware Antibiotic Resistance Is Unrelated To The Outbreak Of Viruses Such As Measles 17 | category: Comparisons 18 | source: KFF Health Tracking Poll (conducted May 30-June 4, 2019) 19 | day_4: 20 | day: 4 21 | theme: waffle 22 | category: Comparisons 23 | source: Portal de datos abiertos del Ayuntamiento de Madrid 24 | day_5: 25 | day: 5 26 | theme: diverging 27 | category: Comparisons 28 | source: Spanish Sociological Research Center (CIS) 29 | day_6: 30 | day: 6 31 | theme: data day OECD 32 | category: Comparisons 33 | source: OECD 34 | day_7: 35 | day: 7 36 | theme: hazards 37 | category: Distributions 38 | source: Ministerio de Agricultura y Pesca, Alimentación y Medio Ambiente 39 | day_8: 40 | day: 8 41 | theme: circular 42 | category: Distributions 43 | source: Portal de datos abiertos del Ayuntamiento de Madrid 44 | day_9: 45 | day: 9 46 | theme: major/minor 47 | category: Distributions 48 | source: Wikipedia 49 | day_10: 50 | day: 10 51 | theme: physical 52 | category: Distributions 53 | source: Billboard Database 54 | day_11: 55 | day: 11 56 | theme: mobile-friendly 57 | category: Distributions 58 | source: Prepared by the author, based on The Collatz Conjecture 59 | day_12: 60 | day: 12 61 | theme: theme day- Reuters Graphics 62 | category: Distributions 63 | source: Economist Intelligence Unit (2023) 64 | day_13: 65 | day: 13 66 | theme: family 67 | category: Relationships 68 | source: Matthews Data 69 | day_14: 70 | day: 14 71 | theme: heatmap 72 | category: Relationships 73 | source: Red de Vigilancia de la Calidad del Aire del Ayto. de Madrid 74 | day_15: 75 | day: 15 76 | theme: historical 77 | category: Relationships 78 | source: U.S. Bureau of Labor Statistics 79 | day_16: 80 | day: 16 81 | theme: weather 82 | category: Relationships 83 | source: Spanish Meteorological Agency (AEMET) 84 | day_17: 85 | day: 17 86 | theme: networks 87 | category: Relationships 88 | source: "{ggnetwork}: blood" 89 | day_18: 90 | day: 18 91 | theme: DataDay 92 | category: Relationships 93 | source: Asian Development Bank 94 | day_19: 95 | day: 19 96 | theme: dinosaurs 97 | category: Timeseries 98 | source: Google Trends 99 | day_20: 100 | day: 20 101 | theme: correlation 102 | category: Timeseries 103 | source: INE | Insee 104 | day_21: 105 | day: 21 106 | theme: GreenEnergy 107 | category: Timeseries 108 | source: Eurostat 109 | day_22: 110 | day: 22 111 | theme: mobility 112 | category: Timeseries 113 | source: Eurostat 114 | day_23: 115 | day: 23 116 | theme: tiles 117 | category: Timeseries 118 | source: GHSL Data Package 2023 119 | day_24: 120 | day: 24 121 | theme: DataDay 122 | category: Timeseries 123 | source: ILO Africa 124 | day_25: 125 | day: 25 126 | theme: GlobalChange 127 | category: Uncertainties 128 | source: NSIDC 129 | day_26: 130 | day: 26 131 | theme: AI 132 | category: Uncertainties 133 | source: UK ONS 134 | day_27: 135 | day: 27 136 | theme: GoodBad 137 | category: Uncertainties 138 | source: FUNCAS 139 | day_28: 140 | day: 28 141 | theme: trend 142 | category: Uncertainties 143 | source: Instituto Canario de Estadística 144 | day_29: 145 | day: 29 146 | theme: black_n_white 147 | category: Uncertainties 148 | source: Prepared by the author 149 | day_30: 150 | day: 30 151 | theme: FiveThirtyEight 152 | category: Uncertainties 153 | source: FiveThirtyEight 154 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_02/day_02_neo.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_02_neo 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(ggplot2) 6 | library(ggforce) 7 | library(ggtext) 8 | library(emojifont) 9 | library(sysfonts) 10 | library(showtext) 11 | 12 | 13 | # Source ------------------------------------------------------------------ 14 | source("R/30DayChartChallenge2024/theme/styles.R") 15 | source("R/30DayChartChallenge2024/theme/theme.R") 16 | 17 | # Config ------------------------------------------------------------------ 18 | cfg <- yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 19 | cfg_day_2 <- cfg$day_2 20 | 21 | 22 | # Data -------------------------------------------------------------------- 23 | death_rates_energy <- fread("R/30DayChartChallenge2024/day_02/death-rates-from-energy-production-per-twh.csv") 24 | death_rates_energy[, label := paste0(Entity, ": ", `Deaths per TWh of electricity production`)] 25 | label_length <- death_rates_energy[, max(nchar(as.character(label)))] + 2 26 | death_rates_energy[, label := paste0(label, strrep(" ", label_length - nchar(as.character(label))))] 27 | death_rates_energy[, Entity := factor(Entity, levels = Entity[order(`Deaths per TWh of electricity production`)])] 28 | death_rates_energy <- death_rates_energy[order(Entity)] 29 | 30 | 31 | # Don't know why but necessary 32 | death_rates_energy[, label := fcase( 33 | Entity == "Solar", paste0(" ", label), 34 | Entity == "Wind", paste0(" ", label), 35 | Entity == "Nuclear", paste0(" ", label), 36 | Entity == "Hydropower", paste0(" ", label), 37 | Entity == "Gas", paste0(" ", label), 38 | Entity == "Biomass", paste0(" ", label), 39 | Entity == "Oil", paste0(" ", label), 40 | Entity == "Coal", paste0(" ", label), 41 | Entity == "Brown coal", label 42 | )] 43 | 44 | 45 | 46 | # Plot -------------------------------------------------------------------- 47 | plot <- ggplot( 48 | death_rates_energy, 49 | aes( 50 | x = Entity, 51 | xend = Entity, 52 | y = 0, 53 | yend = `Deaths per TWh of electricity production` 54 | ) 55 | ) + 56 | geom_text( 57 | aes(label = label), 58 | hjust = -.2, 59 | family = "inter_bold", 60 | color = color_text_1, 61 | size = rel(5), 62 | ) + 63 | geom_link(size = 3.5, 64 | lineend = "round", 65 | color = color_set_2) + 66 | geom_link(size = 2.2, 67 | lineend = "round", 68 | color = color_set_1) + 69 | scale_y_continuous(limits = c(0, 40)) + 70 | coord_radial(theta = "y", 71 | -1.09 * pi, 72 | end = 0.9 * pi, 73 | inner.radius = .15) + 74 | geom_richtext(aes(I(.12), I(0), label = ""), 75 | size = 24, 76 | label.colour = NA, 77 | fill = NA, 78 | col = color_set_2, 79 | inherit.aes = F) + 80 | geom_richtext(aes(I(0), I(0), label = ""), 81 | size = 20, 82 | label.colour = NA, 83 | fill = NA, 84 | col = color_set_1, 85 | inherit.aes = F) + 86 | labs( 87 | title = "Death rates per unit of electricity production", 88 | subtitle = "Death rates are measured based on deaths from\naccidents and air pollution per terawatt-hour of electricity", 89 | caption = caption_text( 90 | source_text = cfg_day_2$source, 91 | day_type = cfg_day_2$category, 92 | day_hashtag = cfg_day_2$theme, 93 | day = cfg_day_2$day 94 | ), 95 | x = NULL, 96 | y = NULL 97 | ) + 98 | theme_my(title_size = 24) + 99 | theme( 100 | panel.grid.major = element_blank(), 101 | plot.margin = margin(1, 0, 0, 0, "cm"), 102 | axis.text = element_blank(), 103 | plot.subtitle = element_text(lineheight = .25, vjust = 1), 104 | plot.caption = element_textbox_simple( 105 | lineheight = .5, 106 | padding = margin(.1, .1, .1, .1, "lines"), 107 | margin = margin(0, 0, 1, 0, "lines"), 108 | ) 109 | ) 110 | 111 | # Save -------------------------------------------------------------------- 112 | ggsave( 113 | filename = "day_02_neo.png", 114 | path = normalizePath("R/30DayChartChallenge2024/day_02"), 115 | plot = plot, 116 | device = "png", 117 | units = "px", 118 | width = 1080, 119 | height = 1080, 120 | dpi = 320 121 | ) 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_08/day_8_circular.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_8_circular 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(ggplot2) 6 | library(ggforce) 7 | library(ggtext) 8 | library(emojifont) 9 | library(sysfonts) 10 | library(showtext) 11 | library(patchwork) 12 | 13 | 14 | # Source ------------------------------------------------------------------ 15 | source("R/30DayChartChallenge2024/theme/styles.R") 16 | source("R/30DayChartChallenge2024/theme/theme.R") 17 | 18 | 19 | # Config ------------------------------------------------------------------ 20 | cfg <- 21 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 22 | cfg_day_8 <- cfg$day_8 23 | 24 | 25 | # Data ---------------------------------------------------------------- 26 | dt <- 27 | readRDS("R/30DayChartChallenge2024/day_08/pm10_mean_zona_2001.RDS") 28 | 29 | dt[, rolling_mean_10y := frollmean(mean_zona, 10, align = "right", fill = NA), zona] 30 | dt[, rolling_sd_10y := frollapply(mean_zona, 10, sd, align = "right", fill = NA), zona] 31 | dt[, yday := yday(fecha)] 32 | dt[, ymin := rolling_mean_10y - 2 * rolling_sd_10y] 33 | dt[, ymax := rolling_mean_10y + 2 * rolling_sd_10y] 34 | 35 | 36 | plot <- dt[fecha >= "2023-01-01" & 37 | zona == "Interior M30", ggplot(.SD, aes(yday, mean_zona)) + 38 | geom_ribbon(data = .SD[fecha <= "2023-12-31"], 39 | aes(ymin = ymin, 40 | ymax = ymax, 41 | fill = "± 2sd"), 42 | alpha = 0.33) + 43 | geom_line(data = .SD[fecha <= "2023-12-31"], aes(color = "PM10 concentration")) + 44 | geom_line(data = .SD[fecha <= "2023-12-31"], 45 | aes(y = rolling_mean_10y, color = "10y roll mean")) + 46 | scale_y_continuous(labels = scales::number_format(accuracy = 1)) + 47 | scale_color_manual(values = c("PM10 concentration" = c2_color_text_2, 48 | "10y roll mean" = c2_color_accent_2)) + 49 | scale_fill_manual(values = c("± 2sd" = c2_color_accent_1)) + 50 | labs( 51 | title = "Daily air quality in Madrid in 2023", 52 | subtitle = "PM10 mean concentration Interior M30 (Central Madrid)", 53 | x = NULL, 54 | y = "PM10 concentration (µg/m³)", 55 | fill = NULL, 56 | color = NULL, 57 | caption = caption_text( 58 | source_text = cfg_day_8$source, 59 | day_type = cfg_day_8$category, 60 | day_hashtag = cfg_day_8$theme, 61 | day = cfg_day_8$day, 62 | color_text_1 = c2_color_text_1, 63 | color_text_2 = c2_color_text_2 64 | ) 65 | ) + 66 | coord_radial( 67 | inner.radius = .25, 68 | rotate_angle = TRUE, 69 | expand = FALSE, 70 | r_axis_inside = FALSE, 71 | direction = 1 72 | ) + 73 | scale_x_continuous(breaks = cumsum(c(31, 28, 31, 30 , 31 , 31, 30, 31, 30, 31, 30, 31))) + 74 | theme_my( 75 | font_regular = "roboto_regular", 76 | font_bold = "roboto_bold", 77 | font_light = "roboto_light", 78 | color_text_1 = c2_color_text_1, 79 | color_text_2 = c2_color_text_2, 80 | color_background = c2_color_background, 81 | title_size = 24 82 | ) + 83 | theme(plot.margin = margin(25, 5, 5, 0, "pt"), 84 | legend.position = "bottom", 85 | legend.margin = margin(0, 0, 0, 0, "pt"), 86 | legend.spacing = unit(5, "pt"), 87 | legend.key.spacing = unit(5, "pt"), 88 | legend.key.height = unit(6, 'pt'), 89 | legend.key.width = unit(9.708, 'pt'), 90 | axis.title.y = element_text( 91 | hjust = 0.5, 92 | vjust = 5 93 | ))] 94 | 95 | # Save -------------------------------------------------------------------- 96 | ggsave( 97 | filename = "day_8_circular.png", 98 | path = normalizePath("R/30DayChartChallenge2024/day_08"), 99 | plot = plot, 100 | device = "png", 101 | units = "px", 102 | width = 1080, 103 | height = 1080, 104 | dpi = 320 105 | ) 106 | -------------------------------------------------------------------------------- /R/2024/week_02/2024_w02_lego_map.R: -------------------------------------------------------------------------------- 1 | # Header ------------------------------------------------------------------ 2 | # 3 | # Author: Michal Kinel 4 | # Copyright (c) Michal Kinel, 2024 5 | # Email: michal.kinel@gmail.com 6 | # 7 | # Date: 2024-01-14 8 | # 9 | # Script Name: 2024_w02_lego_map.R 10 | # 11 | # Script Description: Make lego style map of Poland of the % eco farms 12 | # 13 | # 14 | # Notes: 15 | # 16 | # 17 | 18 | # Set options ------------------------------------------------------------- 19 | cat("Setting options... \n\n", sep = "") 20 | options(scipen = 999) # turns off scientific notation 21 | options(encoding = "UTF-8") # sets string encoding to UTF-8 instead of ANSI 22 | 23 | 24 | # Install packages & load libraries --------------------------------------- 25 | cat("Install packages & load libraries... \n\n", sep = "") 26 | packages <- c("tidyverse", "data.table", "sf", "raster", "extrafont") # list of packages to load 27 | n_packages <- length(packages) # count how many packages are required 28 | 29 | new_pkg <- packages[!(packages %in% installed.packages())] # determine which packages aren't installed 30 | 31 | # Install missing packages 32 | if(length(new_pkg)){ 33 | install.packages(new_pkg) 34 | } 35 | 36 | # Load all requried libraries 37 | for(n in 1:n_packages){ 38 | cat("Loading Library #", n, " of ", n_packages, "... Currently Loading: ", packages[n], "\n", sep = "") 39 | lib_load <- paste("library(\"",packages[n],"\")", sep = "") # create string of text for loading each library 40 | eval(parse(text = lib_load)) # evaluate the string to load the library 41 | } 42 | 43 | # Load data --------------------------------------------------------------- 44 | cat("Load data... \n\n", sep = "") 45 | poland <- sf::st_as_sf(raster::getData('GADM', country = 'POL', level = 1)) 46 | eco_farms <- fread("R/2024/week_02/eco_farms_poland.csv") 47 | eco_farms[, perc_eco := eco_farms / farms] 48 | 49 | # Join data --------------------------------------------------------------- 50 | cat("Join data... \n\n", sep = "") 51 | poland <- poland %>% 52 | left_join(eco_farms, by = "NAME_1") 53 | 54 | 55 | # Prepare data ------------------------------------------------------------ 56 | # Make grid 57 | grid <- st_make_grid(poland, n = c(45,45)) %>% st_sf() 58 | grid <- st_join(grid, poland) 59 | grid <- grid %>% filter(!is.na(perc_eco)) 60 | centroids <- st_centroid(grid) 61 | 62 | 63 | # Style ------------------------------------------------------------------- 64 | # Color palette 65 | background <- "#0D1F2D" 66 | text <- "#FFFFFF" 67 | palette <- c("#FF3D3D", "#ffe0c8","#afffff", "#4a9d9c", "#0D6E6E") 68 | 69 | # Load fonts 70 | loadfonts(device = "win") 71 | 72 | # Fonts 73 | font_base <- "Lato" 74 | font_title <- "Lato Black" 75 | 76 | # Plot data --------------------------------------------------------------- 77 | cat("Plot data... \n\n", sep = "") 78 | 79 | plot <- 80 | ggplot() + 81 | geom_sf(data = grid, aes(fill = perc_eco), color = background) + 82 | geom_sf(data = centroids, 83 | color = alpha("black", 0.75), 84 | size = 1) + 85 | labs(fill = "% of eco-farms", title = "Ecological farms in Poland \U1F33D", 86 | caption = "Source: Główny Urząd Statystyczny\nmichal0091") + 87 | guides(fill = guide_legend( 88 | nrow = 1, 89 | title.position = "top", 90 | label.position = "bottom" 91 | )) + 92 | scale_fill_stepsn(labels = scales::percent, colors = palette, 93 | breaks = c(0, .01, .02, .04, .06, .08)) + 94 | theme_void() + 95 | theme( 96 | plot.margin = margin(1, 0.5, 1, 1, "cm"), 97 | plot.background = element_rect(fill = background, color = NA), 98 | plot.title = element_text( 99 | hjust = 0.5, 100 | vjust = 6, 101 | color = text, 102 | family = font_title, 103 | size = 28 104 | ), 105 | plot.caption = element_text( 106 | hjust = 1, 107 | vjust = -18, 108 | color = text, 109 | family = font_base, 110 | size = 8 111 | ), 112 | legend.position = "bottom", 113 | legend.title = element_text( 114 | hjust = 0.5, 115 | color = text, 116 | family = font_title 117 | ), 118 | legend.text = element_text(color = text, family = font_base) 119 | ) 120 | plot 121 | 122 | # Save plot --------------------------------------------------------------- 123 | cat("Saving plot... \n\n", sep = "") 124 | 125 | ggsave( 126 | filename = "eco_farms_poland.png", 127 | path = normalizePath("R/2024/week_02/"), 128 | plot = plot, 129 | device = "png", 130 | units = "cm", 131 | width = 15.75, 132 | height = 21 133 | ) 134 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_21/day_21_green_energy.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_21_green_energy 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(patchwork) 13 | library(lubridate) 14 | library(zoo) 15 | 16 | 17 | # Source ------------------------------------------------------------------ 18 | source("R/30DayChartChallenge2024/theme/styles.R") 19 | source("R/30DayChartChallenge2024/theme/theme.R") 20 | 21 | 22 | # Config ------------------------------------------------------------------ 23 | cfg <- 24 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 25 | cfg_day_21 <- cfg$day_21 26 | 27 | 28 | 29 | # Data -------------------------------------------------------------------- 30 | energy <- fread("R/30DayChartChallenge2024/day_21/energy.csv", dec = ",") 31 | 32 | energy <- melt(energy, id.vars = "year", variable.name = "Country", value.name = "Share") 33 | energy[, Country := factor(Country, levels = c("Portugal", "Italy", "Greece", "Spain", "EU27"), 34 | labels = c("Portugal", "Italy", "Greece", "Spain", "EU27"))] 35 | energy[, Share := Share / 100] 36 | 37 | 38 | # Plot -------------------------------------------------------------------- 39 | 40 | plot <- energy[, ggplot(.SD, aes(year, Share, color = Country)) + 41 | geom_line() + 42 | geom_point() + 43 | labs(title = "Share of renewable energy in gross final energy consumption", 44 | subtitle = "Renewable energy sources in electricity in PIGS countries", 45 | x = NULL, 46 | y = "% of renewable energy", 47 | color = NULL, 48 | caption = caption_text( 49 | source_text = cfg_day_21$source, 50 | day_type = cfg_day_21$category, 51 | day_hashtag = cfg_day_21$theme, 52 | day = cfg_day_21$day, 53 | color_text_1 = c4_color_text_1, 54 | color_text_2 = c4_color_text_2 55 | )) + 56 | scale_y_continuous(labels = scales::percent_format(accuracy = 1), 57 | limits = c(0, .8), 58 | breaks = seq(0, .8, .2)) + 59 | scale_color_manual(values = c( 60 | "Portugal" = "#0D6938", 61 | "Italy" = "#ce2b37", 62 | "Greece" = "#0d5eaf", 63 | "Spain" = "#F1BF00", 64 | "EU27" = "#001489" 65 | )) + 66 | theme_my( 67 | font_regular = "josefin_regular", 68 | font_bold = "josefin_bold", 69 | font_light = "josefin_light", 70 | color_text_1 = c4_color_text_1, 71 | color_text_2 = c4_color_text_2, 72 | color_background = c4_color_background, 73 | title_size = 50 74 | ) + 75 | theme( 76 | legend.position = "bottom", 77 | plot.margin = margin(25, 25, 10, 10, "pt"), 78 | plot.caption = element_textbox_simple( 79 | size = 20, 80 | lineheight = .5, 81 | padding = margin(4, 0, 4, 0, "pt"), 82 | margin = margin(20, 0, 0, 0, "pt"), 83 | ), 84 | axis.text = element_text( 85 | size = rel(2), 86 | family = "josefin_bold", 87 | color = c4_color_text_2, 88 | margin = margin(2, 2, 2, 0, "pt") 89 | ), 90 | axis.title.y = element_text( 91 | size = 32, 92 | family = "josefin_bold", 93 | color = c4_color_text_2, 94 | margin = margin(5, 5, 5, 5, "pt"), 95 | angle = 90 96 | ), 97 | panel.grid.major = element_line( 98 | color = c4_color_text_2, 99 | linetype = "dotted", 100 | size = .3, 101 | ), 102 | axis.title.y.right = element_text( 103 | size = 32, 104 | family = "josefin_bold", 105 | color = c4_color_text_2, 106 | margin = margin(5, 5, 5, 5, "pt"), 107 | angle = -90 108 | ) 109 | ) 110 | ] 111 | 112 | 113 | # Save -------------------------------------------------------------------- 114 | ggsave( 115 | filename = "R/30DayChartChallenge2024/day_21/day_21_green_energy.png", 116 | plot = plot, 117 | width = 3106.56, 118 | height = 1920, 119 | units = "px", 120 | dpi = 320 121 | ) 122 | 123 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_15/day_15_historical.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_15_historical 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(patchwork) 13 | library(lubridate) 14 | 15 | 16 | # Source ------------------------------------------------------------------ 17 | source("R/30DayChartChallenge2024/theme/styles.R") 18 | source("R/30DayChartChallenge2024/theme/theme.R") 19 | 20 | 21 | # Config ------------------------------------------------------------------ 22 | cfg <- 23 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 24 | cfg_day_15 <- cfg$day_15 25 | 26 | 27 | # Data -------------------------------------------------------------------- 28 | dt <- fread("R/30DayChartChallenge2024/day_15/fredgraph.csv") 29 | 30 | 31 | # Plot -------------------------------------------------------------------- 32 | dt_sub <- dt[DATE >="1950-01-01" & DATE <="1984-12-01"] 33 | dt_sub[, date_braek := fifelse(DATE <= "1970-12-01", "Yaers 1950-1970", "Years 1971-1984")] 34 | 35 | 36 | plot <- dt_sub[, ggplot(.SD, aes(UNRATE, CPIAUCSL_PC1)) + 37 | geom_point(aes(color = date_braek), size = 2.5, alpha = .5) + 38 | scale_color_manual(values = c(c3_color_accent_1, c3_color_accent_2)) + 39 | geom_smooth( 40 | data = .SD[DATE <= "1970-12-01"], 41 | method = "glm", 42 | formula = y ~ log(x), 43 | se = FALSE, 44 | color = c3_color_text_2, 45 | linewidth = 1.05, 46 | show.legend = FALSE 47 | ) + 48 | scale_x_continuous(breaks = seq(0, 12, 2), limits = c(0,12)) + 49 | scale_y_continuous(breaks = seq(-2.5, 15, 2.5), limits = c(-3,15)) + 50 | labs( 51 | title = "Fall of the Phillips Curve", 52 | subtitle = "Unemployment and Inflation in the United States\nYears 1950-1984", 53 | x = "Unemployment rate (%)", 54 | y = "Inflation rate (%)", 55 | color = NULL, 56 | caption = caption_text( 57 | source_text = cfg_day_15$source, 58 | day_type = cfg_day_15$category, 59 | day_hashtag = cfg_day_15$theme, 60 | day = cfg_day_15$day, 61 | color_text_1 = c3_color_text_2, 62 | color_text_2 = c3_color_text_1 63 | ) 64 | ) + 65 | theme_my( 66 | font_regular = "redhat_regular", 67 | font_bold = "redhat_bold", 68 | font_light = "redhat_light", 69 | color_text_1 = c3_color_text_1, 70 | color_text_2 = c3_color_text_2, 71 | color_background = c3_color_background, 72 | title_size = 52 73 | ) + 74 | theme( 75 | plot.margin = margin(20, 25, 10, 20, "pt"), 76 | plot.caption = element_textbox_simple( 77 | size = 24, 78 | lineheight = .5, 79 | padding = margin(5, 5, 5, 5, "pt"), 80 | margin = margin(10, 0, 0, 0, "pt"), 81 | ), 82 | legend.position = "bottom", 83 | legend.spacing = unit(5, "pt"), 84 | legend.key.spacing = unit(5, "pt"), 85 | legend.key.height = unit(10, 'pt'), 86 | legend.key.width = unit(16.18, 'pt'), 87 | panel.grid.major = element_line( 88 | colour = c3_color_text_2, 89 | linetype = "solid", 90 | linewidth = .3 91 | ), 92 | axis.text = element_text( 93 | size = rel(1.8), 94 | family = "redhat_regular", 95 | color = c3_color_text_2, 96 | margin = margin(2, 2, 2, 0, "pt") 97 | ) 98 | )] 99 | 100 | 101 | # Save -------------------------------------------------------------------- 102 | ggsave( 103 | filename = "R/30DayChartChallenge2024/day_15/day_15_historical.png", 104 | plot = plot, 105 | width = 1920, 106 | height = 1920, 107 | units = "px", 108 | dpi = 320 109 | ) 110 | 111 | -------------------------------------------------------------------------------- /R/2024/week_06/median_net_wealth_by_age.csv: -------------------------------------------------------------------------------- 1 | concepto,elemento,estadistico,desglose,categoria,unidadMedida,ola,valor 2 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 35 y 44,Miles de Euros (),2017,65.7911983563343 3 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 45 y 54,Miles de Euros (),2017,116.02595494030082 4 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 55 y 64,Miles de Euros (),2017,176.97383595224068 5 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 65 y 74,Miles de Euros (),2017,183.1412059311521 6 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Mayor de 75,Miles de Euros (),2017,131.38357782601955 7 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Menor de 35,Miles de Euros (),2017,5.373384726314157 8 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 35 y 44,Miles de Euros (),2014,71.9878903031208 9 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 45 y 54,Miles de Euros (),2014,129.34132809317606 10 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 55 y 64,Miles de Euros (),2014,194.7444753810164 11 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 65 y 74,Miles de Euros (),2014,215.51803352346823 12 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Mayor de 75,Miles de Euros (),2014,132.0591222417998 13 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Menor de 35,Miles de Euros (),2014,4.959630481310039 14 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 35 y 44,Miles de Euros (),2011,122.77505147408418 15 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 45 y 54,Miles de Euros (),2011,171.9979978982872 16 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 55 y 64,Miles de Euros (),2011,246.70105326208423 17 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 65 y 74,Miles de Euros (),2011,204.170865899994 18 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Mayor de 75,Miles de Euros (),2011,162.6955036593047 19 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Menor de 35,Miles de Euros (),2011,72.65405756547536 20 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 35 y 44,Miles de Euros (),2008,171.12734298403552 21 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 45 y 54,Miles de Euros (),2008,225.50111318732883 22 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 55 y 64,Miles de Euros (),2008,308.9709906613852 23 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 65 y 74,Miles de Euros (),2008,219.40727257886752 24 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Mayor de 75,Miles de Euros (),2008,173.04273277681384 25 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Menor de 35,Miles de Euros (),2008,85.17145631322224 26 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 35 y 44,Miles de Euros (),2005,193.2520578067752 27 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 45 y 54,Miles de Euros (),2005,268.6937365674177 28 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 55 y 64,Miles de Euros (),2005,281.520113697285 29 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 65 y 74,Miles de Euros (),2005,221.67549879509264 30 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Mayor de 75,Miles de Euros (),2005,165.49992649535392 31 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Menor de 35,Miles de Euros (),2005,87.24643017747626 32 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 35 y 44,Miles de Euros (),2002,117.66751414777336 33 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 45 y 54,Miles de Euros (),2002,163.03078947896952 34 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 55 y 64,Miles de Euros (),2002,164.1573385758243 35 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 65 y 74,Miles de Euros (),2002,131.8997640776074 36 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Mayor de 75,Miles de Euros (),2002,98.99752320626216 37 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Menor de 35,Miles de Euros (),2002,65.14499235512984 38 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 35 y 44,Miles de Euros (),2020,70.0 39 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 45 y 54,Miles de Euros (),2020,116.48084 40 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 55 y 64,Miles de Euros (),2020,160.6502 41 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Entre 65 y 74,Miles de Euros (),2020,197.9254 42 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Mayor de 75,Miles de Euros (),2020,165.18779999999998 43 | RIQUEZA,RIQUEZA NETA,MEDIANA,EDAD DEL CABEZA DE FAMILIA,Menor de 35,Miles de Euros (),2020,23.9686 44 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_19/day_19_dinosaurs.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_19_dinosaurs 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(patchwork) 13 | library(lubridate) 14 | library(zoo) 15 | 16 | 17 | # Source ------------------------------------------------------------------ 18 | source("R/30DayChartChallenge2024/theme/styles.R") 19 | source("R/30DayChartChallenge2024/theme/theme.R") 20 | 21 | 22 | # Config ------------------------------------------------------------------ 23 | cfg <- 24 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 25 | cfg_day_19 <- cfg$day_19 26 | 27 | 28 | # Data -------------------------------------------------------------------- 29 | dinos <- fread("R/30DayChartChallenge2024/day_19/multiTimeline.csv") 30 | 31 | setnames(dinos, 32 | old = c("Mes", "dinosaurs: (Todo el mundo)"), 33 | new = c("date", "searches")) 34 | 35 | dinos[, date := lubridate::as_date(as.yearmon(date, format = "%Y-%m"))] 36 | 37 | 38 | # 2009 - Ice Age: Dawn of the Dinosaurs - 1 July 2009 39 | # 2013 - Walking with Dinosaurs - 20 December 2013 40 | # 2015 - Jurassic World - 12 June 2015 41 | # 2018 - Jurassic World: Fallen Kingdom - 22 June 2018 42 | # 2022 - Jurassic World: Dominion - 10 June 2022 43 | 44 | labels <- data.table( 45 | date = as.Date(c("2009-07-01", "2013-12-01", "2015-06-01", "2018-06-01", "2022-07-01")), 46 | label = c("Ice Age: Dawn of the Dinosaurs", "Walking with Dinosaurs", "Jurassic World", "Jurassic World: Fallen Kingdom", "Jurassic World: Dominion") 47 | ) 48 | labels <- merge(labels, dinos, by = "date") 49 | 50 | # Plot -------------------------------------------------------------------- 51 | 52 | plot <- dinos[, ggplot(.SD, aes(date, searches)) + 53 | geom_line(color = c4_color_set_1) + 54 | geom_point(data = .SD[date %in% labels$date], color = c4_color_set_1) + 55 | geom_text( 56 | data = labels, 57 | aes(label = label, x = date, y = searches), 58 | hjust = 0, 59 | vjust = -1, 60 | nudge_x = 1, 61 | family = "josefin_bold", 62 | color = c4_color_text_1, 63 | size = rel(9) 64 | ) + 65 | scale_x_date( 66 | date_breaks = "1 year", 67 | date_labels = "%Y", 68 | limits = c(as.Date("2005-01-01"), as.Date("2025-01-01")), 69 | expand = c(0, 0) 70 | ) + 71 | scale_y_continuous( 72 | expand = c(0, 0), 73 | limits = c(0, 100), 74 | labels = scales::number_format(accuracy = 1) 75 | ) + 76 | labs( 77 | title = "Dinosaurs searches on Google", 78 | subtitle = "2005 - 2024", 79 | x = "Year", 80 | y = "Interest over time", 81 | caption = caption_text( 82 | source_text = cfg_day_19$source, 83 | day_type = cfg_day_19$category, 84 | day_hashtag = cfg_day_19$theme, 85 | day = cfg_day_19$day, 86 | color_text_1 = c4_color_text_1, 87 | color_text_2 = c4_color_text_2 88 | ) 89 | ) + 90 | theme_my( 91 | font_regular = "josefin_regular", 92 | font_bold = "josefin_bold", 93 | font_light = "josefin_light", 94 | color_text_1 = c4_color_text_1, 95 | color_text_2 = c4_color_text_2, 96 | color_background = c4_color_background, 97 | title_size = 50 98 | ) + 99 | theme( 100 | axis.title = element_blank(), 101 | legend.position = "none" 102 | ) + 103 | coord_cartesian(clip = "off") + 104 | theme( 105 | plot.margin = margin(25, 25, 10, 10, "pt"), 106 | plot.caption = element_textbox_simple( 107 | size = 20, 108 | lineheight = .5, 109 | padding = margin(4, 0, 4, 0, "pt"), 110 | margin = margin(20, 0, 0, 0, "pt"), 111 | ), 112 | axis.text = element_text( 113 | size = rel(2), 114 | family = "josefin_bold", 115 | color = c4_color_text_2, 116 | margin = margin(2, 2, 2, 0, "pt") 117 | ), 118 | axis.title.y = element_text( 119 | size = rel(3), 120 | family = "josefin_bold", 121 | color = c4_color_text_2, 122 | margin = margin(5, 5, 5, 5, "pt"), 123 | angle = 90 124 | ), 125 | panel.grid.major = element_line( 126 | color = c4_color_text_2, 127 | linetype = "dotted", 128 | size = .3, 129 | 130 | ) 131 | )] 132 | 133 | 134 | # Save -------------------------------------------------------------------- 135 | ggsave( 136 | filename = "R/30DayChartChallenge2024/day_19/day_19_dinosaurs.png", 137 | plot = plot, 138 | width = 3106.56, 139 | height = 1920, 140 | units = "px", 141 | dpi = 320 142 | ) 143 | 144 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_18/day_18_asian_development_bank.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_18_asian_development_bank 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(patchwork) 13 | library(lubridate) 14 | library(geomnet) 15 | library(ggnetwork) 16 | library(igraph) 17 | 18 | 19 | # Source ------------------------------------------------------------------ 20 | source("R/30DayChartChallenge2024/theme/styles.R") 21 | source("R/30DayChartChallenge2024/theme/theme.R") 22 | 23 | 24 | # Config ------------------------------------------------------------------ 25 | cfg <- 26 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 27 | cfg_day_18 <- cfg$day_18 28 | 29 | 30 | # Data -------------------------------------------------------------------- 31 | exch <- fread("R/30DayChartChallenge2024/day_18/exchange.csv", dec = ",") 32 | library(readxl) 33 | KIDB <- read_excel("R/30DayChartChallenge2024/day_18/KIDB.xlsx") %>% 34 | as.data.table() 35 | 36 | KIDB <- KIDB[Economy %in% exch[, country]] 37 | KIDB <- KIDB[, .(int_tourism_receipts_pc = 1000 * `2022`[Indicator == "International Tourism Receipts ($ million)"] / `2022`[Indicator == "Total population"], 38 | gdp_pc_lp = `2022`[Indicator == "GDP at current prices"] / `2022`[Indicator == "Total population"]), by = .(country = Economy)] 39 | KIDB <- na.omit(KIDB) 40 | KIDB <- merge(KIDB, exch, by = "country") 41 | KIDB[, gdp_pc_usd := gdp_pc_lp / exchange_rate] 42 | 43 | 44 | # Plot -------------------------------------------------------------------- 45 | 46 | plot <- KIDB[, ggplot(.SD, aes(x = gdp_pc_usd, y = int_tourism_receipts_pc)) + 47 | geom_point(aes(color = region), size = 3) + 48 | geom_text_repel(aes(label = country), size = rel(8), 49 | box.padding = 1, point.padding = 1, 50 | max.overlaps = 12, 51 | family = "redhat_regular") + 52 | scale_x_log10(expand = c(0.1, 0.1), 53 | labels = scales::label_dollar(accuracy = 1000L)) + 54 | scale_y_log10(expand = c(0.1, 0.5), 55 | 56 | labels = scales::label_dollar(accuracy = 1000L)) + 57 | scale_color_manual(values = c("#d99058", 58 | "#02517a", 59 | "#9556eb", 60 | "#c0dccd")) + 61 | labs( 62 | title = "International Tourism Receipts vs\nGDP per capita", 63 | subtitle = "Asian Development Bank 2022", 64 | x = "GDP per capita (USD)", 65 | y = "International Tourism Receipts per capita (USD thousand)", 66 | color = NULL, 67 | caption = caption_text( 68 | source_text = cfg_day_18$source, 69 | day_type = cfg_day_18$category, 70 | day_hashtag = cfg_day_18$theme, 71 | day = cfg_day_18$day, 72 | color_text_1 = c3_color_text_1, 73 | color_text_2 = c3_color_text_2 74 | ) 75 | ) + 76 | theme_my( 77 | font_regular = "redhat_regular", 78 | font_bold = "redhat_bold", 79 | font_light = "redhat_light", 80 | color_text_1 = c3_color_text_1, 81 | color_text_2 = c3_color_text_2, 82 | color_background = c3_color_background, 83 | title_size = 50 84 | ) + 85 | theme( 86 | plot.margin = margin(20, 60, 10, 20, "pt"), 87 | plot.caption = element_textbox_simple( 88 | size = 20, 89 | lineheight = .5, 90 | padding = margin(4, 0, 4, 0, "pt"), 91 | margin = margin(20, 0, 0, 0, "pt"), 92 | ), 93 | legend.position = "bottom", 94 | legend.spacing = unit(2.5, "pt"), 95 | legend.key.spacing = unit(2.5, "pt"), 96 | legend.key.height = unit(8, 'pt'), 97 | legend.key.width = unit(12.944, 'pt'), 98 | legend.title = element_text(hjust = 0), 99 | panel.grid.major = element_line( 100 | colour = c3_color_text_2, 101 | linetype = "dashed", 102 | linewidth = .3 103 | ), 104 | axis.text = element_text( 105 | size = rel(1.8), 106 | family = "redhat_regular", 107 | color = c3_color_text_2, 108 | margin = margin(2, 2, 2, 0, "pt") 109 | ) 110 | )] 111 | 112 | 113 | # Save plot --------------------------------------------------------------- 114 | ggsave( 115 | filename = "R/30DayChartChallenge2024/day_18/day_18_asian_development_bank.png", 116 | plot = plot, 117 | width = 1920, 118 | height = 1920, 119 | units = "px", 120 | dpi = 320 121 | ) 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_03/day_3_makeover.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_3_makeover 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(ggplot2) 6 | library(ggforce) 7 | library(ggtext) 8 | library(emojifont) 9 | library(sysfonts) 10 | library(showtext) 11 | library(ggpubr) 12 | 13 | 14 | # Source ------------------------------------------------------------------ 15 | source("R/30DayChartChallenge2024/theme/styles.R") 16 | source("R/30DayChartChallenge2024/theme/theme.R") 17 | 18 | 19 | # Config ------------------------------------------------------------------ 20 | cfg <- 21 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 22 | cfg_day_3 <- cfg$day_3 23 | 24 | # Data -------------------------------------------------------------------- 25 | # From chart 26 | # Values less than 0.5 percent are indicated by an asterisk (*) 27 | #' 28 | #'Q11. To the best of your knowledge, will the overuse of antibiotics lead to 29 | #' (INSERT ITEM), will the overuse of antibiotics not lead to this, or do 30 | #' you not know enough to say? How about (INSERT NEXT ITEM)? 31 | #' (IF NECESSARY: Will the overuse of antibiotics lead to (INSERT ITEM), will 32 | #' the overuse of antibiotics not lead to this, or do you not know enough to say?) 33 | #' (scramble items a-f) 34 | #' c. The spread of measles or other contagious viruses 26 39 35 * 35 | #' 36 | 37 | dt <- data.table( 38 | correct = c("Correct", "Incorrect", "Incorrect"), 39 | anwser = c("No", "Yes", "Don't know enough to say"), 40 | value = c(0.39, 0.26, 0.35) 41 | ) 42 | dt[, label := paste0(correct, " ", sprintf("%2.0f", 100 * sum(value)), "%"), by = correct] 43 | 44 | # Plot -------------------------------------------------------------------- 45 | color_text_2 <- "#2948FF" 46 | title_text <- glue::glue( 47 | "Most of the public 48 | unaware, antibiotic resistance
is 49 | unrelated to the outbreak of viruses such as measles 50 |
" 51 | ) 52 | 53 | 54 | plot <- dt %>% 55 | ggplot(aes(value, anwser, fill = anwser)) + 56 | geom_col(just = 0.5, size = 1) + 57 | facet_grid(label ~ ., scales = "free", space = "free") + 58 | geom_text( 59 | aes(label = paste0(" ", sprintf("%2.0f", 100 * value), "% "), 60 | hjust = -.1), 61 | vjust = "center", 62 | color = color_text_1, 63 | size = rel(7), 64 | fontface = "bold", 65 | family = "inter_regular" 66 | ) + 67 | geom_text( 68 | aes(x = 0.005, 69 | label = anwser), 70 | color = color_background, 71 | hjust = "left", 72 | vjust = "center", 73 | size = rel(9), 74 | fontface = "bold", 75 | family = "inter_regular" 76 | ) + 77 | scale_x_continuous( 78 | name = NULL, 79 | expand = c(0, 0), 80 | limits = c(0, 0.5), 81 | guide = "none" 82 | ) + 83 | scale_y_discrete(guide = "none") + 84 | scale_color_manual(values = c(color_text_1, color_background), 85 | guide = "none") + 86 | scale_fill_manual( 87 | values = c( 88 | "No" = "#537c78", 89 | "Yes" = "#cc222b", 90 | "Don't know enough to say" = "#f15b4c" 91 | ), 92 | guide = "none" 93 | ) + 94 | labs( 95 | title = title_text, 96 | subtitle = "To the best of your knowledge, will the overuse of antibiotics\nlead to the spread of measles or other contagious viruses?", 97 | x = NULL, 98 | y = NULL, 99 | caption = glue::glue( 100 | "* Refused less than 0.5%
", 101 | caption_text( 102 | source_text = cfg_day_3$source, 103 | day_type = cfg_day_3$category, 104 | day_hashtag = cfg_day_3$theme, 105 | day = cfg_day_3$day, 106 | color_text_2 = color_text_2 107 | ) 108 | ) 109 | ) + 110 | theme_my(color_text_2 = color_text_2) + 111 | theme( 112 | strip.background = element_rect(fill = color_text_1, color = color_background), 113 | strip.text = element_text( 114 | color = color_background, 115 | family = "inter_regular", 116 | hjust = 0.5, 117 | margin = margin(.25, .25, .25, .25, "line"), 118 | face = "bold", 119 | angle = -90, 120 | ), 121 | panel.grid.major = element_blank(), 122 | panel.spacing = unit(0.5, "lines"), 123 | plot.title = element_markdown( 124 | size = 26, 125 | family = "inter_bold", 126 | face = "bold", 127 | hjust = 0, 128 | vjust = 4.5, 129 | lineheight = .34, 130 | margin = margin(.2, .2, 1, .2, "lines") 131 | ), 132 | plot.margin = margin(.5, .5, .5, .5, "lines"), 133 | ) 134 | 135 | 136 | # Save -------------------------------------------------------------------- 137 | ggsave( 138 | filename = "day_3_makeover.png", 139 | path = normalizePath("R/30DayChartChallenge2024/day_03"), 140 | plot = plot, 141 | device = "png", 142 | units = "px", 143 | width = 1080, 144 | height = 1080, 145 | dpi = 320 146 | ) 147 | 148 | 149 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_20/day_20_correlation.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_20_correlation 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(patchwork) 13 | library(lubridate) 14 | library(zoo) 15 | 16 | 17 | # Source ------------------------------------------------------------------ 18 | source("R/30DayChartChallenge2024/theme/styles.R") 19 | source("R/30DayChartChallenge2024/theme/theme.R") 20 | 21 | 22 | # Config ------------------------------------------------------------------ 23 | cfg <- 24 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 25 | cfg_day_20 <- cfg$day_20 26 | 27 | 28 | # Data -------------------------------------------------------------------- 29 | cpi_brent <- fread("R/30DayChartChallenge2024/day_20/cpi_brent.csv", dec = ",") 30 | cpi_brent[, y_m := as.Date(as.yearmon(y_m, "%YM%m"))] 31 | cpi_brent[, cpi := cpi / 100] 32 | 33 | 34 | # Plot -------------------------------------------------------------------- 35 | 36 | b <- diff(cpi_brent[, c(min(brent_crude_oil_12m), max(brent_crude_oil_12m))]) / 37 | diff(cpi_brent[, c(min(cpi), max(cpi))]) 38 | 39 | plot <- cpi_brent[, ggplot(.SD, aes(y_m)) + 40 | geom_line(aes(y_m, brent_crude_oil_12m, color = "brent")) + 41 | geom_line(aes(y_m, cpi * b, color = "cpi")) + 42 | scale_y_continuous(labels = scales::percent, 43 | limits = c(min(brent_crude_oil_12m), max(brent_crude_oil_12m)), 44 | name = "Brent Crude Oil price (yoy)", 45 | sec.axis = sec_axis(~ (. )/b, name = "CPI Spain (yoy)", 46 | labels = scales::percent)) + 47 | scale_color_manual(values = c("cpi" = c4_color_set_1, "brent" = c4_color_set_2)) + 48 | annotate("text", x = as.Date("2022-01-01"), 49 | y = -0.5, 50 | label = paste("ρ:", round(cor(cpi, brent_crude_oil_12m, use = "complete.obs"), 2)), 51 | color = c4_color_text_2, 52 | hjust = 0, 53 | size = rel(10), 54 | family = "roboto_bold") + 55 | labs( 56 | title = "CPI and Brent Crude Oil year-on-year change", 57 | subtitle = "Correlation between Spanish CPI and the Brent Crude Oil Price", 58 | x = "Year", 59 | y = "Value", 60 | color = NULL, 61 | caption = caption_text( 62 | source_text = cfg_day_20$source, 63 | day_type = cfg_day_20$category, 64 | day_hashtag = cfg_day_20$theme, 65 | day = cfg_day_20$day, 66 | color_text_1 = c4_color_text_1, 67 | color_text_2 = c4_color_text_2 68 | ) 69 | ) + 70 | theme_my( 71 | font_regular = "josefin_regular", 72 | font_bold = "josefin_bold", 73 | font_light = "josefin_light", 74 | color_text_1 = c4_color_text_1, 75 | color_text_2 = c4_color_text_2, 76 | color_background = c4_color_background, 77 | title_size = 50 78 | ) + 79 | theme( 80 | legend.position = "bottom", 81 | plot.margin = margin(25, 25, 10, 10, "pt"), 82 | plot.caption = element_textbox_simple( 83 | size = 20, 84 | lineheight = .5, 85 | padding = margin(4, 0, 4, 0, "pt"), 86 | margin = margin(20, 0, 0, 0, "pt"), 87 | ), 88 | axis.text = element_text( 89 | size = rel(2), 90 | family = "josefin_bold", 91 | color = c4_color_text_2, 92 | margin = margin(2, 2, 2, 0, "pt") 93 | ), 94 | axis.title.y = element_text( 95 | size = 32, 96 | family = "josefin_bold", 97 | color = c4_color_text_2, 98 | margin = margin(5, 5, 5, 5, "pt"), 99 | angle = 90 100 | ), 101 | panel.grid.major = element_line( 102 | color = c4_color_text_2, 103 | linetype = "dotted", 104 | size = .3, 105 | ), 106 | axis.title.y.right = element_text( 107 | size = 32, 108 | family = "josefin_bold", 109 | color = c4_color_text_2, 110 | margin = margin(5, 5, 5, 5, "pt"), 111 | angle = -90 112 | ) 113 | ) 114 | ] 115 | 116 | 117 | # Save -------------------------------------------------------------------- 118 | ggsave( 119 | filename = "R/30DayChartChallenge2024/day_20/day_20_correlation.png", 120 | plot = plot, 121 | width = 3106.56, 122 | height = 1920, 123 | units = "px", 124 | dpi = 320 125 | ) 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_27/day_27_GoodBad.R: -------------------------------------------------------------------------------- 1 | # 30DayChartChallenge2024 / day_27_GoodBad 2 | 3 | # Libraries --------------------------------------------------------------- 4 | library(data.table) 5 | library(tidyverse) 6 | library(ggforce) 7 | library(ggtext) 8 | library(ggrepel) 9 | library(emojifont) 10 | library(sysfonts) 11 | library(showtext) 12 | library(ggplot2) 13 | library(tidyverse) 14 | library(mlmhelpr) 15 | 16 | 17 | # Source ------------------------------------------------------------------ 18 | source("R/30DayChartChallenge2024/theme/styles.R") 19 | source("R/30DayChartChallenge2024/theme/theme.R") 20 | 21 | 22 | # Config ------------------------------------------------------------------ 23 | cfg <- 24 | yaml::read_yaml("R/30DayChartChallenge2024/cfg/plots.yml")[["default"]] 25 | cfg_day_27 <- cfg$day_27 26 | 27 | 28 | # Data -------------------------------------------------------------------- 29 | dt <- 30 | fread("R/30DayChartChallenge2024/day_27/forecast.csv", dec = ",") 31 | dt <- 32 | melt(dt, 33 | id.vars = "previsiones", 34 | variable.name = "year", 35 | value.name = "forecast") 36 | dt[, year := fifelse(year == "pib_2025", "GDP 2025 forecast", "GDP 2024 forecast")] 37 | dt[, forecast := forecast / 100] 38 | dt[, x_jit := jitter(as.numeric(as.factor(year)), factor = .5)] 39 | 40 | 41 | # Get min forecast of each year 42 | min_forecast <- 43 | dt[, .(x_jit = x_jit[forecast == min(forecast)], forecast = min(forecast)), year] 44 | max_forecast <- 45 | dt[, .(x_jit = x_jit[forecast == max(forecast)], forecast = max(forecast)), year] 46 | max_forecast <- max_forecast[, first(.SD), year] 47 | 48 | plot <- dt[, ggplot(.SD, aes(year, forecast)) + 49 | geom_boxplot( 50 | width = .5, 51 | outliers = FALSE, 52 | staplewidth = 0.5, 53 | fill = NA, 54 | color = "#1f2937" 55 | ) + 56 | 57 | geom_point(aes(x_jit, forecast), color = "#4b5563") + 58 | geom_text_repel( 59 | data = min_forecast, 60 | aes(x_jit, forecast, label = paste0( 61 | "Worst: ", scales::percent(forecast, accuracy = .01) 62 | )), 63 | family = "inter_bold", 64 | size = rel(12), 65 | direction = "y", 66 | color = "#030712", 67 | segment.size = 0.5, 68 | nudge_x = 0.5, 69 | nudge_y = c(0.001, 0.0015), 70 | segment.curvature = 0.2, 71 | segment.color = "#1f2937" 72 | ) + 73 | geom_text_repel( 74 | data = max_forecast, 75 | aes(x_jit, forecast, label = paste0( 76 | "Best: ", scales::percent(forecast, accuracy = .01) 77 | )), 78 | family = "inter_bold", 79 | size = rel(12), 80 | direction = "y", 81 | color = "#030712", 82 | segment.size = 0.5, 83 | nudge_x = 0.5, 84 | nudge_y = c(0.0015,-0.001), 85 | segment.curvature = 0.2, 86 | segment.color = "#1f2937" 87 | ) + 88 | 89 | scale_y_continuous(labels = scales::percent) + 90 | labs( 91 | title = "GDP Forecast 2024 and 2025", 92 | subtitle = "for Spanish economy", 93 | x = NULL, 94 | y = NULL, 95 | caption = caption_text( 96 | source = cfg_day_27$source, 97 | day_type = cfg_day_27$category, 98 | day_hashtag = cfg_day_27$theme, 99 | day = cfg_day_27$day, 100 | color_text_1 = "#030712", 101 | color_text_2 = "#1f2937" 102 | ) 103 | ) + 104 | theme_my( 105 | font_regular = "inter_regular", 106 | font_bold = "inter_bold", 107 | font_light = "inter_light", 108 | color_text_1 = "#030712", 109 | color_text_2 = "#1f2937", 110 | color_background = "#d1d5db", 111 | title_size = 48 112 | ) + 113 | theme( 114 | legend.position = "bottom", 115 | axis.text = element_text( 116 | family = "roboto_regular", 117 | size = 26, 118 | hjust = .5 119 | ), 120 | plot.margin = margin(25, 45, 25, 25, "pt"), 121 | plot.title.position = "plot", 122 | plot.caption.position = "plot", 123 | plot.caption = element_textbox_simple( 124 | size = 26, 125 | lineheight = .5, 126 | padding = margin(0, 0, 0, 0, "pt"), 127 | margin = margin(25, 0, 0, 0, "pt"), 128 | ) 129 | )] 130 | 131 | 132 | 133 | # Save -------------------------------------------------------------------- 134 | ggsave( 135 | "R/30DayChartChallenge2024/day_27/day_27_GoodBad.png", 136 | plot, 137 | width = 1920, 138 | height = 1920, 139 | units = "px", 140 | dpi = 320 141 | ) 142 | 143 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_4_timeseries/day_22_stars/day_22.R: -------------------------------------------------------------------------------- 1 | # --- Day 22: Stars (Confirmed Exoplanet Discoveries Over Time) --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: NASA Exoplanet Archive) 4 | # Número acumulado de exoplanetas confirmados descubiertos por año. 5 | 6 | # --- 1. Cargar Librerías --- 7 | library(ggplot2) 8 | library(data.table) 9 | library(yaml) 10 | library(showtext) 11 | library(ggtext) 12 | library(scales) 13 | library(lubridate) 14 | # --- 2. Cargar Configuración, Temas y Utilidades --- 15 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 16 | utils_file <- "R/30DayChartChallenge2025/utils.R" 17 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 18 | font_path_fa <- "fonts/fa-brands-400.ttf" 19 | output_path <- "R/30DayChartChallenge2025/plots/" 20 | 21 | # Verificar existencia de archivos y cargar 22 | source(themes_file) 23 | source(utils_file) 24 | config <- read_yaml(config_file) 25 | 26 | # --- 3. Configurar Fuentes --- 27 | setup_fonts(fa_brands_path = font_path_fa) # Carga "Lato" 28 | 29 | # --- 4. Cargar y Preparar Datos de Exoplanetas --- 30 | 31 | data_file <- "R/30DayChartChallenge2025/data/nasa_exoplanets_confirmed.csv" 32 | 33 | if (!file.exists(data_file)) { 34 | stop("Archivo CSV de exoplanetas no encontrado en: ", data_file, 35 | "\nDescárgalo desde https://exoplanetarchive.ipac.caltech.edu/ (Confirmed Planets Table).") 36 | } 37 | 38 | message("Cargando datos de exoplanetas desde: ", data_file) 39 | exoplanet_dt <- fread(data_file, skip = 99, header = TRUE) 40 | 41 | message("Datos cargados. ", nrow(exoplanet_dt), " planetas confirmados iniciales.") 42 | print(head(exoplanet_dt)) 43 | print(names(exoplanet_dt)) # <- ¡Verifica el nombre exacto de la columna del año! 44 | 45 | # --- Procesamiento --- 46 | # Asumiendo que la columna se llama 'disc_year' 47 | col_year <- "disc_year" 48 | if (!col_year %in% names(exoplanet_dt)) { 49 | # Intenta con otros nombres comunes si falla 50 | alt_col_year <- names(exoplanet_dt)[grep("discoveryyear|disc_year", names(exoplanet_dt), ignore.case = TRUE)][1] 51 | if(!is.na(alt_col_year)) { 52 | warning("Columna '", col_year, "' no encontrada, usando '", alt_col_year, "' en su lugar.") 53 | col_year <- alt_col_year 54 | } else { 55 | stop("No se encontró una columna con el año de descubrimiento. Revisa el CSV.") 56 | } 57 | } 58 | 59 | 60 | # Asegurar que el año es numérico y válido 61 | exoplanet_dt[, Year := as.numeric(get(col_year))] 62 | exoplanet_clean_dt <- exoplanet_dt[!is.na(Year) & Year > 0] # Filtrar años inválidos 63 | 64 | # Contar descubrimientos por año 65 | discoveries_per_year <- exoplanet_clean_dt[, .N, by = .(Year)][order(Year)] 66 | 67 | # Calcular el acumulado 68 | discoveries_per_year[, Cumulative_Discoveries := cumsum(N)] 69 | 70 | message("Datos agregados por año. Rango: ", min(discoveries_per_year$Year), "-", max(discoveries_per_year$Year)) 71 | print(tail(discoveries_per_year)) 72 | 73 | # --- 5. Crear Gráfico de Líneas (Acumulado Exoplanetas) --- 74 | 75 | # Definir textos 76 | source_text_day22 <- "Fuente: NASA Exoplanet Archive (exoplanetarchive.ipac.caltech.edu)" 77 | plot_title <- "La Explosión en el Descubrimiento de Exoplanetas" 78 | current_year <- year(Sys.Date()) 79 | plot_subtitle <- paste0("Número acumulado de exoplanetas confirmados descubiertos por año.\n", 80 | "Nota: El dato de ", current_year, " incluye descubrimientos hasta la fecha actual (", 81 | format(Sys.Date(), "%b %Y"), ").") 82 | 83 | 84 | # Generar caption 85 | caption_day22 <- generate_caption( 86 | day = 22, 87 | source_text = source_text_day22, 88 | config = config, 89 | color_text_source = "#5c5c5c", 90 | color_text_author = "#757de8" 91 | 92 | ) 93 | 94 | # Colores y tema 95 | bg_col <- "#F2F2F2" 96 | # Usar un color de la paleta social (ej. el primario índigo o el acento rosa) 97 | line_color <- challenge_palettes$week4_social['pink'] 98 | 99 | # Crear el gráfico de línea acumulada 100 | gg_day22 <- ggplot(discoveries_per_year, aes(x = Year, y = Cumulative_Discoveries)) + 101 | geom_line(color = line_color, linewidth = 1.3) + 102 | geom_point(color = line_color, size = 1.5, shape = 21, fill = bg_col, stroke = 0.5) + # Puntos opcionales 103 | 104 | # Formato de ejes 105 | scale_y_continuous(labels = scales::label_comma(), expand = expansion(mult=c(0, 0.05))) + # Números grandes con comas 106 | scale_x_continuous() + # Ajusta breaks si es necesario 107 | 108 | # Aplicar tema 109 | theme_week4_social(base_family = "Lato", base_size = 10) + 110 | 111 | # Etiquetas y caption 112 | labs( 113 | title = plot_title, 114 | subtitle = plot_subtitle, 115 | x = "Año de Descubrimiento", 116 | y = "Número Acumulado de Exoplanetas Confirmados", 117 | caption = caption_day22 118 | ) + 119 | theme(legend.position = "none") 120 | 121 | 122 | # --- 6. Guardar Gráfico --- 123 | output_file <- file.path(output_path, "day_22_stars_exoplanets.png") 124 | ggsave( 125 | filename = output_file, 126 | plot = gg_day22, 127 | width = 1200, height = 1200, units = "px", dpi = 150, bg = bg_col # Apaisado 128 | ) 129 | 130 | message("Gráfico del Día 22 (Stars Exoplanets) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 131 | 132 | # --- Fin day_22_stars_exoplanets.R --- -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_1_comparisons/day_1_fractions/day_1.R: -------------------------------------------------------------------------------- 1 | # --- Day 1: Fractions (Régimen Tenencia Vivienda por Edad) --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: INE) 4 | 5 | # --- 1. Cargar Librerías --- 6 | library(ggplot2) 7 | library(dplyr) 8 | library(data.table) # Usaremos fread por eficiencia y manejo de decimales/NA 9 | library(yaml) 10 | library(showtext) 11 | library(ggtext) 12 | library(scales) 13 | 14 | # --- 2. Cargar Configuración, Temas y Utilidades --- 15 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 16 | utils_file <- "R/30DayChartChallenge2025/utils.R" 17 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 18 | font_path_fa <- "fonts/fa-brands-400.ttf" 19 | output_path <- "R/30DayChartChallenge2025/plots/" 20 | data_file <- "R/30DayChartChallenge2025/data/day_1.csv" 21 | 22 | # Verificar archivos 23 | if (!file.exists(themes_file)) stop("Archivo de temas no encontrado.") 24 | if (!file.exists(utils_file)) stop("Archivo de utilidades no encontrado.") 25 | if (!file.exists(config_file)) stop("Archivo de configuración no encontrado.") 26 | if (!file.exists(data_file)) stop("Archivo de datos day_1.csv no encontrado en data/.") 27 | 28 | source(themes_file) 29 | source(utils_file) 30 | config <- read_yaml(config_file) 31 | 32 | # --- 3. Configurar Fuentes --- 33 | setup_fonts(fa_brands_path = font_path_fa) # Verifica ruta a fa-brands! 34 | 35 | # --- 4. Cargar y Preparar Datos --- 36 | 37 | # Leer el CSV descargado del INE 38 | dt <- fread(data_file, sep = ";", dec = ",", na.strings = c('""', ".."), encoding = "Latin-1") 39 | 40 | # Limpiar nombres de columnas 41 | original_names <- names(dt) 42 | new_names <- c("Sexo", "Edad", "Tenencia", "Periodo", "Total") 43 | setnames(dt, old = original_names, new = new_names) 44 | 45 | # Filtrar año 2024 y regímenes relevantes 46 | dt_2024 <- dt[Periodo == 2024 & Tenencia %in% c("Propiedad", "Propiedad con hipoteca", "Propiedad sin hipoteca")] 47 | 48 | # Seleccionar columnas necesarias y pivotar para tener el % por tipo de tenencia 49 | dt_prop <- dt_2024[Tenencia %in% c("Propiedad con hipoteca", "Propiedad sin hipoteca"), 50 | .(Edad, Tenencia, Total)] 51 | 52 | # Calcular el porcentaje de "Alquiler u otros" (100 - % Propiedad Total) 53 | dt_prop_total <- dt_2024[Tenencia == "Propiedad", .(Edad, Total_Propiedad = Total)] 54 | dt_calc <- merge(dt_prop, dt_prop_total, by = "Edad", all = TRUE) 55 | dt_calc[, Pct_Alquiler_Otros := 100 - Total_Propiedad] 56 | 57 | # Combinar y dar formato final para ggplot 58 | dt_plot <- rbindlist(list( 59 | dt_calc[!is.na(Tenencia), .(Edad, Tenencia, Total)], 60 | unique(dt_calc[, .(Edad, Tenencia = "Alquiler u otros", Total = Pct_Alquiler_Otros)]) 61 | )) 62 | 63 | # Renombrar grupos de edad (opcional) y ordenar factores 64 | dt_plot[, Generacion := factor(Edad, 65 | levels = c("De 16 a 29 años", "De 30 a 44 años", "De 45 a 64 años", "65 y más años"), 66 | labels = c("16-29 años\n(Gen Z / Mill.)", "30-44 años\n(Mill. / Gen X)", "45-64 años\n(Gen X / Boomer)", "65+ años\n(Boomer / Sil.)"))] 67 | 68 | # Ordenar factor de Tenencia para el gráfico apilado 69 | dt_plot[, Tenencia := factor(Tenencia, levels = c("Alquiler u otros", "Propiedad con hipoteca", "Propiedad sin hipoteca"))] 70 | 71 | # Convertir Total a numérico (si fread no lo hizo ya por el dec=",") 72 | dt_plot[, Total := as.numeric(Total)] 73 | 74 | # --- 5. Crear Gráfico --- 75 | 76 | # Definir textos 77 | source_text_day1 <- "INE: Indicadores de Calidad de Vida (2024)" 78 | plot_title <- "Régimen de Tenencia de Vivienda\npor Edad en España (2024)" 79 | plot_subtitle <- "Fracción de la población en cada grupo de edad\nsegún el tipo de tenencia de su vivienda principal" 80 | 81 | # Generar caption 82 | caption_day1 <- generate_caption( 83 | day = 1, 84 | source_text = source_text_day1, 85 | config = config 86 | ) 87 | 88 | # Crear el objeto ggplot 89 | gg_day1 <- ggplot(dt_plot, aes(x = Generacion, y = Total, fill = Tenencia)) + 90 | geom_col(position = "fill") + 91 | # Aplicar paleta personalizada de la semana 1 92 | scale_fill_challenge(palette = "week1", discrete = TRUE, # Usaremos los 3 primeros colores 93 | reverse = TRUE, # Invertir orden de colores 94 | guide = guide_legend(reverse = FALSE)) + 95 | # Formatear eje Y como porcentaje 96 | scale_y_continuous(labels = scales::percent_format(), expand = c(0, 0)) + 97 | # Aplicar tema personalizado (ajusta base_size si es necesario) 98 | theme_week1(base_size = 14) + 99 | # Añadir etiquetas y caption 100 | labs( 101 | title = plot_title, 102 | subtitle = plot_subtitle, 103 | x = "Grupo de Edad (Generación Aproximada)", 104 | y = "Porcentaje de Población", 105 | fill = NULL, # QUitar el título de leyenda 106 | caption = caption_day1 107 | ) + 108 | theme(axis.text.x = element_text(angle = 0, hjust = 0.5, size = rel(0.9))) # Ajustar texto eje x 109 | 110 | # --- 6. Guardar Gráfico --- 111 | output_file <- file.path(output_path, "day_1_fractions_tenencia.png") 112 | ggsave( 113 | filename = output_file, 114 | plot = gg_day1, 115 | width = 1200, height = 1200, units = "px", dpi = 300, bg = "white" 116 | ) 117 | 118 | message("Gráfico del Día 1 (Tenencia Vivienda) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 119 | 120 | # --- Fin day_1.R --- -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_3_relationships/day_15_complicated/day_15.R: -------------------------------------------------------------------------------- 1 | # --- Day 15: Complicated (Palmer Penguins Traits Matrix) --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: palmerpenguins R package) 4 | # Matriz de scatter plots (ggpairs) mostrando relaciones complejas 5 | # entre rasgos de pingüinos, coloreado por especie. 6 | 7 | # --- 1. Cargar Librerías --- 8 | library(ggplot2) 9 | library(data.table) 10 | library(yaml) 11 | library(showtext) 12 | library(ggtext) 13 | library(scales) 14 | library(grid) 15 | library(palmerpenguins) 16 | library(GGally) 17 | 18 | # --- 2. Cargar Configuración, Temas y Utilidades --- 19 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 20 | utils_file <- "R/30DayChartChallenge2025/utils.R" 21 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 22 | font_path_fa <- "fonts/fa-brands-400.ttf" 23 | output_path <- "R/30DayChartChallenge2025/plots/" 24 | 25 | # Verificar existencia de archivos y cargar 26 | if (!file.exists(themes_file)) stop("Archivo de temas no encontrado: ", themes_file) 27 | if (!file.exists(utils_file)) stop("Archivo de utilidades no encontrado: ", utils_file) 28 | if (!file.exists(config_file)) stop("Archivo de configuración no encontrado: ", config_file) 29 | source(themes_file) 30 | source(utils_file) 31 | config <- read_yaml(config_file) 32 | 33 | # --- 3. Configurar Fuentes --- 34 | setup_fonts(fa_brands_path = font_path_fa) # Carga "Cabin" 35 | 36 | # --- 4. Cargar y Preparar Datos --- 37 | 38 | message("Cargando datos del paquete palmerpenguins...") 39 | penguins_dt <- as.data.table(penguins) 40 | 41 | # Seleccionar columnas relevantes y eliminar filas con NAs en ellas 42 | cols_for_plot <- c("species", "bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g") 43 | penguins_clean_dt <- na.omit(penguins_dt, cols = cols_for_plot) 44 | 45 | # No necesitamos logaritmos aquí, las escalas son razonables 46 | message("Número de pingüinos después de limpiar NAs: ", nrow(penguins_clean_dt)) 47 | message("Especies: ", paste(levels(penguins_clean_dt$species), collapse=", ")) 48 | 49 | message("Renombrando columnas a Español...") 50 | setnames(penguins_clean_dt, 51 | old = c("bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g", "species"), 52 | new = c("Longitud Pico (mm)", "Profundidad Pico (mm)", "Longitud Aleta (mm)", "Masa Corporal (g)", "Especie") 53 | ) 54 | print(summary(penguins_clean_dt)) 55 | 56 | 57 | # --- 5. Crear Matriz de Scatter Plots (ggpairs) --- 58 | 59 | # Definir textos 60 | source_text_day15 <- "Source: palmerpenguins R package (Gorman, Williams & Fraser, 2014. PLoS ONE)" 61 | plot_title <- "Relaciones Complejas: Pingüinos de Palmer" 62 | plot_subtitle <- "Matriz de relaciones entre medidas corporales por especie.\nInf: Scatterplots, Sup: Correlación (Pearson), Diag: Densidad." 63 | 64 | # Generar caption 65 | caption_day15 <- generate_caption( 66 | day = 15, 67 | source_text = source_text_day15, 68 | config = config, 69 | color_text_source = "#5D4037", 70 | color_text_author = "#6B8E23" 71 | ) 72 | 73 | 74 | # Columnas numéricas para incluir en la matriz 75 | ggpairs_cols <- c("Longitud Pico (mm)", "Longitud Aleta (mm)", "Masa Corporal (g)") 76 | 77 | # Colores 78 | bg_col <- "#FAF0E6" 79 | num_species <- length(levels(penguins_clean_dt$Especie)) 80 | plot_colors <- challenge_pal("week3_animals")(num_species) 81 | names(plot_colors) <- levels(penguins_clean_dt$species) 82 | 83 | message("Generando gráfico ggpairs...") 84 | # Crear el objeto ggpairs 85 | gg_day15_matrix <- ggpairs( 86 | data = penguins_clean_dt, 87 | columns = ggpairs_cols, 88 | mapping = aes(color = Especie, alpha = 0.7), # Color por especie 89 | upper = list(continuous = wrap("cor", size = 4.5, stars = FALSE)), # Correlación 90 | lower = list(continuous = wrap("points", size = 2.5)), # Scatterplot 91 | diag = list(continuous = wrap("densityDiag", alpha = 0.6)), # Densidad 92 | title = plot_title, # Título principal integrado 93 | progress = FALSE # Ocultar barra de progreso de ggpairs 94 | ) 95 | 96 | # Aplicar tema y escalas DESPUÉS de crear el objeto ggpairs 97 | gg_day15 <- gg_day15_matrix + 98 | theme_week3_animals(base_size = 9, base_family = "Cabin") + # Tamaño base reducido para la matriz 99 | scale_color_manual(values = plot_colors, name = "Especie") + 100 | scale_fill_manual(values = plot_colors, name = "Especie") + # Para las densidades 101 | labs(subtitle = plot_subtitle, caption = caption_day15) + # Añadir subtítulo y caption 102 | # Ajustes específicos para ggpairs si son necesarios 103 | theme( 104 | strip.background = element_rect(fill=alpha(bg_col, 0.8), color=NA), # Fondo etiquetas panel semi-transp 105 | strip.text = element_text(face="bold", size=rel(1.5), color="#5D4037"), # Texto etiquetas panel 106 | aspect.ratio = NULL 107 | ) 108 | 109 | message("Gráfico ggpairs generado.") 110 | 111 | # --- 6. Guardar Gráfico --- 112 | output_file <- file.path(output_path, "day_15_complicated_penguins.png") 113 | # Darle un poco más de tamaño para que la matriz se vea bien 114 | ggsave( 115 | filename = output_file, 116 | plot = gg_day15, 117 | width = 1200, height = 1200, units = "px", dpi = 150, bg = bg_col 118 | ) 119 | 120 | message("Gráfico del Día 15 (Complicated Penguins ggpairs) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 121 | 122 | # --- Fin day_15_complicated_penguins.R --- -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_1_comparisons/day_5_ranking/day_5.R: -------------------------------------------------------------------------------- 1 | # --- Day 5: Ranking (Lollipop Chart - Precio Vivienda Distritos Madrid) --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: Idealista) 4 | 5 | # --- 1. Cargar Librerías --- 6 | library(data.table) 7 | library(ggplot2) 8 | library(dplyr) 9 | library(yaml) 10 | library(showtext) 11 | library(ggtext) 12 | library(scales) # Para formatear etiquetas 13 | 14 | # --- 2. Cargar Configuración, Temas y Utilidades --- 15 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 16 | utils_file <- "R/30DayChartChallenge2025/utils.R" 17 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 18 | font_path_fa <- "fonts/fa-brands-400.ttf" 19 | output_path <- "R/30DayChartChallenge2025/plots/" 20 | 21 | if (!file.exists(utils_file)) stop("Archivo de temas no encontrado.") 22 | if (!file.exists(utils_file)) stop("Archivo de utilidades no encontrado.") 23 | if (!file.exists(config_file)) stop("Archivo de configuración no encontrado.") 24 | 25 | source(themes_file) 26 | source(utils_file) 27 | config <- read_yaml(config_file) 28 | 29 | # --- 3. Configurar Fuentes --- 30 | setup_fonts(fa_brands_path = font_path_fa) 31 | 32 | # --- 4. Preparar Datos --- 33 | distritos <- c("Salamanca", "Chamberí", "Retiro", "Chamartín", "Centro", "Moncloa", 34 | "Arganzuela", "Tetuán", "Hortaleza", "Fuencarral", "Ciudad Lineal", 35 | "Barajas", "Moratalaz", "San Blas", "Latina", "Vicálvaro", 36 | "Carabanchel", "Villa de Vallecas", "Usera", "Puente de Vallecas", "Villaverde") 37 | precios <- c(9374, 7677, 7014, 6988, 6816, 5500, 5341, 5162, 4745, 4572, 4219, 38 | 4070, 3607, 3362, 3275, 3171, 3039, 3032, 2880, 2648, 2294) # Idealista Mar 2025 39 | fuente_datos_real <- "Idealista (Marzo 2025)" 40 | 41 | # Crear el data.table inicial 42 | dt_distritos_ranking <- data.table( 43 | Distrito = factor(distritos), 44 | Precio_m2 = precios 45 | ) 46 | 47 | # Precio medio Madrid 48 | precio_medio_madrid <- 5321 # Idealista Mar 2025 49 | 50 | # Calcular diferencia y tipo usando sintaxis data.table (:= para añadir columnas) 51 | dt_distritos_ranking[, Diff_vs_Avg := Precio_m2 - precio_medio_madrid] 52 | dt_distritos_ranking[, Tipo := fifelse(Diff_vs_Avg >= 0, "Superior a la Media", "Inferior a la Media")] 53 | dt_distritos_ranking[, Tipo := factor(Tipo, levels = c("Superior a la Media", "Inferior a la Media"))] 54 | 55 | # --- 5. Crear Gráfico --- 56 | 57 | # Definir textos 58 | plot_title <- "Ranking de Distritos de Madrid" 59 | plot_subtitle <- paste0("Diferencia del precio medio (€/m²) de cada distrito\nrespecto a la media de Madrid (Media Madrid = ", 60 | number(precio_medio_madrid, accuracy=1, big.mark=".", decimal.mark=","), " €/m²)") 61 | 62 | # Generar caption 63 | caption_day5 <- generate_caption( 64 | day = 5, 65 | source_text = fuente_datos_real, 66 | config = config 67 | ) 68 | 69 | # Colores para los tipos 70 | colores_tipo <- c("Superior a la Media" = paleta_week1[1], # Azul oscuro 71 | "Inferior a la Media" = paleta_week1[4]) # Rojo oscuro 72 | 73 | # Rango de variación 74 | rango <- dt_distritos_ranking[, round((max(c(max(Diff_vs_Avg), abs(min(Diff_vs_Avg)))) * 1.1) / 500) * 500 ] 75 | 76 | # Crear el gráfico de piruleta divergente horizontal ordenado 77 | gg_day5 <- dt_distritos_ranking[, 78 | ggplot(.SD, aes(x = Diff_vs_Avg, y = reorder(Distrito, Diff_vs_Avg))) + 79 | # Línea vertical en cero (la media) 80 | geom_vline(xintercept = 0, color = paleta_week1[2], linewidth = 1.05) + 81 | # Segmento (palo de la piruleta) desde 0 hasta la diferencia 82 | geom_segment(aes(x = 0, xend = Diff_vs_Avg, 83 | y = reorder(Distrito, Diff_vs_Avg), 84 | yend = reorder(Distrito, Diff_vs_Avg)), 85 | color = fifelse(Tipo == "Superior a la Media", paleta_week1[1], paleta_week1[4]), 86 | linewidth = 1.1) + 87 | # Punto (cabeza de la piruleta), coloreado por Tipo (encima/debajo media) 88 | geom_point(aes(color = Tipo), size = 2.5) + 89 | # Asignar colores manualmente 90 | scale_color_manual(values = colores_tipo, guide = "none") + # Ocultar leyenda de color 91 | # Formatear eje X 92 | scale_x_continuous( 93 | limits = c(-rango, rango), 94 | breaks = seq(-rango, rango, 1500), 95 | expand = c(0.1, 0.1), 96 | labels = label_number(big.mark = ".", decimal.mark = ",", suffix = " €")) + 97 | # Aplicar tema personalizado 98 | theme_week1(base_size = 10) + 99 | # Añadir etiquetas y caption 100 | labs( 101 | title = plot_title, 102 | subtitle = plot_subtitle, 103 | x = "Diferencia vs Precio Medio (€/m²)", 104 | y = NULL, 105 | caption = caption_day5 106 | ) + 107 | # Ajustes adicionales al tema 108 | theme( 109 | panel.grid.major.y = element_blank(), # Sin líneas grid horizontales 110 | panel.grid.minor.x = element_blank(), # Sin grids menores en X 111 | axis.text.y = element_text(size = rel(1)), 112 | plot.margin = margin(15, 30, 10, 15) 113 | )] 114 | 115 | # --- 6. Guardar Gráfico --- 116 | output_file <- file.path(output_path, "day_5_ranking_madrid_diverging_lollipop.png") 117 | ggsave( 118 | filename = output_file, 119 | plot = gg_day5, 120 | width = 1200, height = 1200, units = "px", dpi = 300, bg = "white" 121 | ) 122 | 123 | message("Gráfico del Día 5 (Diverging Lollipop Madrid) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 124 | 125 | # --- Fin day_5.R --- -------------------------------------------------------------------------------- /R/2024/week_03/2024_w03_calendar.R: -------------------------------------------------------------------------------- 1 | # Header ------------------------------------------------------------------ 2 | # 3 | # Author: Michal Kinel 4 | # Copyright (c) Michal Kinel, 2024 5 | # Email: michal.kinel@gmail.com 6 | # 7 | # Date: 2024-01-21 8 | # 9 | # Script Name:2024_w03_calendar 10 | # 11 | # Script Description: Make a calendar with ggplot2 12 | # 13 | # 14 | # Notes: 15 | # 16 | # 17 | 18 | # Set options ------------------------------------------------------------- 19 | cat("Setting options... \n\n", sep = "") 20 | options(scipen = 999) # turns off scientific notation 21 | options(encoding = "UTF-8") # sets string encoding to UTF-8 instead of ANSI 22 | 23 | 24 | # Install packages & load libraries --------------------------------------- 25 | cat("Install packages & load libraries... \n\n", sep = "") 26 | packages <- c("tidyverse", "data.table", "zoo", "extrafont") # list of packages to load 27 | n_packages <- length(packages) # count how many packages are required 28 | 29 | new_pkg <- packages[!(packages %in% installed.packages())] # determine which packages aren't installed 30 | 31 | # Install missing packages 32 | if(length(new_pkg)){ 33 | install.packages(new_pkg) 34 | } 35 | 36 | # Load all requried libraries 37 | for(n in 1:n_packages){ 38 | cat("Loading Library #", n, " of ", n_packages, "... Currently Loading: ", packages[n], "\n", sep = "") 39 | lib_load <- paste("library(\"",packages[n],"\")", sep = "") # create string of text for loading each library 40 | eval(parse(text = lib_load)) # evaluate the string to load the library 41 | } 42 | 43 | 44 | # Data -------------------------------------------------------------------- 45 | cat("Data... \n\n", sep = "") 46 | 47 | # Create data frame 48 | calendar <- data.table( 49 | date = seq.Date(as.Date("2024-01-01"), as.Date("2024-12-31"), by = "day") 50 | ) 51 | 52 | # Add month 53 | calendar[, month := str_to_title(lubridate::month(date, 54 | label = TRUE, 55 | abbr = FALSE))] 56 | calendar[, month := factor(month, levels = unique(month))] 57 | 58 | # Add week 59 | calendar[, week := lubridate::week(date)] 60 | 61 | # Add day 62 | calendar[, day := day(date)] 63 | 64 | # Add weekday 65 | calendar[, weekday := { 66 | weekdays(date, abbreviate = TRUE) %>% 67 | fct_inorder() 68 | }] 69 | 70 | # Sunday as first day of week 71 | calendar[, weekend_holydays := fifelse(wday(date) %in% c(7, 1), "weekend", "workdays")] 72 | 73 | # Holydays Spain 74 | holdays <- 75 | c( 76 | "2024-01-01", 77 | "2024-03-29", 78 | "2024-05-01", 79 | "2024-08-15", 80 | "2024-10-12", 81 | "2024-11-01", 82 | "2024-12-06", 83 | "2024-12-25" 84 | ) %>% as.Date() 85 | 86 | # Add holydays 87 | calendar[, weekend_holydays := fifelse(date %in% holdays, "holydays", weekend_holydays)] 88 | 89 | # Add week of month 90 | calendar[, week_month := frank(week, ties.method = "dense"), by = month] 91 | 92 | 93 | # Style ------------------------------------------------------------------- 94 | # Color palette 95 | background <- "#fffefa" 96 | weekday_color <- "#313743" 97 | weekend_color <- "#67b7b5" 98 | holiday_color <- "#fa334c" 99 | 100 | # Load fonts 101 | loadfonts(device = "win") 102 | 103 | # Fonts 104 | font_base <- "Lato" 105 | font_title <- "Lato Black" 106 | 107 | 108 | # Plot -------------------------------------------------------------------- 109 | cat("Plot... \n\n", sep = "") 110 | 111 | plot <- calendar %>% 112 | ggplot(aes(x = weekday, y = week_month)) + 113 | geom_tile(alpha = 0.8, aes(fill = weekend_holydays)) + 114 | geom_text( 115 | aes(label = day), 116 | family = font_base, 117 | color = fifelse(calendar$weekend_holydays != "weekend", "white", "black"), 118 | size = 3 119 | ) + 120 | facet_wrap( ~ month, scales = "free_x", ncol = 3) + 121 | scale_x_discrete() + 122 | scale_y_reverse(breaks = NULL) + 123 | labs(title = "Calendario 2024", 124 | fill = NULL, 125 | caption = "Festivos de España en rojo\nmichal0091") + 126 | theme_void() + 127 | scale_fill_manual(values = c(holiday_color, weekend_color, weekday_color)) + 128 | # Add theme elements 129 | theme( 130 | plot.margin = margin(1, 0.5, 1, 1, "cm"), 131 | axis.text.x = element_text( 132 | color = weekday_color, 133 | family = font_base, 134 | size = 10, 135 | vjust = 2 136 | ), 137 | # add plot title 138 | plot.title = element_text( 139 | hjust = 0.5, 140 | vjust = 3, 141 | color = weekday_color, 142 | family = font_title, 143 | size = 28 144 | ), 145 | # add plot caption 146 | plot.caption = element_text( 147 | hjust = 1, 148 | color = weekday_color, 149 | family = font_base, 150 | size = 8 151 | ), 152 | # add legend 153 | legend.position = "none", 154 | # add panel spacing 155 | panel.spacing = unit(0.5, "lines"), 156 | # add panel background 157 | panel.background = element_rect(fill = background, color = background), 158 | # add plot background 159 | plot.background = element_rect(fill = background, color = background) 160 | ) 161 | 162 | 163 | # Save plot --------------------------------------------------------------- 164 | cat("Saving plot... \n\n", sep = "") 165 | 166 | ggsave( 167 | filename = "calendar_2024.png", 168 | path = normalizePath("R/2024/week_03/"), 169 | plot = plot, 170 | device = "png", 171 | units = "cm", 172 | width = 21, 173 | height = 15.75 174 | ) 175 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2024/day_28/trend_tourist.csv: -------------------------------------------------------------------------------- 1 | Fecha;Extranjeros y España (excluida Canarias) 2 | 03/2024;2018375 3 | 02/2024;1836746 4 | 01/2024;1739341 5 | 2023;19280684 6 | 12/2023;1905982 7 | 11/2023;1726909 8 | 10/2023;1737311 9 | 09/2023;1470212 10 | 08/2023;1576004 11 | 07/2023;1610288 12 | 06/2023;1395483 13 | 05/2023;1385742 14 | 04/2023;1573367 15 | 03/2023;1707195 16 | 02/2023;1596895 17 | 01/2023;1595296 18 | 2022;17286949 19 | 12/2022;1765971 20 | 11/2022;1585099 21 | 10/2022;1633480 22 | 09/2022;1367100 23 | 08/2022;1544046 24 | 07/2022;1555727 25 | 06/2022;1330794 26 | 05/2022;1263332 27 | 04/2022;1496211 28 | 03/2022;1465502 29 | 02/2022;1257258 30 | 01/2022;1022429 31 | 2021;8296043 32 | 12/2021;1297710 33 | 11/2021;1318285 34 | 10/2021;1343200 35 | 09/2021;968990 36 | 08/2021;1026248 37 | 07/2021;809895 38 | 06/2021;466837 39 | 05/2021;328486 40 | 04/2021;216136 41 | 03/2021;207988 42 | 02/2021;145546 43 | 01/2021;166722 44 | 2020;5693229 45 | 2004;12660634 46 | 01/2004;1045261 47 | 02/2004;1090596 48 | 03/2004;1107029 49 | 04/2004;1041639 50 | 05/2004;844375 51 | 06/2004;847026 52 | 07/2004;1103344 53 | 08/2004;1231906 54 | 09/2004;1013299 55 | 10/2004;1163031 56 | 11/2004;1059114 57 | 12/2004;1114014 58 | 2005;12750771 59 | 01/2005;1078251 60 | 02/2005;1047982 61 | 03/2005;1172431 62 | 04/2005;961002 63 | 05/2005;844561 64 | 06/2005;861976 65 | 07/2005;1139866 66 | 08/2005;1230369 67 | 09/2005;1024833 68 | 10/2005;1190416 69 | 11/2005;1087188 70 | 12/2005;1111896 71 | 2006;13155406 72 | 01/2006;1045095 73 | 02/2006;1031214 74 | 03/2006;1182122 75 | 04/2006;1142390 76 | 05/2006;885815 77 | 06/2006;945703 78 | 07/2006;1196527 79 | 08/2006;1248696 80 | 09/2006;1054592 81 | 10/2006;1179535 82 | 11/2006;1084442 83 | 12/2006;1159275 84 | 2007;13219349 85 | 01/2007;1027616 86 | 02/2007;1060870 87 | 03/2007;1232057 88 | 04/2007;1062158 89 | 05/2007;859800 90 | 06/2007;938926 91 | 07/2007;1187133 92 | 08/2007;1249286 93 | 09/2007;1056387 94 | 10/2007;1185806 95 | 11/2007;1149307 96 | 12/2007;1210003 97 | 2008;13072068 98 | 01/2008;1076417 99 | 02/2008;1155648 100 | 03/2008;1318717 101 | 04/2008;1024491 102 | 05/2008;907577 103 | 06/2008;967121 104 | 07/2008;1155030 105 | 08/2008;1246988 106 | 09/2008;966991 107 | 10/2008;1086215 108 | 11/2008;1090470 109 | 12/2008;1076403 110 | 2009;11468333 111 | 01/2009;980784 112 | 02/2009;954506 113 | 03/2009;1028973 114 | 04/2009;953968 115 | 05/2009;750573 116 | 06/2009;783223 117 | 07/2009;999853 118 | 08/2009;1072655 119 | 09/2009;841073 120 | 10/2009;1010268 121 | 11/2009;1027625 122 | 12/2009;1064832 123 | 2010;12177546 124 | 01/2010;1013938 125 | 02/2010;997684 126 | 03/2010;1117882 127 | 04/2010;840838 128 | 05/2010;826209 129 | 06/2010;887440 130 | 07/2010;1100600 131 | 08/2010;1140848 132 | 09/2010;940526 133 | 10/2010;1142974 134 | 11/2010;1083642 135 | 12/2010;1084965 136 | 2011;13877848 137 | 01/2011;1107701 138 | 02/2011;1162507 139 | 03/2011;1287837 140 | 04/2011;1231543 141 | 05/2011;897630 142 | 06/2011;973818 143 | 07/2011;1230204 144 | 08/2011;1238784 145 | 09/2011;1069499 146 | 10/2011;1267519 147 | 11/2011;1173475 148 | 12/2011;1237331 149 | 2012;13230571 150 | 01/2012;1143053 151 | 02/2012;1134348 152 | 03/2012;1235969 153 | 04/2012;1044372 154 | 05/2012;881032 155 | 06/2012;965951 156 | 07/2012;1174376 157 | 08/2012;1158847 158 | 09/2012;1027775 159 | 10/2012;1179455 160 | 11/2012;1101961 161 | 12/2012;1183432 162 | 2013;13526439 163 | 01/2013;1075738 164 | 02/2013;1075968 165 | 03/2013;1261886 166 | 04/2013;998282 167 | 05/2013;913159 168 | 06/2013;967756 169 | 07/2013;1157622 170 | 08/2013;1184428 171 | 09/2013;1042595 172 | 10/2013;1245588 173 | 11/2013;1286597 174 | 12/2013;1316820 175 | 2014;14478580 176 | 01/2014;1195148 177 | 02/2014;1172309 178 | 03/2014;1327581 179 | 04/2014;1209557 180 | 05/2014;989555 181 | 06/2014;1045130 182 | 07/2014;1252328 183 | 08/2014;1301767 184 | 09/2014;1105163 185 | 10/2014;1309887 186 | 11/2014;1258780 187 | 12/2014;1311375 188 | 2015;14933111 189 | 01/2015;1232987 190 | 02/2015;1204708 191 | 03/2015;1332001 192 | 04/2015;1150904 193 | 05/2015;1045917 194 | 06/2015;1060467 195 | 07/2015;1280137 196 | 08/2015;1347280 197 | 09/2015;1141670 198 | 10/2015;1394716 199 | 11/2015;1338754 200 | 12/2015;1403570 201 | 2016;17014118 202 | 01/2016;1361098 203 | 02/2016;1375027 204 | 03/2016;1510160 205 | 04/2016;1312287 206 | 05/2016;1207896 207 | 06/2016;1256106 208 | 07/2016;1516606 209 | 08/2016;1514672 210 | 09/2016;1321137 211 | 10/2016;1587147 212 | 11/2016;1452652 213 | 12/2016;1599330 214 | 2017;18180995 215 | 01/2017;1452746 216 | 02/2017;1438342 217 | 03/2017;1568698 218 | 04/2017;1572978 219 | 05/2017;1296939 220 | 06/2017;1378762 221 | 07/2017;1602888 222 | 08/2017;1574087 223 | 09/2017;1446259 224 | 10/2017;1655159 225 | 11/2017;1540900 226 | 12/2017;1653237 227 | 2018;18059717 228 | 01/2018;1492573 229 | 02/2018;1470660 230 | 03/2018;1676389 231 | 04/2018;1409198 232 | 05/2018;1293551 233 | 06/2018;1354855 234 | 07/2018;1560690 235 | 08/2018;1544335 236 | 09/2018;1434169 237 | 10/2018;1638278 238 | 11/2018;1522264 239 | 12/2018;1662755 240 | 2019;17737398 241 | 01/2019;1491569 242 | 02/2019;1476107 243 | 03/2019;1674785 244 | 04/2019;1471735 245 | 05/2019;1258250 246 | 06/2019;1357063 247 | 07/2019;1495809 248 | 08/2019;1498147 249 | 09/2019;1356218 250 | 10/2019;1519793 251 | 11/2019;1516957 252 | 12/2019;1620965 253 | 01/2020;1433358 254 | 02/2020;1460630 255 | 03/2020;598185 256 | 04/2020;4327 257 | 05/2020;9394 258 | 06/2020;35163 259 | 07/2020;428525 260 | 08/2020;530971 261 | 09/2020;286234 262 | 10/2020;300365 263 | 11/2020;251888 264 | 12/2020;354189 265 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/utils.R: -------------------------------------------------------------------------------- 1 | # --- utils.R --- 2 | 3 | library(glue) 4 | library(ggtext) 5 | library(sysfonts) 6 | library(showtext) 7 | library(ggplot2) 8 | 9 | font_add(family = "fa-brands", regular = "fonts/fa-brands-400.ttf") 10 | font_add(family = "fa-solid", regular = "fonts/fa-solid-900.ttf") 11 | 12 | showtext_auto() 13 | 14 | #' Genera el texto del pie de foto (caption) para los gráficos del #30DayChartChallenge 15 | #' 16 | #' Utiliza la información del archivo de configuración YAML y los detalles específicos del día. 17 | #' Requiere que ggtext esté instalado y una fuente de iconos (ej. Font Awesome) configurada con showtext. 18 | #' 19 | #' @param day El número del día (1-30). 20 | #' @param source_text El texto que describe la fuente de los datos para ese día. 21 | #' @param config El objeto de configuración cargado desde el archivo YAML. 22 | #' @param color_text_author Color para el autor y hashtags principales (predeterminado: azul). 23 | #' @param color_text_source Color para la fuente y nombres de usuario (predeterminado: negro/gris). 24 | #' @param icon_font_family Nombre de la familia de la fuente de iconos (predeterminado: 'Font Awesome 6 Brands'). 25 | #' 26 | #' @return Una cadena de texto formateada en HTML/Markdown lista para usar con ggtext::element_markdown(). 27 | #' 28 | generate_caption <- function(day, 29 | source_text, 30 | config, 31 | color_text_author = "#286e8c", # Azul de tu paleta semana 1 32 | color_text_source = "#373737", # Gris oscuro de tu paleta semana 1 33 | icon_font_family = "fa-brands") { # Asegúrate de que este nombre coincide con cómo lo carga showtext 34 | 35 | # Extraer información por defecto del config 36 | defaults <- config$defaults 37 | author <- defaults$author_name 38 | social_media <- defaults$social_media 39 | main_hashtag <- defaults$main_hashtag 40 | 41 | # Extraer información del día específico del config 42 | daily_info <- config$daily_prompts[[day]] 43 | if (is.null(daily_info)) { 44 | stop(paste("No se encontró información para el día", day, "en el archivo de configuración.")) 45 | } 46 | theme_name <- daily_info$theme 47 | day_hashtag <- paste0("#Day", day) # Hashtag #DayN 48 | 49 | # Construir la parte de redes sociales dinámicamente 50 | social_html_parts <- character() 51 | build_social_part <- function(icon_code_html, username) { 52 | glue(" {icon_code_html}; {username} ") 53 | } 54 | 55 | build_mastodon_part <- function(icon_code_html, username, server) { 56 | glue("{icon_code_html}; {username}@{server} ") 57 | } 58 | 59 | if (!is.null(social_media$github_username) && !is.null(social_media$github_icon)) { 60 | social_html_parts <- c(social_html_parts, build_social_part(social_media$github_icon, social_media$github_username)) 61 | } 62 | 63 | if (!is.null(social_media$linkedin_username) && !is.null(social_media$linkedin_icon)) { 64 | social_html_parts <- c(social_html_parts, build_social_part(social_media$linkedin_icon, social_media$linkedin_username)) 65 | } 66 | 67 | if (!is.null(social_media$mastodon_username) && !is.null(social_media$mastodon_icon) && !is.null(social_media$mastodon_server)) { 68 | social_html_parts <- c(social_html_parts, build_mastodon_part(social_media$mastodon_icon, social_media$mastodon_username, social_media$mastodon_server)) 69 | } 70 | 71 | 72 | # Separador entre redes sociales: varios espacios sin ruptura 73 | social_string <- paste(social_html_parts, collapse = "   ") 74 | 75 | 76 | # Construir el caption final usando glue 77 | caption <- glue::glue( 78 | "Viz: {author} | ", 79 | " Source: {source_text}
", 80 | "{social_string}
", 81 | "{main_hashtag} | {day_hashtag}: {theme_name}" 82 | ) 83 | 84 | return(caption) 85 | } 86 | 87 | # --- Función para Configurar Fuentes --- 88 | 89 | #' Carga las fuentes necesarias para el #30DayChartChallenge usando showtext 90 | #' 91 | #' Carga Roboto, Baumans desde Google Fonts y Font Awesome Brands desde un archivo local. 92 | #' Activa showtext para su uso en gráficos. 93 | #' 94 | #' @param fa_brands_path 95 | #' 96 | setup_fonts <- function(fa_brands_path = "fonts/fa-brands-400.ttf") { 97 | 98 | # Cargar fuentes de Google Fonts 99 | font_add_google("Roboto", "Roboto") 100 | font_add_google("Roboto", "Roboto bold", regular.wt = 700) 101 | font_add_google("Baumans", "Baumans") 102 | font_add_google("Roboto Mono", "Roboto Mono") 103 | font_add_google("Exo 2", "Exo 2") 104 | font_add_google("Cabin", "Cabin") 105 | font_add_google("Lato", "Lato") # El País? 106 | font_add_google("Gudea", "Gudea") # NatGeo 107 | 108 | # Cargar fuente de iconos local (Font Awesome Brands) 109 | if (file.exists(fa_brands_path)) { 110 | font_add(family = "fa-brands", regular = fa_brands_path) 111 | } else { 112 | warning(paste("Archivo de fuente Font Awesome Brands no encontrado en:", 113 | normalizePath(fa_brands_path, mustWork = FALSE), 114 | "\nLos iconos no se mostrarán correctamente.")) 115 | } 116 | 117 | # Activar showtext para que ggplot use estas fuentes 118 | showtext_auto() 119 | } 120 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_4_timeseries/day_19_smooth/day_19.R: -------------------------------------------------------------------------------- 1 | # --- Day 19: Smooth (Polish Presidential Polls Trends) --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: User CSV - Polish Election Polls 2025) 4 | # Evolución suavizada de la intención de voto para candidatos presidenciales 5 | # en Polonia, incluyendo orientación política. 6 | 7 | # --- 1. Cargar Librerías --- 8 | library(ggplot2) 9 | library(data.table) 10 | library(yaml) 11 | library(showtext) 12 | library(ggtext) 13 | library(scales) 14 | library(lubridate) 15 | library(viridis) 16 | 17 | # --- 2. Cargar Configuración, Temas y Utilidades --- 18 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 19 | utils_file <- "R/30DayChartChallenge2025/utils.R" 20 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 21 | font_path_fa <- "fonts/fa-brands-400.ttf" 22 | output_path <- "R/30DayChartChallenge2025/plots/" 23 | 24 | # Verificar existencia de archivos y cargar 25 | source(themes_file) # Carga paletas y theme_week4_social 26 | source(utils_file) # Carga caption y setup_fonts (con "Lato") 27 | config <- read_yaml(config_file) 28 | 29 | # --- 3. Configurar Fuentes --- 30 | setup_fonts(fa_brands_path = font_path_fa) 31 | 32 | # --- 4. Cargar y Preparar Datos de Encuestas Polonia --- 33 | 34 | data_file <- "R/30DayChartChallenge2025/data/elecciones_polonia_2025.csv" 35 | if (!file.exists(data_file)) stop("Archivo CSV de encuestas no encontrado: ", data_file) 36 | 37 | message("Cargando datos desde: ", data_file) 38 | # Leer CSV especificando separador y decimal 39 | polls_dt <- data.table::fread(data_file, sep = ";", dec = ",", header = TRUE) 40 | message("Datos cargados. ", nrow(polls_dt), " filas iniciales.") 41 | print(head(polls_dt)) 42 | 43 | # --- Limpieza y Preparación --- 44 | 45 | # Convertir fecha y apoyo 46 | polls_dt[, fecha := lubridate::as_date(fecha)] 47 | polls_dt[, apoyo_pct := as.numeric(apoyo) * 100] 48 | 49 | # Limpiar nombres y orientación (quitar espacios extra) 50 | cols_to_trim <- c("candidato", "partido", "orientación") 51 | polls_dt[, (cols_to_trim) := lapply(.SD, trimws), .SDcols = cols_to_trim] 52 | 53 | # Crear etiqueta combinada para leyenda 54 | polls_dt[, label_legend := paste0(candidato, " (", orientación, ")")] 55 | 56 | 57 | # Filtrar NAs generados y rango de fechas si es necesario 58 | cols_check_na <- c("fecha", "apoyo_pct", "label_legend") 59 | polls_clean_dt <- na.omit(polls_dt, cols = cols_check_na) 60 | 61 | # Seleccionar 6 candidatos con más apoyo medio 62 | top_6_candidatos <- polls_clean_dt[, .(apoyo_medio = mean(apoyo_pct, na.rm = TRUE)), label_legend][order(-apoyo_medio), head(label_legend, 6)] 63 | polls_clean_dt <- polls_clean_dt[label_legend %in% top_6_candidatos] 64 | 65 | # Convertir a factor para ordenar leyenda 66 | polls_clean_dt[, label_legend := factor(label_legend, levels = top_6_candidatos)] 67 | 68 | message("Datos limpios y preparados: ", nrow(polls_clean_dt), " registros válidos.") 69 | message("Rango de fechas: ", min(polls_clean_dt$fecha), " a ", max(polls_clean_dt$fecha)) 70 | message("Candidatos (Orientación) encontrados: ", paste(levels(polls_clean_dt$label_legend), collapse=", ")) 71 | 72 | # --- 5. Crear Gráfico de Tendencias Suavizadas --- 73 | 74 | # Definir textos 75 | source_text_day19 <- "Fuente: Diversas encuestadoras (elaboración propia)" 76 | plot_title <- "Evolución Intención de Voto: Presidenciales Polonia 2025" 77 | plot_subtitle <- paste0("Tendencias suavizadas (LOESS/GAM) basadas en encuestas publicadas.\nPeriodo: ", 78 | format(min(polls_clean_dt$fecha), "%b %Y"), " - ", format(max(polls_clean_dt$fecha), "%b %Y")) 79 | 80 | # Generar caption 81 | caption_day19 <- generate_caption( 82 | day = 19, 83 | source_text = source_text_day19, 84 | config = config, 85 | color_text_source = "#5c5c5c", 86 | color_text_author = "#757de8" 87 | ) 88 | 89 | # Colores y tema 90 | bg_col <- "#F2F2F2" 91 | text_col <- challenge_palettes$week4_social['grey'] 92 | num_candidatos <- length(levels(polls_clean_dt$label_legend)) 93 | 94 | # Crear el gráfico 95 | gg_day19 <- ggplot(polls_clean_dt, aes(x = fecha, y = apoyo_pct, color = label_legend, group = label_legend)) + 96 | 97 | # Opcional: Puntos de encuestas individuales (muy transparentes) 98 | geom_point(alpha = 0.3, size = 2, shape = 19, show.legend = FALSE) + 99 | 100 | # Líneas suavizadas (método por defecto LOESS/GAM) 101 | geom_smooth(se = FALSE, linewidth = 1.2, span = 0.95) + 102 | 103 | # Escala de color 104 | scale_color_manual(values = challenge_pal("week4_social")(num_candidatos), name = NULL) + 105 | 106 | # Formato de ejes 107 | scale_y_continuous(labels = scales::label_percent(scale = 1), limits = c(0, 40), expand = expansion(mult=c(0, 0.05))) + 108 | scale_x_date(date_breaks = "1 month", date_labels = "%B %Y") + # Ajusta breaks según rango real 109 | 110 | # Aplicar tema 111 | theme_week4_social(base_family = "Lato", base_size = 11) + # Usar tema semana 4 112 | 113 | # Leyenda 114 | guides(color = guide_legend(override.aes = list(alpha = 1, linewidth=2), ncol = 3)) + # Leyenda más clara y en 2 cols si es larga 115 | 116 | # Etiquetas y caption 117 | labs( 118 | title = plot_title, 119 | subtitle = plot_subtitle, 120 | x = "Fecha de Encuesta", 121 | y = "Apoyo Estimado (%)", 122 | caption = caption_day19 123 | ) + 124 | theme(legend.title.align = 0.5) # Centrar título leyenda 125 | 126 | # --- 6. Guardar Gráfico --- 127 | output_file <- file.path(output_path, "day_19_smooth_polls_poland.png") 128 | ggsave( 129 | filename = output_file, 130 | plot = gg_day19, 131 | width = 1200, height = 1200, units = "px", dpi = 150, bg = bg_col 132 | ) 133 | 134 | message("Gráfico del Día 19 (Smooth Polls) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 135 | 136 | # --- Fin day_19_smooth_polls.R --- -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_4_timeseries/day_23_logscale/day_23.R: -------------------------------------------------------------------------------- 1 | # --- Day 23: Log Scale (Long-Term GDP per Capita Growth in Spain) --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: World Bank via WDI package) 4 | # Evolución del PIB per cápita de España (PPA, const.) en escala logarítmica. 5 | 6 | # --- 1. Cargar Librerías --- 7 | library(ggplot2) 8 | library(data.table) 9 | library(yaml) 10 | library(showtext) 11 | library(ggtext) 12 | library(scales) 13 | library(lubridate) 14 | library(WDI) 15 | 16 | # --- 2. Cargar Configuración, Temas y Utilidades --- 17 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 18 | utils_file <- "R/30DayChartChallenge2025/utils.R" 19 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 20 | font_path_fa <- "fonts/fa-brands-400.ttf" 21 | output_path <- "R/30DayChartChallenge2025/plots/" 22 | 23 | # Verificar existencia de archivos y cargar 24 | source(themes_file) # Carga paletas y theme_week4_social 25 | source(utils_file) # Carga caption y setup_fonts (con "Lato") 26 | config <- read_yaml(config_file) 27 | 28 | # --- 3. Configurar Fuentes --- 29 | setup_fonts(fa_brands_path = font_path_fa) # Carga "Lato" 30 | 31 | # --- 4. Cargar y Preparar Datos del Banco Mundial --- 32 | 33 | # Indicador: PIB per capita, PPA (dólares internacionales constantes de 2017) 34 | indicator_code <- "NY.GDP.PCAP.PP.KD" 35 | country_code <- "ES" # Código ISO para España 36 | start_year <- 1990 # Datos disponibles desde 1990 en este indicador 37 | # Obtener hasta el último año completo con datos (normalmente con 1-2 años de retraso) 38 | end_year <- year(Sys.Date()) - 2 39 | 40 | message("Descargando datos del PIB per cápita para España desde World Bank (WDI)...") 41 | gdp_raw_df <- tryCatch({ 42 | WDI(country = country_code, indicator = indicator_code, start = start_year, end = end_year, extra = FALSE) 43 | }, error = function(e) { 44 | warning("Error al descargar datos de WDI. Comprueba la conexión o el indicador.\nError: ", e$message) 45 | return(NULL) 46 | }) 47 | 48 | if (is.null(gdp_raw_df) || nrow(gdp_raw_df) == 0) { 49 | stop("No se pudieron obtener datos del Banco Mundial.") 50 | } 51 | 52 | # Convertir a data.table y limpiar 53 | gdp_dt <- as.data.table(gdp_raw_df) 54 | setnames(gdp_dt, indicator_code, "GDP_pc_ppp_kd", skip_absent=TRUE) 55 | if (!"GDP_pc_ppp_kd" %in% names(gdp_dt)) { 56 | # Intentar encontrarla si WDI usó un nombre ligeramente diferente 57 | potential_name <- names(gdp_dt)[!names(gdp_dt) %in% c("iso2c", "country", "year", "iso3c")] 58 | if (length(potential_name) == 1) { 59 | message("Columna indicador encontrada como: ", potential_name) 60 | setnames(gdp_dt, potential_name, "GDP_pc_ppp_kd") 61 | } else { 62 | stop("No se pudo identificar la columna del indicador GDP descargada.") 63 | } 64 | } 65 | gdp_dt <- gdp_dt[, .(Year = year, GDP_pc = GDP_pc_ppp_kd)] # Seleccionar y renombrar 66 | gdp_dt <- na.omit(gdp_dt) # Quitar años con NA 67 | setorder(gdp_dt, Year) # Ordenar por año 68 | 69 | message("Datos de PIB per cápita preparados. Rango: ", min(gdp_dt$Year), "-", max(gdp_dt$Year)) 70 | print(tail(gdp_dt)) 71 | print(summary(gdp_dt)) 72 | 73 | # --- Definir períodos de crisis --- 74 | crisis_periods <- data.frame( 75 | start_year = c(1992, 2008, 2020), 76 | end_year = c(1994, 2013, 2021) 77 | ) 78 | 79 | # --- 5. Crear Gráfico de Líneas con Escala Logarítmica --- 80 | 81 | # Definir textos 82 | source_text_day23 <- "Fuente: World Bank (Indicator: NY.GDP.PCAP.PP.KD) via WDI package" 83 | plot_title <- paste0("Crecimiento Económico de España (", min(gdp_dt$Year), "-", max(gdp_dt$Year),")") 84 | plot_subtitle <- paste0("Evolución del PIB per cápita (PPA, dólares const. 2017).\n", 85 | "La escala logarítmica del eje Y revela cambios en la tasa de crecimiento.\n", 86 | "Las áreas sombreadas indican períodos de crisis económicas en España.") 87 | # Generar caption 88 | caption_day23 <- generate_caption( 89 | day = 23, 90 | source_text = source_text_day23, 91 | config = config, 92 | color_text_source = "#5c5c5c", 93 | color_text_author = "#757de8" 94 | ) 95 | 96 | # Colores y tema 97 | bg_col <- "#F2F2F2" 98 | line_color <- challenge_palettes$week4_social['indigo'] # Azul índigo 99 | 100 | # Crear el gráfico 101 | gg_day23 <- ggplot(gdp_dt, aes(x = Year, y = GDP_pc)) + 102 | geom_line(color = line_color, linewidth = 1.2, alpha = 0.8) + 103 | geom_point(color = line_color, size = 2, shape=21, fill=bg_col, stroke=0.5) + 104 | 105 | # Añadir sombreado para periodos de crisis 106 | geom_rect( 107 | data = crisis_periods, 108 | mapping = aes(xmin = start_year, xmax = end_year, ymin = 0, ymax = Inf), 109 | fill = challenge_palettes$week4_social['pink'] , alpha = 0.2, 110 | inherit.aes = FALSE 111 | ) + 112 | 113 | scale_y_log10( 114 | name = "PIB per Cápita (PPA, $ const. 2017) [Escala Log]", # Título eje Y 115 | labels = scales::label_dollar(accuracy = 1), # Formato Dólar (simplificado) 116 | breaks = scales::log_breaks(n = 6) # Ajustar número de breaks si es necesario 117 | ) + 118 | 119 | # Escala X (Año) 120 | scale_x_continuous(n.breaks = 8) + 121 | 122 | # Aplicar tema 123 | theme_week4_social(base_family = "Lato", base_size = 10) + 124 | 125 | # Etiquetas y caption 126 | labs( 127 | title = plot_title, 128 | subtitle = plot_subtitle, 129 | x = "Año", 130 | caption = caption_day23 131 | ) + 132 | theme(legend.position = "none") 133 | 134 | 135 | 136 | 137 | 138 | # --- 6. Guardar Gráfico --- 139 | output_file <- file.path(output_path, "day_23_logscale_gdp_spain.png") 140 | ggsave( 141 | filename = output_file, 142 | plot = gg_day23, 143 | width = 1200, height = 1200, units = "px", dpi = 150, bg = bg_col # Apaisado 144 | ) 145 | 146 | message("Gráfico del Día 23 (Log Scale GDP) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 147 | 148 | # --- Fin day_23_logscale_gdp.R --- -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_2_distributions/day_11_stripes/day_11.R: -------------------------------------------------------------------------------- 1 | # --- Day 11: Stripes (High Volatility VIX Days Barcode) --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: Yahoo Finance) 4 | # Visualización de días con alta volatilidad (VIX > umbral) como "rayas" 5 | # en una línea de tiempo, creando un efecto de código de barras. 6 | 7 | # --- 1. Cargar Librerías --- 8 | library(quantmod) 9 | library(ggplot2) 10 | library(data.table) 11 | library(lubridate) 12 | library(yaml) 13 | library(showtext) 14 | library(ggtext) 15 | library(scales) 16 | 17 | # --- 2. Cargar Configuración, Temas y Utilidades --- 18 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 19 | utils_file <- "R/30DayChartChallenge2025/utils.R" 20 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 21 | font_path_fa <- "fonts/fa-brands-400.ttf" 22 | output_path <- "R/30DayChartChallenge2025/plots/" 23 | 24 | # Verificar existencia de archivos 25 | if (!file.exists(themes_file)) stop("Archivo de temas no encontrado: ", themes_file) 26 | if (!file.exists(utils_file)) stop("Archivo de utilidades no encontrado: ", utils_file) 27 | if (!file.exists(config_file)) stop("Archivo de configuración no encontrado: ", config_file) 28 | 29 | source(themes_file) # Carga paletas y temas 30 | source(utils_file) # Carga caption y setup_fonts 31 | config <- read_yaml(config_file) 32 | 33 | # --- 3. Configurar Fuentes --- 34 | setup_fonts(fa_brands_path = font_path_fa) 35 | 36 | # --- 4. Obtener y Preparar Datos VIX --- 37 | 38 | # Definir fechas y ticker 39 | end_date <- Sys.Date() 40 | start_date <- as.Date("1993-01-20") # Ampliar para cubrir más presidentes (desde Clinton) 41 | ticker_symbol <- "^VIX" 42 | ticker_name <- "VIX Index" 43 | 44 | message("Descargando datos para ", ticker_name, " (", ticker_symbol, ")") 45 | data_xts <- tryCatch({ 46 | getSymbols( 47 | ticker_symbol, 48 | src = "yahoo", 49 | from = start_date, 50 | to = end_date, 51 | auto.assign = FALSE 52 | ) 53 | }, error = function(e) { 54 | warning("Error al descargar ", ticker_symbol, ": ", e$message) 55 | return(NULL) 56 | }) 57 | 58 | 59 | if (!is.null(data_xts)) { 60 | price_col_name <- paste0(gsub("\\^", "", ticker_symbol), ".Close") 61 | if (!price_col_name %in% names(data_xts)) { 62 | price_col_name <- grep("\\.Close", names(data_xts), value = TRUE)[1] 63 | if(is.na(price_col_name)) stop("No se encontró la columna de cierre para VIX.") 64 | warning("Usando columna de cierre detectada: ", price_col_name) 65 | } 66 | vix_levels_xts <- data_xts[, price_col_name] 67 | names(vix_levels_xts) <- "VIX_Level" 68 | 69 | vix_dt <- data.table( 70 | Date = index(vix_levels_xts), 71 | VIX_Level = as.numeric(coredata(vix_levels_xts)) 72 | ) 73 | vix_dt <- na.omit(vix_dt) 74 | message("Procesado ", ticker_name, ". ", nrow(vix_dt), " niveles diarios obtenidos.") 75 | 76 | # --- Filtrar días de alta volatilidad --- 77 | high_vol_thr <- 30 # Umbral para considerar alta volatilidad (puedes usar 35 si prefieres) 78 | vix_high_days_dt <- vix_dt[VIX_Level >= high_vol_thr] 79 | message(nrow(vix_high_days_dt), " días encontrados con VIX >= ", high_vol_thr) 80 | 81 | } else { 82 | stop("No se pudieron obtener datos para ", ticker_name, " (", ticker_symbol, ").") 83 | } 84 | 85 | # Verificar datos filtrados 86 | print(head(vix_high_days_dt)) 87 | 88 | 89 | # --- 5. Crear Gráfico de Código de Barras ("Stripes") --- 90 | 91 | # Definir textos 92 | source_text_day11 <- paste0("Yahoo Finance (^VIX). Periodo: ", 93 | format(start_date, "%Y-%m-%d"), " a ", 94 | format(end_date, "%Y-%m-%d")) 95 | plot_title <- paste0("Días de Alta Volatilidad del Mercado (VIX >= ", high_vol_thr, ")") 96 | plot_subtitle <- "Cada 'raya' vertical representa un día donde el Índice VIX cerró por encima del umbral,\nmostrando clústeres de estrés en el mercado a lo largo del tiempo." 97 | 98 | # Generar caption 99 | caption_day11 <- generate_caption( 100 | day = 11, 101 | source_text = source_text_day11, 102 | config = config, 103 | color_text_source = "#E8EAED", 104 | color_text_author = "#4FC3F7" 105 | ) 106 | 107 | # Colores y tema 108 | stripe_color <- paleta_week2_tech[5] 109 | text_col <- "#E8EAED" 110 | bg_col <- "#202124" 111 | 112 | # Crear el gráfico 113 | gg_day11 <- ggplot(vix_high_days_dt, aes(x = Date)) + 114 | # Usar geom_segment para crear las rayas verticales 115 | geom_segment(aes(y = 0, yend = 1), # Fija la altura de las rayas 116 | color = stripe_color, 117 | linewidth = 0.4) + # Ajusta el grosor de las rayas 118 | 119 | # Escala de fecha 120 | scale_x_date(date_breaks = "2 years", date_labels = "%Y", expand = expansion(mult = 0.01)) + 121 | 122 | # Aplicar tema personalizado 123 | theme_week2_tech(base_size = 11) + 124 | 125 | # Ocultar el eje Y ya que no tiene significado aquí 126 | theme( 127 | axis.text.y = element_blank(), 128 | axis.ticks.y = element_blank(), 129 | axis.title.y = element_blank(), 130 | panel.grid.major.y = element_blank(), 131 | panel.grid.minor.y = element_blank() 132 | ) + 133 | 134 | # Añadir etiquetas y caption 135 | labs( 136 | title = plot_title, 137 | subtitle = plot_subtitle, 138 | x = "Año", 139 | y = NULL, # Eje Y sin título 140 | caption = caption_day11 141 | ) + 142 | # Fijar límites Y (opcional pero ayuda a asegurar que los segmentos llenen el espacio) 143 | coord_cartesian(ylim = c(0, 1)) 144 | 145 | 146 | # --- 6. Guardar Gráfico --- 147 | output_file <- file.path(output_path, "day_11_stripes_vix_barcode.png") 148 | ggsave( 149 | filename = output_file, 150 | plot = gg_day11, 151 | width = 1200, height = 1200, units = "px", dpi = 150, bg = bg_col # Más ancho y menos alto 152 | ) 153 | 154 | message("Gráfico del Día 11 (VIX Barcode Stripes) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 155 | 156 | # --- Fin day_11_stripes_vix_barcode.R --- -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/30DayChartChallenge2025.yml: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------- 2 | # Archivo de Configuración para #30DayChartChallenge 2025 3 | # ----------------------------------------------------- 4 | 5 | # Información por defecto/global 6 | defaults: 7 | author_name: "Michal Kinel" 8 | social_media: 9 | github_icon: "" 10 | github_username: "michal0091" 11 | mastodon_icon: "" 12 | mastodon_username: "miki_peltzer" 13 | mastodon_server: "techhub.social" 14 | linkedin_icon: "" 15 | linkedin_username: "michal-kinel" 16 | main_hashtag: "#30DayChartChallenge" 17 | year: 2025 18 | 19 | # Prompts diarios (Abril 2025) 20 | daily_prompts: 21 | 1: 22 | day: 1 23 | category: "Comparisons" 24 | theme: "Fractions" 25 | hashtag: "#Day1" 26 | data_source_url: null 27 | notes: "" 28 | 2: 29 | day: 2 30 | category: "Comparisons" 31 | theme: "Slope" 32 | hashtag: "#Day2" 33 | data_source_url: null 34 | notes: "" 35 | 3: 36 | day: 3 37 | category: "Comparisons" 38 | theme: "Circular" 39 | hashtag: "#Day3" 40 | data_source_url: null 41 | notes: "" 42 | 4: 43 | day: 4 44 | category: "Comparisons" 45 | theme: "Big or Small" 46 | hashtag: "#Day4" 47 | data_source_url: null 48 | notes: "" 49 | 5: 50 | day: 5 51 | category: "Comparisons" 52 | theme: "Ranking" 53 | hashtag: "#Day5" 54 | data_source_url: null 55 | notes: "" 56 | 6: 57 | day: 6 58 | category: "Comparisons" 59 | theme: "Florence Nightingale" 60 | hashtag: "#Day6" 61 | data_source_url: null 62 | notes: "Theme day" 63 | 7: 64 | day: 7 65 | category: "Distributions" 66 | theme: "Outliers" 67 | hashtag: "#Day7" 68 | data_source_url: null 69 | notes: "" 70 | 8: 71 | day: 8 72 | category: "Distributions" 73 | theme: "Histogram" 74 | hashtag: "#Day8" 75 | data_source_url: null 76 | notes: "" 77 | 9: 78 | day: 9 79 | category: "Distributions" 80 | theme: "Diverging" 81 | hashtag: "#Day9" 82 | data_source_url: null 83 | notes: "" 84 | 10: 85 | day: 10 86 | category: "Distributions" 87 | theme: "Multi-modal" 88 | hashtag: "#Day10" 89 | data_source_url: null 90 | notes: "" 91 | 11: 92 | day: 11 93 | category: "Distributions" 94 | theme: "Stripes" 95 | hashtag: "#Day11" 96 | data_source_url: null 97 | notes: "" 98 | 12: 99 | day: 12 100 | category: "Distributions" 101 | theme: "Data.gov" 102 | hashtag: "#Day12" 103 | data_source_url: "https://www.data.gov/" # Portal principal 104 | notes: "Data day" 105 | 13: 106 | day: 13 107 | category: "Relationships" 108 | theme: "Clusters" 109 | hashtag: "#Day13" 110 | data_source_url: null 111 | notes: "" 112 | 14: 113 | day: 14 114 | category: "Relationships" 115 | theme: "Kinship" 116 | hashtag: "#Day14" 117 | data_source_url: null 118 | notes: "" 119 | 15: 120 | day: 15 121 | category: "Relationships" 122 | theme: "Complicated" 123 | hashtag: "#Day15" 124 | data_source_url: null 125 | notes: "" 126 | 16: 127 | day: 16 128 | category: "Relationships" 129 | theme: "Negative" 130 | hashtag: "#Day16" 131 | data_source_url: null 132 | notes: "" 133 | 17: 134 | day: 17 135 | category: "Relationships" 136 | theme: "Birds" 137 | hashtag: "#Day17" 138 | data_source_url: null # Posibles fuentes: eBird, GBIF 139 | notes: "" 140 | 18: 141 | day: 18 142 | category: "Relationships" 143 | theme: "El País" 144 | hashtag: "#Day18" 145 | data_source_url: null # Buscar datos en El País o relacionados 146 | notes: "Theme day" 147 | 19: 148 | day: 19 149 | category: "Time Series" 150 | theme: "Smooth" 151 | hashtag: "#Day19" 152 | data_source_url: null 153 | notes: "" 154 | 20: 155 | day: 20 156 | category: "Time Series" 157 | theme: "Urbanization" 158 | hashtag: "#Day20" 159 | data_source_url: null # Posibles fuentes: ONU, Banco Mundial, INE 160 | notes: "" 161 | 21: 162 | day: 21 163 | category: "Time Series" 164 | theme: "Fossils" 165 | hashtag: "#Day21" 166 | data_source_url: null 167 | notes: "" 168 | 22: 169 | day: 22 170 | category: "Time Series" 171 | theme: "Stars" 172 | hashtag: "#Day22" 173 | data_source_url: null # Posibles fuentes: NASA, ESA 174 | notes: "" 175 | 23: 176 | day: 23 177 | category: "Time Series" 178 | theme: "Log Scale" 179 | hashtag: "#Day23" 180 | data_source_url: null 181 | notes: "" 182 | 24: 183 | day: 24 184 | category: "Time Series" 185 | theme: "World Health Organization" 186 | hashtag: "#Day24" 187 | data_source_url: "https://www.who.int/data/gho" # Portal de datos GHO de la OMS 188 | notes: "Data day" 189 | 25: 190 | day: 25 191 | category: "Uncertainties" 192 | theme: "Risk" 193 | hashtag: "#Day25" 194 | data_source_url: null 195 | notes: "" 196 | 26: 197 | day: 26 198 | category: "Uncertainties" 199 | theme: "Monochrome" 200 | hashtag: "#Day26" 201 | data_source_url: null 202 | notes: "" 203 | 27: 204 | day: 27 205 | category: "Uncertainties" 206 | theme: "Noise" 207 | hashtag: "#Day27" 208 | data_source_url: null 209 | notes: "" 210 | 28: 211 | day: 28 212 | category: "Uncertainties" 213 | theme: "Inclusion" 214 | hashtag: "#Day28" 215 | data_source_url: null 216 | notes: "" 217 | 29: 218 | day: 29 219 | category: "Uncertainties" 220 | theme: "Extraterrestrial" 221 | hashtag: "#Day29" 222 | data_source_url: null 223 | notes: "" 224 | 30: 225 | day: 30 226 | category: "Uncertainties" 227 | theme: "National Geographic" 228 | hashtag: "#Day30" 229 | data_source_url: null # Buscar datos o inspiración en NatGeo 230 | notes: "Theme day" 231 | -------------------------------------------------------------------------------- /R/2024/week_12/2024_w12_portfolio.R: -------------------------------------------------------------------------------- 1 | # Header ------------------------------------------------------------------ 2 | # 3 | # Author: Michal Kinel 4 | # Copyright (c) Michal Kinel, 2024 5 | # Email: michal.kinel@gmail.com 6 | # 7 | # Date: 2024-03-24 8 | # 9 | # Script Name: 2024_w12_portfolio.R 10 | # 11 | # Script Description: Protfolio allocation plot 12 | # 13 | # 14 | # Notes: 15 | # 16 | # 17 | 18 | # Set options ------------------------------------------------------------- 19 | cat("Setting options... \n\n", sep = "") 20 | options(scipen = 999) # turns off scientific notation 21 | options(encoding = "UTF-8") # sets string encoding to UTF-8 instead of ANSI 22 | 23 | 24 | # Install packages & load libraries --------------------------------------- 25 | cat("Install packages & load libraries... \n\n", sep = "") 26 | packages <- c("tidyverse", "data.table", "zoo", "showtext", "sysfonts", "treemapify", 27 | "patchwork") # list of packages to load 28 | n_packages <- length(packages) # count how many packages are required 29 | 30 | new_pkg <- packages[!(packages %in% installed.packages())] # determine which packages aren't installed 31 | 32 | # Install missing packages 33 | if(length(new_pkg)){ 34 | install.packages(new_pkg) 35 | } 36 | 37 | # Load all requried libraries 38 | for(n in 1:n_packages){ 39 | cat("Loading Library #", n, " of ", n_packages, "... Currently Loading: ", packages[n], "\n", sep = "") 40 | lib_load <- paste("library(\"",packages[n],"\")", sep = "") # create string of text for loading each library 41 | eval(parse(text = lib_load)) # evaluate the string to load the library 42 | } 43 | 44 | # Load data --------------------------------------------------------------- 45 | cat("Load data... \n\n", sep = "") 46 | portfolio <- fread("R/2024/week_12/portfolio.csv") 47 | portfolio[, prp := as.numeric(gsub(",", ".", prp))] 48 | 49 | # Styles ------------------------------------------------------------------ 50 | cat("Setting style... \n\n", sep = "") 51 | source("R/2024/theme.R") 52 | 53 | 54 | # Plot -------------------------------------------------------------------- 55 | cat("Plot... \n\n", sep = "") 56 | 57 | pais <- portfolio[type == "pais"][order(-prp)][, .(prp = sum(prp)), by = .(name = fifelse( 58 | prp > 1, name, paste0("Otros ", length(name), " países") 59 | ))] 60 | pais[, name := factor(name, levels = pais$name)] 61 | 62 | # Pais plot 63 | pais_plot <- pais %>% 64 | ggplot(aes(area = prp, label = paste0(name, " ", sprintf("%2.0f", prp), "% "))) + 65 | geom_treemap(fill = color_set_1, color = color_background, layout = "scol") + 66 | geom_treemap_text(family = "inter_regular", 67 | colour = color_background, 68 | place = "centre", 69 | grow = TRUE, 70 | layout = "scol", 71 | min.size = 7) + 72 | labs(subtitle = "Porcentaje de la cartera en cada país") + 73 | theme_my() 74 | 75 | 76 | # Sector 77 | sector <- 78 | portfolio[type == "sector"][order(-prp)][, .(prp = sum(prp)), by = .(name = fifelse(prp > 2.5, name, paste0("Otros sectores")))] 79 | sector[, name := factor(name, levels = sector$name)] 80 | 81 | # Sector base plot 82 | sector_base_plot <- 83 | sector %>% 84 | ggplot(aes(prp, name)) + 85 | geom_col() + 86 | facet_wrap(~ name, ncol = 1, scales = "free_y") + 87 | scale_x_continuous(name = "Porcentaje", 88 | expand = c(0, 0), 89 | limits = c(0, 35)) + 90 | scale_y_discrete(guide = "none") + 91 | theme_my() + 92 | theme( 93 | strip.background = element_rect(fill = color_background, color = color_background), 94 | strip.text = element_text( 95 | color = color_text_2, 96 | family = "inter_regular", 97 | hjust = 0, 98 | margin = margin(1, 1, 1, 1), 99 | size = rel(1.1), 100 | face = "bold" 101 | ), 102 | panel.grid.major = element_blank() 103 | ) 104 | 105 | # Sector plot add text labels 106 | sector_plot <- sector_base_plot + 107 | geom_text( 108 | aes( 109 | label = paste0(" ", sprintf("%2.1f", prp), "% "), 110 | color = prp > 5, 111 | hjust = prp > 5 112 | ), 113 | size = 4, 114 | fontface = "bold", 115 | family = "inter_regular" 116 | ) + 117 | scale_color_manual(values = c(color_text_1, color_background), 118 | guide = "none") + 119 | labs(subtitle = "Porcentaje de la cartera en cada sector", y = NULL) 120 | 121 | 122 | # Combine plots ----------------------------------------------------------- 123 | cat("Combine plots... \n\n", sep = "") 124 | combined_plot <- 125 | pais_plot + sector_plot + 126 | plot_layout(widths = c(1, 1)) + 127 | plot_annotation( 128 | title = "Distribución de la cartera de ETFs", 129 | caption = caption_text(source_text = "Own elaboration"), 130 | theme = theme_my() 131 | ) 132 | 133 | 134 | # Save plot --------------------------------------------------------------- 135 | cat("Save plot... \n\n", sep = "") 136 | 137 | ggsave( 138 | filename = "portfolio_distr_plot.png", 139 | path = normalizePath("R/2024/week_12"), 140 | plot = combined_plot, 141 | device = "png", 142 | units = "mm", 143 | width = 105*2, 144 | height = 105, 145 | dpi = 320 146 | ) 147 | 148 | # Save separately 149 | pais_plot_solo <- pais_plot + 150 | labs( 151 | title = "Distribución de la cartera de ETFs", 152 | caption = caption_text(source_text = "Elaboración propia")) 153 | ggsave( 154 | filename = "portfolio_distr_pais_plot.png", 155 | path = normalizePath("R/2024/week_12"), 156 | plot = pais_plot_solo, 157 | device = "png", 158 | units = "mm", 159 | width = 105, 160 | height = 105, 161 | dpi = 320 162 | ) 163 | 164 | 165 | pais_sector_solo <- sector_plot + 166 | labs( 167 | title = "Distribución de la cartera de ETFs", 168 | caption = caption_text(source_text = "Elaboración propia")) 169 | ggsave( 170 | filename = "portfolio_distr_sector_plot.png", 171 | path = normalizePath("R/2024/week_12"), 172 | plot = pais_sector_solo, 173 | device = "png", 174 | units = "mm", 175 | width = 105, 176 | height = 105, 177 | dpi = 320 178 | ) 179 | 180 | 181 | -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_3_relationships/day_18_el_pais/day_18.R: -------------------------------------------------------------------------------- 1 | # --- Day 18: El País (Theme Day) - Housing Effort vs Pet Ratio (Madrid) --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: datos.madrid.es / INE - via User CSV) 4 | # Relación entre esfuerzo inmobiliario y ratio mascotas/niño por distrito y año. 5 | # Estilo inspirado en El País. 6 | 7 | # --- 1. Cargar Librerías --- 8 | library(ggplot2) 9 | library(data.table) 10 | library(yaml) 11 | library(showtext) 12 | library(ggtext) 13 | library(scales) 14 | library(lubridate) 15 | library(viridis) # Para escala de color de año 16 | 17 | # --- 2. Cargar Configuración, Temas y Utilidades --- 18 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 19 | utils_file <- "R/30DayChartChallenge2025/utils.R" 20 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 21 | font_path_fa <- "fonts/fa-brands-400.ttf" 22 | output_path <- "R/30DayChartChallenge2025/plots/" 23 | 24 | # Verificar existencia de archivos y cargar 25 | source(themes_file) # Carga paletas y TEMA EL PAIS 26 | source(utils_file) # Carga caption y setup_fonts (con "Lato") 27 | config <- read_yaml(config_file) 28 | 29 | # --- 3. Configurar Fuentes --- 30 | setup_fonts(fa_brands_path = font_path_fa) 31 | 32 | # --- 4. Cargar y Preparar Datos de Madrid --- 33 | data_dir <- "R/30DayChartChallenge2025/data" 34 | csv_file <- file.path(data_dir, "madrid.csv") # <- Nombre del archivo CSV 35 | 36 | if (!file.exists(csv_file)) stop("Archivo CSV de Madrid no encontrado: ", csv_file) 37 | 38 | message("Cargando datos desde: ", csv_file) 39 | # Leer CSV, ¡cuidado con separador decimal y de miles si no es punto! 40 | # Asumiré punto decimal por defecto. Si es coma, usa dec=",". 41 | madrid_dt <- data.table::fread(csv_file, header = TRUE) 42 | message("Datos cargados. ", nrow(madrid_dt), " filas iniciales.") 43 | print(head(madrid_dt, 2)) # Ver las primeras filas y nombres 44 | 45 | # --- Limpieza y Cálculo de Variables --- 46 | # Limpiar nombres de distrito 47 | madrid_dt[, Distrito := sub("^[0-9]+\\. ", "", Distrito)] 48 | 49 | # Asegurar tipos numéricos (puede necesitar gsub(",",".",...) si decimal es coma) 50 | cols_num <- c("Renta neta media por persona", "Menores de 16", 51 | "ESPECIE CANINA", "ESPECIE FELINA", "precio €/m2 vivienda venta") 52 | madrid_dt[, (cols_num) := lapply(.SD, as.numeric), .SDcols = cols_num] 53 | 54 | # Calcular variables necesarias 55 | madrid_dt[, Total_Pets := `ESPECIE CANINA` + `ESPECIE FELINA`] 56 | # Calcular Ratio (evitando división por cero) 57 | madrid_dt[, Pet_Ratio := fifelse(`Menores de 16` > 0, Total_Pets / `Menores de 16`, NA_real_)] 58 | # Calcular Ingreso Hogar (Asunción: 2x ingreso per cápita ANUAL) 59 | madrid_dt[, Household_Income := `Renta neta media por persona` * 2] 60 | # Calcular Precio Vivienda 75m2 61 | madrid_dt[, Price_75m2 := `precio €/m2 vivienda venta` * 75] 62 | # Calcular Años de Esfuerzo 63 | madrid_dt[, Years_Effort := fifelse(Household_Income > 0, Price_75m2 / Household_Income, NA_real_)] 64 | 65 | # Seleccionar datos finales y quitar NAs 66 | madrid_clean_dt <- na.omit(madrid_dt, cols=c("Distrito", "year", "Pet_Ratio", "Years_Effort", "Household_Income")) 67 | 68 | madrid_clean_dt[, year_f := factor(year)] 69 | 70 | message("Datos calculados y limpios: ", nrow(madrid_clean_dt), " observaciones Distrito-Año.") 71 | print(summary(madrid_clean_dt[, .(Pet_Ratio, Years_Effort)])) 72 | print("Años incluidos:") 73 | print(levels(madrid_clean_dt$year_f)) 74 | 75 | # --- 5. Crear Scatter Plot (Estilo El País) --- 76 | 77 | # Definir textos 78 | source_text_day18 <- "Fuente: Portal de Datos Abiertos Ayto. Madrid / INE (elaboración propia)" 79 | plot_title <- "¿El Ladrillo ahoga a la Cigüeña? Mascotas y Esfuerzo Inmobiliario" 80 | plot_subtitle <- "Relación positiva en distritos de Madrid (2015-2022): A más años para pagar el piso, ¿más 'perrhijos' por niño?" 81 | 82 | # Generar caption 83 | caption_day18 <- generate_caption( 84 | day = 18, 85 | source_text = source_text_day18, 86 | config = config, 87 | color_text_source = challenge_palettes$el_pais['text2'], 88 | color_text_author = challenge_palettes$el_pais['text'] 89 | ) 90 | 91 | # Colores 92 | bg_col <- challenge_palettes$el_pais['bg'] 93 | text_col <- challenge_palettes$el_pais['text'] 94 | accent_color <- challenge_palettes$el_pais['accent1'] # Azul para regresión 95 | 96 | # Crear el gráfico 97 | gg_day18 <- ggplot(madrid_clean_dt, aes(x = Pet_Ratio, y = Years_Effort)) + 98 | # Puntos coloreados por año 99 | geom_point(aes(color = year_f), alpha = 1, size = 3.5) + 100 | 101 | # Línea de regresión lineal 102 | geom_smooth(method = "lm", color = accent_color, fill = accent_color, alpha = 0.1, se = TRUE, linewidth = 0.8) + 103 | 104 | # Escala de color para año (Viridis es buena opción) 105 | scale_color_manual(values = c( 106 | "#2c85b1", "#96bbd7", "#41373f", "#c6c08c", 107 | "#df3a4d", "#ef9ca6", "#3d5a0e", "#7ab41d"), 108 | name = "Año") + # colores más de El País 109 | 110 | # Guías para leyenda (ajustar ncol si es necesario para 8 años) 111 | guides(color = guide_legend(override.aes = list(size = 4, alpha=1), ncol = 4)) + 112 | 113 | 114 | # Formato de ejes 115 | scale_x_continuous(expand = expansion(mult=c(0.02, 0.05))) + # Empezar eje X en 0 116 | scale_y_continuous(expand = expansion(mult=c(0.02, 0.05))) + # Empezar eje Y en 0 117 | 118 | # Aplicar tema El País 119 | theme_el_pais(base_family = "Lato", base_size = 10) + # Usar Lato, ajustar tamaño base 120 | 121 | # Etiquetas y caption 122 | labs( 123 | title = plot_title, 124 | subtitle = plot_subtitle, 125 | x = "Ratio Mascotas (Perros+Gatos) / Menores 16", 126 | y = "Años de Renta Familiar (Vivienda 75m²)", 127 | caption = caption_day18 128 | ) + 129 | facet_wrap(Distrito ~ ., ncol = 4, scales = "free") 130 | 131 | 132 | # --- 6. Guardar Gráfico --- 133 | output_file <- file.path(output_path, "day_18_el_pais_pets_effort.png") 134 | ggsave( 135 | filename = output_file, 136 | plot = gg_day18, 137 | width = 1400, height = 1400, units = "px", dpi = 150, bg = bg_col 138 | ) 139 | 140 | message("Gráfico del Día 18 (El Pais - Pets vs Effort) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 141 | 142 | # --- Fin day_18_el_pais.R --- -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_5_uncertainties/day_28_inclusion/day_28.R: -------------------------------------------------------------------------------- 1 | # --- Day 28: Inclusion (Unemployment Rate Disparity & Uncertainty by Spanish Region) --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: INE - Encuesta de Población Activa) 4 | # Tasa de paro estimada por CCAA incluyendo Intervalo de Confianza del 95% 5 | # para visualizar disparidad territorial e incertidumbre de la estimación. 6 | 7 | # --- 1. Cargar Librerías --- 8 | library(ggplot2) 9 | library(data.table) 10 | library(yaml) 11 | library(showtext) 12 | library(ggtext) 13 | library(scales) 14 | library(lubridate) 15 | 16 | # --- 2. Cargar Configuración, Temas y Utilidades --- 17 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 18 | utils_file <- "R/30DayChartChallenge2025/utils.R" 19 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 20 | font_path_fa <- "fonts/fa-brands-400.ttf" 21 | output_path <- "R/30DayChartChallenge2025/plots/" 22 | 23 | # Verificar existencia de archivos y cargar 24 | source(themes_file) # Carga paletas y theme_week5_uncertainty 25 | source(utils_file) 26 | config <- read_yaml(config_file) 27 | 28 | # --- 3. Configurar Fuentes --- 29 | setup_fonts(fa_brands_path = font_path_fa) # Carga "Lato" 30 | 31 | # --- 4. Cargar y Preparar Datos EPA por CCAA --- 32 | 33 | data_file <- "R/30DayChartChallenge2025/data/epa_paro_ccaa.csv" 34 | 35 | if (!file.exists(data_file)) { 36 | stop("Archivo CSV de EPA por CCAA no encontrado en: ", data_file, 37 | "\nDescárgalo desde INE.es o busca la publicación adecuada.") 38 | } 39 | 40 | message("Cargando datos EPA desde: ", data_file) 41 | epa_dt <- data.table::fread(data_file, encoding = "Latin-1") # Ajusta sep, dec, skip si es necesario 42 | message("Datos EPA cargados. ", nrow(epa_dt), " filas iniciales.") 43 | print(head(epa_dt)) 44 | print(names(epa_dt)) 45 | 46 | 47 | # --- Limpieza y Preparación --- 48 | setnames(epa_dt, 49 | old = c("Edad", "Sexo", "Comunidades y Ciudades Autónomas", "Periodo", "Total"), 50 | new = c("Edad_Grp", "Sexo_Grp", "CCAA_Raw", "Periodo_Str", "Tasa_Paro"), 51 | skip_absent=TRUE) 52 | 53 | # Filtrar datos necesarios 54 | epa_clean_dt <- epa_dt[Edad_Grp == "Total" & Sexo_Grp == "Ambos sexos"] 55 | 56 | # Limpiar nombre CCAA (quitar código inicial) 57 | epa_clean_dt[, CCAA := trimws(sub("^[0-9]{2} ", "", CCAA_Raw))] 58 | 59 | # Convertir Periodo a Fecha (inicio del trimestre) 60 | epa_clean_dt[, Date := as.Date(zoo::as.yearqtr(Periodo_Str, format = "%YT%q"))] 61 | 62 | # Asegurar que Tasa_Paro es numérica (ya debería serlo si dec="," funcionó) 63 | epa_clean_dt[, Tasa_Paro := as.numeric(Tasa_Paro)] 64 | 65 | # Seleccionar columnas finales y quitar NAs 66 | epa_clean_dt <- epa_clean_dt[!is.na(Date) & !is.na(Tasa_Paro) & !is.na(CCAA), 67 | .(CCAA, Date, Rate = Tasa_Paro)] 68 | 69 | # Corregir algunos nombres de CCAA 70 | epa_clean_dt[, CCAA := fcase( 71 | CCAA == "Madrid, Comunidad de", "Madrid", 72 | CCAA == "Murcia, Región de", "Murcia", 73 | CCAA == "Navarra, Comunidad Foral de", "Navarra", 74 | CCAA == "Rioja, La", "La Rioja", 75 | CCAA == "Asturias, Principado de", "Asturias", 76 | CCAA == "Balears, Illes", "Balears", 77 | CCAA == "Total Nacional", "España", 78 | default = CCAA 79 | )] 80 | 81 | # --- Seleccionar CCAA para visualizar --- 82 | ccaa_seleccionadas <- c( 83 | "Andalucía", "Navarra", "Madrid", "País Vasco", "Castilla y León", "España" 84 | ) 85 | epa_plot_dt <- epa_clean_dt[CCAA %in% ccaa_seleccionadas] 86 | # Convertir a factor para leyenda consistente 87 | epa_plot_dt[, CCAA := factor(CCAA, levels = intersect(ccaa_seleccionadas, unique(CCAA)))] 88 | 89 | 90 | message("Datos EPA listos para graficar para: ", paste(levels(epa_plot_dt$CCAA), collapse=", ")) 91 | print(tail(epa_plot_dt)) 92 | 93 | # --- 5. Crear Gráfico de Líneas Comparativo --- 94 | 95 | # Definir textos 96 | epa_periodo_plot <- paste(min(year(epa_plot_dt$Date)), "-", max(year(epa_plot_dt$Date))) 97 | source_text_day28 <- paste0("Fuente: INE - Encuesta de Población Activa (EPA). Periodo: ", epa_periodo_plot) 98 | plot_title <- "Evolución de la Disparidad Territorial en el Paro (España)" 99 | plot_subtitle <- paste0("Tasa de paro trimestral estimada por CC.AA. seleccionadas.") 100 | 101 | # Generar caption 102 | caption_day28 <- generate_caption( 103 | day = 28, 104 | source_text = source_text_day28, 105 | config = config, 106 | color_text_source = "#000000", 107 | color_text_author = "#455A64" 108 | ) 109 | 110 | # Colores y tema 111 | bg_col <- "#FFFFFF" 112 | num_ccaa <- length(levels(epa_plot_dt$CCAA)) 113 | # Usar paleta week4_social o week5_uncertainty 114 | plot_colors <- challenge_pal("week4_social")(num_ccaa) # O "week5_uncertainty" 115 | names(plot_colors) <- levels(epa_plot_dt$CCAA) 116 | 117 | # Cambiar color para España 118 | plot_colors["España"] <- "#DE1D1A" 119 | 120 | # Line width 121 | l_width <- rep(1.1, num_ccaa) 122 | names(l_width) <- levels(epa_plot_dt$CCAA) 123 | l_width["España"] <- 1.4 124 | 125 | # Crear el gráfico de líneas 126 | gg_day28 <- ggplot(epa_plot_dt, aes(x = Date, y = Rate, color = CCAA, linewidth = CCAA, group = CCAA)) + 127 | geom_line(alpha = 0.85) + 128 | 129 | # Escala de colores manual 130 | scale_color_manual(values = plot_colors, name = NULL) + 131 | scale_linewidth_manual(values = l_width, name = NULL) + 132 | 133 | # Formato de ejes 134 | scale_y_continuous(labels = scales::label_percent(scale = 1), 135 | name = "Tasa de Paro Estimada (%)") + 136 | scale_x_date(date_breaks = "3 years", date_labels = "%Y", 137 | expand = expansion(mult=c(0.01, 0.01))) + 138 | 139 | # Aplicar tema Semana 5 140 | theme_week5_uncertainty(base_family = "Lato", base_size = 10) + 141 | 142 | # Leyenda 143 | guides(color = guide_legend(nrow = 1)) + # Ajustar columnas 144 | 145 | # Etiquetas y caption 146 | labs( 147 | title = plot_title, 148 | subtitle = plot_subtitle, 149 | x = "Año", 150 | caption = caption_day28 151 | ) + 152 | theme(legend.title = element_blank()) # Confirmar leyenda sin título 153 | 154 | # --- 6. Guardar Gráfico --- 155 | output_file <- file.path(output_path, "day_28_inclusion_epa_ts.png") 156 | ggsave( 157 | filename = output_file, 158 | plot = gg_day28, 159 | width = 1200, height = 1200, units = "px", dpi = 150, bg = bg_col 160 | ) 161 | 162 | message("Gráfico del Día 28 (Inclusion EPA TS) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 163 | 164 | # --- Fin day_28_inclusion_epa_ts.R --- -------------------------------------------------------------------------------- /R/30DayChartChallenge2025/category_4_timeseries/day_24_who/day_24.R: -------------------------------------------------------------------------------- 1 | # --- Day 24: WHO (data day) - DTP3 Vaccination Coverage in Spain --- 2 | # #30DayChartChallenge 2025 3 | # Autor: Michal Kinel (Datos: WHO Global Health Observatory) 4 | # Evolución de la cobertura de vacunación con DTP3 en niños de 1 año por grupo de ingresos del Banco Mundial. 5 | 6 | # --- 1. Cargar Librerías --- 7 | library(ggplot2) 8 | library(data.table) 9 | library(yaml) 10 | library(showtext) 11 | library(ggtext) 12 | library(scales) 13 | library(lubridate) 14 | 15 | # --- 2. Cargar Configuración, Temas y Utilidades --- 16 | themes_file <- "R/30DayChartChallenge2025/themes_30DCC2025.R" 17 | utils_file <- "R/30DayChartChallenge2025/utils.R" 18 | config_file <- "R/30DayChartChallenge2025/30DayChartChallenge2025.yml" 19 | font_path_fa <- "fonts/fa-brands-400.ttf" 20 | output_path <- "R/30DayChartChallenge2025/plots/" 21 | 22 | # Verificar existencia de archivos y cargar 23 | source(themes_file) 24 | source(utils_file) 25 | config <- read_yaml(config_file) 26 | 27 | 28 | # --- 3. Configurar Fuentes --- 29 | setup_fonts(fa_brands_path = font_path_fa) # Carga "Lato" 30 | 31 | # --- 4. Cargar y Preparar Datos de Cobertura Vacunal OMS --- 32 | 33 | data_url <- "https://srhdpeuwpubsa.blob.core.windows.net/whdh/DATADOT/INDICATOR/F8E084C_ALL_LATEST.csv" 34 | 35 | message("Cargando datos de cobertura vacunal desde: ", data_url) 36 | vacc_dt <- data.table::fread(data_url) 37 | 38 | if (nrow(vacc_dt) == 0) { 39 | stop("Problema en la lectura de los datos, revisa la URL.") 40 | } 41 | message("Datos cargados. ", nrow(vacc_dt), " filas iniciales.") 42 | 43 | 44 | # --- Limpieza y Preparación --- 45 | col_geo_name <- "GEO_NAME_SHORT" 46 | col_geo_type <- "DIM_GEO_CODE_TYPE" 47 | col_year <- "DIM_TIME" 48 | col_coverage <- "RATE_PER_100_N" 49 | 50 | # Verificar que las columnas existen 51 | required_cols <- c(col_geo_name, col_geo_type, col_year, col_coverage) 52 | if (!all(required_cols %in% names(vacc_dt))) { 53 | stop("El archivo CSV de WHO no contiene las columnas esperadas ('", col_year, "', '", col_coverage,"'). Revisa nombres.") 54 | } 55 | 56 | # Seleccionar, renombrar y asegurar tipos 57 | vacc_clean_dt <- vacc_dt[, .( 58 | Country = as.character(get(col_geo_name)), 59 | Geo_Type = as.character(get(col_geo_type)), 60 | Year = as.numeric(get(col_year)), 61 | Coverage_Pct = as.numeric(get(col_coverage)) # Ya debería ser % (0-100) 62 | )] 63 | 64 | # Filtrar NAs y ordenar 65 | vacc_clean_dt <- na.omit(vacc_clean_dt) 66 | setorder(vacc_clean_dt, Geo_Type, Country, Year) 67 | 68 | # Subset zona de interés 69 | selected_geo_type <- "WORLDBANKINCOMEGROUP" 70 | vacc_clean_dt <- vacc_clean_dt[Geo_Type == selected_geo_type] 71 | 72 | # Traducir grupos de ingresos 73 | vacc_clean_dt[, Income_Group := fcase( 74 | Country == "Low-income economies", "Bajo", 75 | Country == "Lower-middle-income economies", "Medio-Bajo", 76 | Country == "Upper-middle-income economies", "Medio-Alto", 77 | Country == "High-income economies", "Alto" 78 | )] 79 | 80 | # Income_Group como factor ordenado 81 | vacc_clean_dt[, Income_Group := factor(Income_Group, levels = c("Bajo", "Medio-Bajo", "Medio-Alto", "Alto"))] 82 | 83 | message("Datos de vacunación preparados. Rango: ", min(vacc_clean_dt$Year), "-", max(vacc_clean_dt$Year)) 84 | print(tail(vacc_clean_dt)) 85 | print(summary(vacc_clean_dt)) 86 | 87 | # --- 5. Crear Gráfico de Líneas (Cobertura Vacunal) --- 88 | 89 | # Definir textos 90 | source_text_day24 <- "Fuente: WHO/UNICEF Estimates (via WHO Global Health Observatory)" 91 | plot_title <- "Cobertura Vacunal con DTP3 por grupo de ingresos del Banco Mundial" 92 | plot_subtitle <- paste0("Porcentaje estimado de niños/as de 1 año vacunados con 3 dosis de DTP.\nPeriodo: ", 93 | min(vacc_clean_dt$Year), "-", max(vacc_clean_dt$Year), ". Línea objetivo: 95%.") 94 | 95 | # Generar caption 96 | caption_day24 <- generate_caption( 97 | day = 24, 98 | source_text = source_text_day24, 99 | config = config, 100 | color_text_source = "#5c5c5c", 101 | color_text_author = "#757de8" 102 | ) 103 | 104 | # Colores y tema 105 | bg_col <- "#F2F2F2" 106 | num_groups <- length(levels(vacc_clean_dt$Income_Group)) 107 | color_map_income_group <- setNames( 108 | challenge_pal("week4_social")(num_groups), # Usa tu paleta social 109 | levels(vacc_clean_dt$Income_Group) # Asigna a los niveles del factor 110 | ) 111 | target_color <- challenge_palettes$week4_social['pink'] # Rosa para línea objetivo 112 | 113 | # Crear el gráfico de línea 114 | gg_day24 <- ggplot(vacc_clean_dt, aes(x = Year, y = Coverage_Pct, color = Income_Group, group = Income_Group)) + 115 | 116 | # Línea objetivo (ej. 95%) 117 | geom_hline(yintercept = 95, linetype = "dashed", color = target_color, linewidth = 1, alpha=0.8) + 118 | annotate("text", x = min(vacc_clean_dt$Year), y = 96, label = "Objetivo 95%", 119 | hjust = 0, vjust = 0, size = 4.5, color = target_color, family="Lato", fontface="italic") + 120 | 121 | # Línea de cobertura 122 | geom_line(linewidth = 1.3, alpha = 0.9) + 123 | geom_point(size = 2, shape=21, fill=bg_col, stroke=0.6) + 124 | 125 | # Escala de colores manual 126 | scale_color_manual(values = color_map_income_group, name = "Grupo de Ingresos") + 127 | 128 | # Formato de ejes 129 | scale_y_continuous(limits = c(0, 100), # Eje Y de 0 a 100% 130 | labels = scales::label_percent(scale = 1), 131 | expand = expansion(mult=c(0, 0.05)), 132 | name = "Cobertura Estimada (%)") + 133 | scale_x_continuous(breaks = seq(min(vacc_clean_dt$Year), max(vacc_clean_dt$Year), 3)) + 134 | 135 | # Aplicar tema 136 | theme_week4_social(base_family = "Lato", base_size = 10) + 137 | 138 | # Etiquetas y caption 139 | labs( 140 | title = plot_title, 141 | subtitle = plot_subtitle, 142 | x = "Año", 143 | # Y ya definido en scale_y_continuous 144 | caption = caption_day24 145 | ) + 146 | theme(legend.title = element_text(hjust = 0.5)) 147 | 148 | # --- 6. Guardar Gráfico --- 149 | output_file <- file.path(output_path, "day_24_who_vaccination_esp.png") 150 | ggsave( 151 | filename = output_file, 152 | plot = gg_day24, 153 | width = 1200, height = 1200, units = "px", dpi = 150, bg = bg_col # Apaisado 154 | ) 155 | 156 | message("Gráfico del Día 24 (WHO Vaccination) guardado en: ", normalizePath(output_file, mustWork = FALSE)) 157 | 158 | # --- Fin day_24_who_vaccination --- --------------------------------------------------------------------------------