{ "version": "https://jsonfeed.org/version/1", "title": "El Blog de pmoracho", "description": "El Blog de pmoracho...", "home_page_url": "https://pmoracho.github.io/", "feed_url": "https://pmoracho.github.io/feed.json", "user_comment": "This feed allows you to read the posts from this site in any feed reader that supports the JSON Feed format.", "items": [ { "id": "https://pmoracho.github.io/blog/2025/06/20/nuevo-kindle/", "url": "https://pmoracho.github.io/blog/2025/06/20/nuevo-kindle/", "title": "Nuevo Kindle misma vida", "content_html": "

\"kindle.jpg\"

\n\n

Doce años después desde Mi vida después del Kindle tengo uno nuevo de estos\n“aparatitos”. Podría seguir usando el mismo Paperwhite 2da generación por\notros tantos años más, la batería aun me aguanta un par de semanas haciendo un\nuso casi diario, no llegué aún a completar los 2 gigabytes de almacenamiento, y\nla pantalla sigue siendo una maravilla para leer, la rutina de descargar libros,\npasarlos por *Calibre y luego al dispositivo y leerlos no ha cambiado en\nnada. Pero regalo tan especial no se puede rechazar, y me he hecho con un\nKindle Paperwhite 12va generación.

\n\n

¿Vale la pena?

\n\n

Si y No. Vamos por partes:

\n\n\n\n

A ver, creo que no hubiese cambiado de Kindle si no fuera por el regalo, ya que\nel Paperwhite 2da generación sigue siendo un dispositivo excelente para leer. Ahora\nbien, el nuevo Kindle es mejor en casi todos los aspectos, y francamente\ndisfruto mucho de la experiencia de lectura en este nuevo dispositivo.

\n\n

Los molestos anuncios

\n\n

Cuando uno compra un kindle en Latinoamérica a un revendedor, lo más habitual es\nque la que obtengas sea la versión con anuncios, que son esos banners que\naparecen en la pantalla de bloqueo y en la tienda de libros. En mi caso, me\nmolestan y mucho. Lamentablemente hace tiempo que Amazon no permite\ndesactivarlos de forma gratuita, y hay que pagar una tarifa para eliminarlos,\nunos 20 dólares. Hacer esto tampoco es tan sencillo, el truco es el siguiente:

\n\n\n\n

Si no se hace esto la opción de desactivar los anuncios, si bien aparece, no\nfunciona, da un error no muy claro y no se pueden desactivar.

\n\n

¿Qué odio del Kindle?

\n\n

Poco, solo diría lo cerrado que es este dispositivo y su cubierta antiadherente\nque se degrada con el tiempo y se vuelve pegajosa.

\n\n

Enlaces interesantes

\n\n\n\n", "date_published": "2025-06-20T00:00:00-03:00" }, { "id": "https://pmoracho.github.io/blog/2022/12/21/linux-mint-21.1-en-lenovo-ideapad/", "url": "https://pmoracho.github.io/blog/2022/12/21/linux-mint-21.1-en-lenovo-ideapad/", "title": "Instalación y configuración de Linux Mint 21.1 en una Ideapad 540", "content_html": "

Antes que nada

\n\n

Copia de seguridad de home

\n\n

Instalación

\n\n\n\n

Cuidado con las particiones, en mi caso

\n\n\n\n

Formateamos instalación anterior, nos gusta comenzar de cero.

\n\n

Wifi

\n\n

Maravillosamente esta versión ahora si detecta la placa wifi, en las instalación se nos pide la contraseña y ya queda configurada.

\n\n

Post-instalación

\n\n

A continuación la lista de cosas que hacemos luego de instalar el equipo.

\n\n
    \n
  1. Habilitar el modo Legacy para las teclas de función.
  2. \n
\n\n

El comportamiento por defecto de las teclas F1..F12 unicamente se activa si\ncombinamos con la tecla Fn. Esto es posible modificarlo desde la BIOS, que de\npaso, se entra presionando F2, luego simplemente buscar el ítem “Hot Key”

\n\n
    \n
  1. \n

    Actualizar el sistema

    \n\n
     sudo apt update && sudo apt upgrade -y\n
    \n
  2. \n
  3. \n

    Instalar codecs multimedia (Si no lo hicimos en la instalación inicial)

    \n\n
     sudo apt install mint-meta-codecs\n
    \n
  4. \n
  5. Crear un snapshot del sistema con timeshift
  6. \n
  7. Deshabilitar aplicaciones que se cargan al inicio del sistema
  8. \n
  9. Habilitar y configurara el firewall
  10. \n
  11. \n

    Limpiar el sistema

    \n\n
     sudo apt autoclean\n sudo apt clean\n sudo apt autoremove\n
    \n
  12. \n
\n\n

Eliminando lo innecesario

\n\n

En lo personal nunca le encontré utilidad al servidor [avahi-daemon][avahi],\npor lo que suelo eliminarlo de las instalaciones

\n\n
sudo apt remove avahi-daemon\nsudo apt remove avahi-utils\nsudo apt remove libnss-mdns\n
\n\n

Cuidado: hay muchos otros paquetes avahi*, que no deben ser eliminados\npor que son dependencias del sistema

\n\n

Eliminar tipos de letras innecesarios

\n\n
sudo apt-get remove \"fonts-kacst*\" \"fonts-khmeros*\" fonts-lklug-sinhala fonts-guru-extra \"fonts-nanum*\" fonts-noto-cjk \"fonts-takao*\" fonts-tibetan-machine fonts-lao fonts-sil-padauk fonts-sil-abyssinica \"fonts-tlwg-*\" \"fonts-lohit-*\" fonts-beng-extra fonts-gargi fonts-gubbi fonts-gujr-extra fonts-kalapi \"fonts-samyak*\" fonts-navilu fonts-nakula fonts-orya-extra fonts-pagul fonts-sarai \"fonts-telu*\" \"fonts-wqy*\" \"fonts-smc*\" fonts-deva-extra fonts-sahadeva\nsudo dpkg-reconfigure fontconfig\n
\n\n

Audio decente

\n\n

Este equipo tiene según su especificaciones, audio DOLBY, por lo que\nsi lo quería aprovechar al máximo, seguí las recomendaciones de esta\nrespuesta. La idea entonces:

\n\n
    \n
  1. \n

    Instalar PulseEffects:

    \n\n

    sudo apt-get install pulseeffects

    \n
  2. \n
  3. \n

    Instalar estos presets

    \n\n

    bash -c “$(curl -fsSL https://raw.githubusercontent.com/JackHack96/EasyEffects-Presets/pulseeffects/install.sh)”

    \n
  4. \n
  5. \n

    Configurar el Convolver, y seleccionar el preset:

    \n\n
    \n

    Dolby ATMOS ((128K MP3)) 1.Default.irs

    \n
    \n
  6. \n
  7. \n

    Disfrutar la diferencia, el audio es notablemente mejor y sobre todo con un volumen superior.

    \n
  8. \n
\n\n

Gestores de sesiones

\n\n

Por defecto mint usa lightdm, pero puede usar gdm o kdm:

\n\n
sudo dpkg-reconfigure lightdm\nsudo dpkg-reconfigure gdm3\nsudo dpkg-reconfigure kdm\n
\n\n

Desarrollo

\n\n

Instalar herramientas básicas de desarrollo:

\n\n
sudo apt-get install build-essential gdb git\nsudo apt-get install docker.io\n
\n\n

Instalar R y RStudio (últimas versiones):

\n\n
# Agregamos certificados para el repositorio\nsudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9\n# Agregamos el repositorio\nsudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/'\nsudo apt update\nsudo apt install r-base\n\n# Instalar RStudio\ncd ~/Descargas\nwget https://download1.rstudio.org/desktop/bionic/amd64/rstudio-2021.09.0-351-amd64.deb\n
\n\n

Configurar python3 como el default:

\n\n
sudo apt update\nsudo apt install python-is-python3\n
\n\n

git

\n\n

Configurar desde mi repositorio de configuraciones:

\n\n
ln -s ~/Proyectos/environment/.gitconfig ~/.gitconfig\n
\n\n

Manejo de credenciales:

\n\n
sudo apt install libsecret-1-0 libsecret-1-dev\nsudo make --directory=/usr/share/doc/git/contrib/credential/libsecret\n\ngit config --global credential.helper\n/usr/share/doc/git/contrib/credential/libsecret/git-credential-libsecret\n
\n\n

Visual Studio Code

\n\n
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg\nsudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/\nsudo sh -c 'echo \"deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/packages.microsoft.gpg] https://packages.microsoft.com/repos/vscode stable main\" > /etc/apt/sources.list.d/vscode.list'\n\nsudo apt-get install apt-transport-https\nsudo apt-get update\n
\n\n

GIMP

\n\n

Configurar:

\n\n
ln -s ~/Proyectos/environment/.config/GIMP/2.10 ~/.config/GIMP/2.10\n
\n\n

Multimedia

\n\n

Instalar *Stremio** desde paquete .deb

\n\n
cd ~/Descargas\n\nwget \"https://dl.strem.io/shell-linux/v4.4.159/stremio_4.4.159-1_amd64.deb\"\nwget http://ftp.osuosl.org/pub/ubuntu/pool/multiverse/f/fdk-aac/libfdk-aac1_0.1.6-1_amd64.deb\nwget http://nz2.archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1l-1ubuntu1.2_amd64.deb\n\nsudo dpkg -i libssl1.1_1.1.1l-1ubuntu1.2_amd64.deb\nsudo dpkg -i libfdk-aac1_0.1.6-1_amd64.deb\nsudo dpkg -i stremio_4.4.159-1_amd64.deb\n
\n\n

Herramientas

\n\n

Descargar e instalar chrome desde su página

\n\n
sudo apt-get install keepassx\nsudo apt-get install gimp\nsudo apt-get install mc\nsudo apt-get install inkscape\nsudo apt-get install k3b\nsudo apt-get install deluge\nsudo apt-get install numlockx\nsudo apt install xdotool\nsudo apt install pdftk\n
\n\n

Configuraciones:

\n\n
ln -s ~/Proyectos/environment/.config/mc ~/.config/mc\n
\n\n

bin local

\n\n
mkdir ~/bin\ncp ~/Proyectos/environment/bin/* ~/bin\n
\n\n

Kitty

\n\n
curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin\ncp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications/\nsed -i \"s|Icon=kitty|Icon=/home/$USER/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g\" ~/.local/share/applications/kitty.desktop\n
\n\n

Configuración:

\n\n
ln -s ~/Proyectos/environment/.config/kitty ~/.config/kitty\n
\n\n

Double Commander

\n\n

Descargar archivo .tar.xz desde la página del proyecto.\nDescomprimir en carpeta bin local y armar un atajo en el escritorio. La\nconfiguración la tengo en un repo de GitHub.

\n\n

Configuración:

\n\n
ln -s ~/Proyectos/environment/doublecmd ~/.config/doublecmd\n
\n\n

Ajustar doublecmd para que tome la configuración de usuario y no la de la carpeta de los binarios

\n\n

Rclone y Rclonebrowser

\n\n

Imposible no tener estas herramientas si tenés espacio en la nube que querés\nmontar como un disco cualquiera.

\n\n
apt-get install rclone\n
\n\n

Uso un fork propio del Rclonebrowser:

\n\n
git clone https://github.com/pmoracho/RcloneBrowser.git\nsudo apt update && sudo apt -y install git g++ cmake make qtdeclarative5-dev\ncd RcloneBrowser\nmkdir build && cd build\ncp build/rclone-browser ~/bin\n
\n\n

Configuración:

\n\n
ln -s ~/Proyectos\n
\n\n

Docky

\n\n

Hace años que uso este Dock, lamentablemente es un proyecto que no tiene\nmantenimiento desde hace varios años, por lo que cada vez se hace más complicado\ninstalarlo. En el caso de Mint 20.2, se instala con algunos paquetes\nantiguos que eventualmente podrían generar algún conflicto:

\n\n

Descargamos e instalamos las librerías:

\n\n
mkdir -p ~/Descargas/docky\ncd ~/Descargas/docky\n\nwget -c http://archive.ubuntu.com/ubuntu/pool/universe/g/gnome-sharp2/libgconf2.0-cil_2.24.2-4_all.deb\nwget -c http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/multiarch-support_2.27-3ubuntu1_amd64.deb\nwget -c http://archive.ubuntu.com/ubuntu/pool/universe/libg/libgnome-keyring/libgnome-keyring-common_3.12.0-1build1_all.deb\nwget -c http://archive.ubuntu.com/ubuntu/pool/universe/libg/libgnome-keyring/libgnome-keyring0_3.12.0-1build1_amd64.deb\nwget -c http://archive.ubuntu.com/ubuntu/pool/universe/g/gnome-keyring-sharp/libgnome-keyring1.0-cil_1.0.0-5_amd64.deb\n\nsudo apt-get install ./*.deb\n
\n\n

Luego instalamos docky:

\n\n
wget -c http://archive.ubuntu.com/ubuntu/pool/universe/d/docky/docky_2.2.1.1-1_all.deb\nsudo apt-get install ./docky_2.2.1.1-1_all.deb\n
\n\n

Fuente: https://askubuntu.com/a/1237413/1050086

\n\n

O bien podemos intentar compilar docky desde el repositorio descargando los\nfuentes desde: https://launchpad.net/docky, pero hasta ahora este camino no es\nmás que un infierno de dependencias incumplidas.

\n\n

Bash

\n\n

Agregamos customización personal al .bashrc

\n\n
###\n### Personal Customization\n###\nif [ -f ~/.bashrc.personal ]; then\n    . ~/.bashrc.personal\nfi\n
\n\n

Apuntamos el .bashrc.personal al que ya tengo en git.

\n\n
ln -s Proyectos/environment/.bashrc.personal .bashrc.personal\n
\n\n

Instalamos qfc

\n\n
git clone https://github.com/pindexis/qfc $HOME/.qfc\n
\n\n

Instalamos fzf - fuzzy file finder

\n\n

fzf is a general-purpose command-line fuzzy finder.

\n\n
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf\n~/.fzf/install\n
\n\n

Atajos de teclado

\n\n

Me resulta muy cómodo asociar combinaciones de teclas a mi script run-or-raise\nque básicamente ejecuta un comando en caso de que no esté corriendo, o\neventualmente reactiva la ventana del mismo. Estos son mis atajos:

\n\n
# Alt-1\n/home/pmoracho/bin/run-or-raise  kitty.kitty /home/pmoracho/bin/kitty --start-as=fullscreen\n# Alt-2\n/home/pmoracho/bin/run-or-raise google-chrome.Google-chrome /usr/bin/google-chrome\n# Alt-4\n/home/pmoracho/bin/run-or-raise code.Code /usr/bin/code\n# Alt-5\n/home/pmoracho/bin/run-or-raise doublecmd.Doublecmd /home/pmoracho/bin/doublecmd/doublecmd\n
\n\n

Problemas

\n\n
sudo apt remove casper -y\nsudo systemctl unmask casper-md5check\nsudo rm /etc/systemd/system/casper.service\nsudo rm /etc/systemd/system/multi-user.target.wants/casper-md5check.service\nsudo rm /etc/systemd/system/final.target.wants/casper.service\nsudo systemctl daemon-reload\nsudo systemctl reset-failed\n
\n\n

Ahorrar algunos segundos:

\n\n
sudo systemctl disable NetworkManager-wait-online.service\nsudo systemctl mask NetworkManager-wait-online.service\n
\n\n

Configuración desde la nube

\n\n
# Borramos archivos y carpetas para hacer enlaces\nrm ~/.bashrc.personal\nrm ~/.face\nrm ~/.gitconfig\nrm -rf ~/.config/kitty\nrm -rf ~/.config/mc\nrm -rf ~/.config/backintime\nrm -rf ~/.config/compiz-1\nrm -rf ~/.config/doublecmd\nrm -rf ~/.config/keepassx\nrm -rf ~/.config/rclone\nrm -rf ~/.config/rclone-browser\n\n# Clonamos repo\nmkdir ~/Proyectos\ncd ~/Proyectos\ngit clone https://github.com/pmoracho/environment.git\n\n\nln -s ~/Proyectos/environment/.bashrc.personal ~/.bashrc.personal\nln -s ~/Proyectos/environment/.face ~/.face\nln -s ~/Proyectos/environment/.gitconfig ~/.gitconfig\nln -s ~/Proyectos/environment/.config/kitty ~/.config/kitty\nln -s ~/Proyectos/environment/.config/mc ~/.config/mc\nln -s ~/Proyectos/environment/.config/backintime ~/.config/backintime\nln -s ~/Proyectos/environment/.config/compiz-1/ ~/.config/compiz-1\nln -s ~/Proyectos/environment/.config/compiz-1 ~/.config/compiz-1\nln -s ~/Proyectos/environment/.config/doublecmd ~/.config/doublecmd\nln -s ~/Proyectos/environment/.config/keepassx/ ~/.config/keepassx\nln -s ~/Proyectos/environment/.config/rclone/ ~/.config/rclone\nln -s ~/Proyectos/environment/.config/rclone-browser/ ~/.config/rclone-browser\n
\n\n

Docker

\n\n
sudo groupadd docker\nsudo usermod -aG docker ${USER}\nsudo chmod 666 /var/run/docker.sock\ndocker run hello-world\n
\n\n", "date_published": "2022-12-21T00:00:00-03:00" }, { "id": "https://pmoracho.github.io/blog/2021/12/05/mis-recetas/", "url": "https://pmoracho.github.io/blog/2021/12/05/mis-recetas/", "title": "Mis recetas", "content_html": "

Tortillas para fajitas

\n\n\n\n

Procedimiento:

\n\n

Combinar todo de la forma tradicional, amasar hasta lograr un bollo liso, luego\ndividir todo en 10 bollitos y dejar descansar 30 minutos. Luego pasar por\npalote cada bollo hasta que quede una tortilla bien finita, inmediatamente\ncocinar sobre sarten bien caliente, dar vuelta ni bien empieza a tostarse.

\n\n

Tips:

\n\n\n\n

Wok de pollo al estilo sichuan

\n\n\n\n

Procedimiento:

\n\n

Cortar el pollo en cubos. Sazonar el almidón de maíz con la sal y las especial.\nEmpolvar el pollo con esta mezcla. En otro recipiente unir el caldo con el\nvinagre, la salsa de soja, el azúcar, el aceite de sésamo y el vino de arroz;\nreservar. Calentar un wok con el aceite neutro. Freír los trazos de pollo, por\ntandas, hasta que se doren bien. Retirarlos con espumadera a mediada que estén\nlistos. Al finalizar la operación, descartar la mayor parte del aceite y dejar el\nwok sólo 2 o 3 cucharadas. Echar en el wok el ajo picado, los chiles sin\nnervaduras ni semillas, también picados, y el jengibre. Dorarlos a fuego fuerte\nsin dejar de revolver. Agregar las cebollas de verdeo cortadas en trozos largos y\nla pimienta sichuan. Cuando todo haya tomado color, desglasar este fondo con la\nmezcla de caldo y dejar que hierva. Añadir el almidón de mandioca disuelto en 1\npocillo de agua y revolver para que se integren los sabores. En cuanto la salsa\ncomience a espesar, agregar el pollo frito y mezclar todo. Servir de inmediato,\ncon arroz blanco.

\n\n

Pollo saltado con fideos al wok

\n\n\n\n

Pollo Shanghai

\n\n

Procedimiento:

\n\n

Trozar el pollo y macerar en salsa de soja, 1/2 vaso de vino, jengibre, sal,\npimienta y un diente de ajo cortado groseramente. Llevar a la heladera por una\nhora.Rehogar en el wok con aceite y manteca el puerro, la cebolla y los dos\ndientes de ajo restantes picados.Escurrir el pollo e introducirlo en el wok.\nDorarlo y retirar cuando esté listo (sólo el pollo). Sobre el jugo de cocción van\nlas zanahorias, el morrón y la cebolla en gajos. Agregar el 1/2 vaso de vino\nrestante y un poco más de salsa de soja. Mientras tanto hervir los fideos en agua\ncon un chorrito de aceite. Por otro lado se vuelve al wok el pollo con los\nchampignones, camarones y brotes de soja. Si está demasiado seco se agrega un\nchorrito de agua y aceite. Salpimentar y cuando los fideos están listos agregar\nal wok y cocinar unos minutos.

\n\n

Pollo Shanghai

\n\n\n\n

Procedimiento:

\n

Mezclar en una olla: 8 muslitos de pollo, 2 cucharadas de salsa de soya, 2\ncucharadas de Jerez, 1 pizca de azúcar, sal, jengibre, pimienta. Dejar reposar.\nCocinar en 50 cc. de aceite: 1/2kg.de champiñones cortados por la mitad con sal y\n1 cebolla picada. Reservar calientes. Con el aceite que queda de hacer los\nchampiñones, se cocina el pollo con los demás ingredientes durante 10´ a fuego\nfuerte. Bajar la temperatura y hacer tapado otros 10 minutos más. Añadir los\nchampiñones, 2 tazas de tomate casero y 150 g de guisantes. Calentar todo y\nservir de inmediato.

\n\n

Rabas de pollo

\n\n\n\n

Procedimiento:

\n\n

Cortar las pechugas en tiras de 1 cm. de ancho. En un cuenco amplio, poner la\ncebolla picada y la salsa de soja, remover y añadir las tiras de pollo. Remover a\nfondo, tapar con film transparente y meter al frigorífico durante 1 hora o más.\nSacar las tiras de la marinada, quitar parte de la cebolla adherida, pasarlas por\nharina y freírlas en abundante aceite muy caliente hasta que estén doradas y\nligeramente crujientes (el aspecto será el de unas “rabas” o calamares). Cuando\nse hayan frito todas las tiras, añadir a la sartén la marinada de cebolla y salsa\nde soja del cuenco y freír hasta que la cebolla esté bien dorada. Servir junto\ncon las tiras fritas. Acompañar de una ensalada o de pasta.

\n\n

Pollo Mediterránea

\n\n\n\n

Procedimiento:

\n\n

El pollo se troza y deshuesa. El apio de troza no muy chico. Se pone a macerar el\npollo con el vinagre, las pasas y la sal, pimienta y la nuez moscada de acuerdo\nal gusto. El vinagre debe cubrirlos, dejarlo así por 5 horas. En una sartén\ncalentar la mantequilla y ponerle las nueces, dorarlas bien, y agregar el azúcar.\nUna vez que estén algo glaseadas agregar el pollo y su maceración, enseguida\naumentarles el apio y la cebollita china picada, se mueve y se deja cocinar hasta\nque el pollo tome un color dorado. Se rectifica la sazón según le falte sal o un\npoco de vinagre. Se sirve acompañado de arroz blanco.

\n\n

Muslos de pollo al horno

\n\n\n\n

Procedimiento:

\n\n

En una bandeja de horno aceitada colocamos todos los muslos y contramuslos de\npollo previamente salpimentados (sal y pimienta). En un mortero machacaremos un\ndiente de ajo por cada pieza de pollo y añadimos un vaso grande de vino blanco y\nun chorro de aceite de oliva. Con esta mezcla pintaremos (con pincel o\ncucharilla) una a una cada pieza de pollo y el resto lo pondremos en el fondo de\nla fuente. Metemos la bandeja al horno que ya habremos precalentado anteriormente\na una temperatura de unos 180º y seleccionada la fuente de calor inferior y\nsuperior. Dejamos que se vaya haciendo por espacio de unos 40 ó 50 minutos, (Los\ntiempos van a variar en función del tipo de horno y la cantidad o tamaño de la\ncarne). De vez en cuando (sobre 10-15 minutos) regamos por encima con su propia\nsalsa. Una vez tengamos el pollo casi listo tendrá un tono dorado, en caso\ncontrario o simplemente porque deseemos darle una textura un poco más crujiente,\npondremos solamente el grill del horno y subiremos la bandeja a la zona alta del\nmismo para que tome ese tono tostado característico y tan delicioso de los\nasados. No os paséis que se os secará. Esto evidentemente es a criterio y gusto\nde cada uno, para mí es imprescindible hacerlo en todos mis asados. Podemos\nservirlo con una guarnición de ensalada (lechuga, tomate, brotes de soja, etc.),\ncon verduras salteadas, patatas asadas con sal, incluso con un arroz blanco y\npasa a ser un primer plato.

\n\n

Pollo con salsa fácil

\n\n\n\n

Procedimiento:

\n\n

Salpimentar los trocitos de pollo (o filetes) y freir en aceite (doraditos).\nReservar en una cacerola. En el mismo aceite o aceite nuevo freir la cebolla\ncortada en cuadraditos (brunoise) , cuando esté casi sofrita agregar ´los\ntrocitos de jamón y mas tarde los champiñones, cuando estos hayan soltado el\nagua, echar todo en la cacerola encima del pollo. En un mortero machacar los ajos\ny el perejil y echar sobre el pollo y sofrito, aclarar el mortero con vino Echar\nvino en la cacerola y agua (doble de vino que de agua) cubriendo todo. y poner a\ncocer lentamete. Cuando el pollo esté tierno y la salsa espesita se puede comer.\nNo agregar sal al caldo es suficiente con la que lleva el pollo y la que suelta\nel jamón

\n\n

Pollo al horno

\n\n\n\n

Procedimiento:

\n\n

Tomá la fuente del horno y tirale aceite hasta que quede todo cubierto por una\nfina capa. Salá los muslos de pollo de cada lado y tiralos arriba del aceite con\nla piel para abajo. Pelá y cortá las dos cebollas en pedacitos chiquitos o como\nte guste y tirá todo alrededor de los muslos y entre ellos. Poné todo en el horno\na mas o menos 220 grados durante 20 minutos, mientras, andá pelando y cortando\nlas papas. Una vez pasados los 20 minutos, tirale un poco de aceite a las papas y\nrevolve para que queden todas bañadas, abri el horno, da vuelta los muslos y tira\ntodas las papas encima y por entre los muslos. Dejá todo cocinandose otros 20\nminutos abriendo cada tanto para girar las papas y ver como anda todo. Listo el\npollo.

\n\n

Pollo a la miel

\n\n\n\n

Procedimiento:

\n\n

Precalentá el horno a unos 200º C. Lo primero a preparar es el aderezo con el que untaremos la preparación y dará sabor a la guarnición de patatas. Para ello mezcla la salsa de soja, el ketchup, la miel, el aceite y el vinagre; remueve bien hasta lograr una preparación homogénea. Reserva. Toma una fuente para horno, cúbrela con papel de aluminio ( asegúrate de disponer el lado brillante hacia abajo) y vierte la mitad del aderezo por encima. Coloca los muslos de pollo, y agrega sal a tu gusto espolvoreando por encima con el ajo en polvo. Hornear unos 20 minutos, retira y agrega las rodajas de patatas bañando con el resto del aliño. Termina de hornear hasta que los muslos estén hechos y dorados. Vigila cada poco rato, ya que los aliños con azúcar o miel -como éste- suelen quemarse prematuramente con facilidad.

\n\n

Pollo a la miel 2

\n\n\n\n

Procedimiento:

\n\n

Comienza lavando el pollo muy bien en su interior, sécalo bien con papel de cocina y luego quítale el exceso de grasa. Colócalo en una placa de horno y condiméntalo con sal y pimienta a gusto, no te excedas demasiado porque la soja que le vas a agregar luego es bastante salada. Ahora coloca el ramito formado por las hierbas en el interior del pollo. En un recipiente mezcla la miel, la soja y el caldo de aves. Rocía todo el pollo con esta mezcla, no uses toda la mezcla guarda un poco. Luego cubre el pollo con trozos de mantequilla y llévalo a cocinar en un horno moderado, a 180° durante 40 minutos aproximadamente. Cada 15 minutos vuelve a rociar con la mezcla de miel, dándolo vuelta. Así lograrás una cocción pareja. Para la salsa, coloca el jugo que quedo de la cocción del pollo y colócalo en una cacerola pequeña. Hierve hasta que reduzca un poco. Pruébalo y si deseas agrégale un poco de pimienta. Ahora sí ya esta listo para salsear el pollo.\nPuedes acompañar esta receta con puré, patatas, verduras salteadas, etc.

\n\n

Bifes de pollo a la cerveza con ensalada de remolachas

\n\n\n\n

Procedimiento:

\n\n

Ensalada: hervimos 2 remolachas, y 3 huevos, cortamos los cherrys en 2 o 3\npartes. Pelamos y cortamos en cubos la remolacha. Pelamos y cortamos en cubos los\nhuevos. Mezclamos todo en un bol y condimentamos con sal, pimienta y aceite de\noliva, mezclamos bien y reservamos. Bifes de pollo a la cerveza: cortamos las\nsupremas en bifecitos, colocamos un poco de aceite de oliva en la sartén y\nrehogamos el ajo picado, añadimos el pollo y dejamos dorar de un lado. Salamos\nagregamos el cebollin picado y damos vuelta los bifes. En ese momento\nsalpimentamos, y ponemos la nuez moscada y el orégano. Cocinamos por unos minutos\nhasta dorar el otro lado y cuando se esté secando añadimos la cerveza. Bajamos el\nfuego y dejamos espesar hasta caramelizar. Servir 2 o 3 piezas de pollo con un\npoco de la verdura cocida (verdeo y ajo) y con una porción de ensalada.

\n\n

Guiso de Lentejas

\n\n\n\n

Procedimiento:

\n\n

Dejamos la lenteja en remojo durante 8 horas por lo menos (incluso toda la\nnoche). Desechamos el agua de remojo, que tiene un exceso de hierro, y las\npasamos a una cacerola. Cubrimos con abundante agua (el doble de agua que de\nlentejas). Llevamos al fuego y dejamos hervir hasta que estén tiernas (morder una\npara probar), retiramos y dejamos reposar.

\n\n
    \n
  1. \n

    En una cacerola grande colocamos el aceite, el ajo, las cebollas y los pimientos, ponemos a rehogar 5 minutos.

    \n
  2. \n
  3. \n

    Luego agregamos la carne y el chorizo, dejamos cocinar 2 minutos y agregamos el tomate. Condimentamos.

    \n
  4. \n
  5. \n

    Cubrimos con agua hasta tapar todo (cuidado con la cantidad de sal que agreguemos porque los chorizos colorados suelen ser salados). Tapamos y dejamos cocinar durante una hora.

    \n
  6. \n
  7. \n

    Luego agregamos el zapallo, las papas y las batatas, volvemos a cubrir con agua si fuera necesario. Dejamos cocinar durante 7 minutos.

    \n
  8. \n
  9. \n

    Agregamos la lenteja, revolvemos bien y dejamos cocinar 5 a 10 minutos más para que se mezcle todo, si es necesario agregamos agua. Consideremos que a partir de este momento el agua que se va a consumir es muy poca, o sea que la cantidad depende del gusto de cada uno, si lo prefiere más o menos espeso.

    \n
  10. \n
\n\n

Guiso de mondongo

\n\n\n\n

Procedimiento:

\n\n

El mondongo de carnicería que sea bien finito. Desgrasarlo, se lo puede dejar en\nagua con algo de vinagre toda la noche. Luego se pone a hervir alrededor de una\nhora hasta que esté blando. Se deja enfriar y se corta en tiritas de 2 cm de\nancho y 4 de largo. Cortamos cebollas, blancas y verdes y morrones colorados,\ntodo chiquitos, y unos dientes de ajo. Se frien en aceite, se salpimientan y se\nle agrega pimentón rojo del bueno. Se le agrega huesitos de chancho cortadas en\ntrozos pequeños. si no tenés patitas de chancho podés reemplazarla por panceta\nsalada, en ese caso no agregar sal a la fritura. Luego cortamos 3 tomates peritas\nno muy maduros en cubitos pequeños, y agregamos hasta tener una salsa poderosa.\nLe agregamos un vasito de jugo de zanahorias o rodajas de zanahorias, como más te\nguste. La salsa debe ser abundante. Ponemos a hervir un litro de agua por\nseparado. Cuando la salsa esté lista agregamos los garbanzos, el mondongo y el\nagua, suficiente para tapar todo. ponemos a fuego lento.- Vamos revolviendo con\ncuchara de madera, y vamos probando el sabor, el cual dependerá del sabor y\ncantidad de nuestra salsa… si hace falta podemos agregarle un cubito de carne o\nahora esos saborizados. Diez minutos antes de que se cocine bien, agregamos una\npapas cortadas en cubitos medianos previamente hervidas con apenas un hervor, no\ndejen que se hiervan mucho porque se hacen pure. Ponemos 10 minutos más y luego a\ncomer.

\n\n

Consejos: Salsa muy suave y con todos los ingredientes cortados muy muy\nchiquititos eso hace que no sea pesado, es sólo para saborizar y amenizar el\nmondongo.Los huesitos de chancho le dan un saborcito especial, pedile al\ncarnicero que te los troce chiquititos. Hay gente que le gusta con chorizo\nespañol si querés agregalos a la salsa, no hay problema. Los garbanzos los uso de\nlata, o sea están precosidos. Si vas a usar seco, primero remojalos en agua toda\nla noche, y luego hacelos hervir. En el norte, se sirve en cazuela con una\nsalcita arriba a base de cebollita de verdeo (la parte verde) con un tomatito\nprocesado con aji queda delicioso!!!

\n\n

Guiso de Arroz

\n\n\n\n

Procedimiento:

\n\n

Colocar en una cacerola el aceite calentar y agregar la cebolla, el pimiento, el\najo, la papa, la batata y la zanahoria, mezclar y cocinar por unos minutos.\nAgregar la carne, sal, pimienta y pimentón, remover y cocinar por unos minutos\nmás. Luego agregar el arroz lavado, el puré de tomate, el caldo bien caliente, el\nlaurel, el azúcar y un poco más de sal y pimienta, mezclar, cocinar por 18\nminutos, aproximadamente. Dejar reposar tapado o hasta que el arroz haya\nabsorbido casi todo el jugo y quede tierno.

\n\n

Pez Angel hervido con papas al natural

\n\n\n\n

Procedimiento:

\n\n

En una olla poner 3 litros de agua y agregar la hoja de laurel, la cebolla, los\ntres dientes de ajo, ½ vaso de vino blanco, el puerro, cocinar 20 minutos y\nagregar el pez ángel en trozos. Hervir 20 minutos o hasta que este cocido. Las\npapas se echan dentro del agua junto con el pescado. Mientras tanto mezclar en\nuna licuadora el aceite, el jugo de los limones exprimidos, condimentar con sal\npimienta, picar unas hojas de albahaca y agregar a la mezcla una hoja de laurel.\nSacar el pescado y las papas, escurrir y servir unos trozos de pescado, una papa\nque se pueda cortar en cuatro. Rociar con la mezcla de aceite y limón.\nSalpimentar a gusto. . El pez ángel o como comúnmente se lo llama (Pollo de Mar)\nse lo consigue en las pescaderías en troncos bien pelados. En los libros de\ncocina española se lo denomina (Rape) que es muy similar . Es una carne muy\nblanca a rosada suave y de consistencia bien fuerte, por lo que hay que\ndiferenciar de otros pescados que no se desarma en la cocción, no posee espinas y\nprácticamente no se le siente olor a pescado, por lo cual a mucha gente le es\nagradable por eso lleva el nombre de pollo de mar.

\n\n

Pez ángel a la Carolina

\n\n\n\n

Procedimiento:

\n\n

Salpimentar los filetes y ponerlos en una fuente para horno. Pelar y cortar las\ncebollas en juliana y las zanahorias en rodajas finas. Distribuir sobre el\npescado. Mezclar por separado el jugo de limón, el ajo picado, el orégano, con un\npoquito de sal y pimienta. Verter la salsa sobre el pescado. Cocer a horno medio\npor 30 minutos. Rinde 4 porciones.

\n\n

Pescado con salsa tártara

\n\n\n\n

Procedimiento:

\n\n

Lavar bien los filetes de pescado (lenguado, merluza, pez angel).Escurrirlos bien\ny cortarlos en tiras. Sazonar a gusto y pasarlos por huevo batido; empanarlos con\npan rallado. Dejar en la heladera un rato, mientras prepara la salsa tártara.\nPicar menudamente los pepinillos y las alcaparras, mezclar con la mayonesa. Freír\nel pescado en abundante aceite caliente, dejar dorar y escurrir sobre papel\nabsorbente. Servir enseguida, acompañados de salsa.

\n\n

Chupin de pescado

\n\n\n\n

Procedimiento:

\n\n

Picar finamente la cebolla con los ajíes y las zanahorias cortadas en láminas\nfinas y rehogar en aceite hasta que la cebolla esté de color transparente (no se\nllega a dorar por la zanahoria). Agregarle el ajo y el perejil finamente picado.\nPelar los tomates sacándoles la piel, o en su defecto, utilizar tomates en lata.\nPicar bien y agregar a la preparación. Condimentar con el Ají molido, el Orégano,\nla sal y el Laurel. Dejar tomar color y sabor por unos 10’ Agregarles los\nCalamares cortados en trozos medianos (el doble del tamaño deseado, ya que con la\ncocción, se encogen). Dejar cocinar por espacio de 30 minutos, controlando la\ncantidad de jugo que se produce. De ser necesario, agregar un poco de agua o\ncaldo de pescado (realizado con las cabezas y los cartílagos de los pescados),\npero tiene que quedar un tanto espeso. Cuando están cocidos los calamares,\nagregar el pescado cortado en trozos, y cocinar unos minutos más, hasta que el\npescado esté cocido. En el momento de servir, se le puede agregar las almejas,\nlos mejillones y una lata de arvejas. Esto es optativo. Controlar la sal, por el\nagregado del pescado.

\n\n

Abadejo en salsa verde (p/4)

\n\n\n\n

Procedimiento:

\n\n

Meter los tomates al horno a fuego moderado. Cortar los dientes de ajo en\nláminas, picar el perejil, sazonar el pescado con sal, rebozarlo con harina y\nsacudirlo para eliminar el exceso. Poner al aceite en una cazuela de barro o\nmaterial refractario. Cuidado con la temperatura, el exceso de calor achicharrará\nel pescado. Dorar los ajos, cuando tomen color, echar el pescado y freírlo por\nlos dos lados. Después , espolvorear con el perejil picado y bañarlo con el agua\ny el vino. Mover la cazuela con las manos, para que se ligue la salsa. Sacar los\ntomates del horno, ponerlos entre las rodajas de pescado, adornas el centro con\nel perejil, y después dar un hervor, servirlo en la misma cazuela.

\n\n

Pez espada a la cordobesa (4/p)

\n\n\n\n

Procedimiento:

\n\n

Lavar bien los filetes de pescado, secarlos con un papel de cocina y sazonarlos.\nAsarlos en una plancha precalentada, dándoles la vuelta para que se asen por\nambos lados. Cuando estén hechos, ponerlos en una fuente de servir. Preparar una\nsalsa en una sartén con aceite , los tomates, la cebolla y la sal, reservarla\ncaliente. Picar los ajos finamente, picar también el perejil. Rociar el pescado\ncon aceite caliente, luego con la salsa de tomate y servirlo espolvoreado con ajo\ny perejil.

\n\n

Arrolladito de pescado a la milanesa (4/p)

\n\n\n\n

Procedimiento:

\n\n

Precalentar el honro a temperatura fuerte (220ºC.). Limpiar los filetes de\nabadejo y sazonarlos con sal y pimienta a gusto. Esparcir sobre los filetes, la\nzanahoria rallada, el puerro cortado en juliana, el perejil y ajo, condimentar\ncon salvia y arrollarlos desde la cola a la cabeza. Cruzar cada rollo con un\npalillo de madera. Pasar los arrollados por las claras de huevo apenas batidas y\nluego, por el pan rallado. Distribuir los arrollados, en una asadera para horno,\nrociarlos con jugo de limón y humedecidos con un poco de caldo. Si no están\nhaciendo dieta se usa el huevo entero y en vez del caldo se usa aceite.

\n\n

Pesto italiano para pastas

\n\n\n\n

Para conservar el pesto hay que poner la pasta adentro de frascos chicos (~200\nml) de vidrio tapados. Llenar el frasco hasta el 80% y poner un poco de aceite de\noliva arriba de la pasta (~5%). Meter en el congelador hasta su uso.

\n\n

Papas duquesa

\n\n\n\n

Procedimiento:

\n\n

Cocinar las papas peladas y cortadas, en agua con sal. Una vez blandas,\nretirarlas, escurrirlas y hacer con ellas un puré, añadiéndoles las yemas y la\nmanteca, revolviendo muy bien. Condimentar con sal, pimienta y nuez moscada,\nagregándole el queso. Mezclar bien y colocar en manga con boquilla rizada para\ndecorar. Puedes formar unos nidos colocar queso rallado y gratinar en el horno.\nSi quieres hacerlas más completas puedes rellenar los nidos con espinacas a la\ncrema ó arvejas con manteca ó los vegetales que gustes inclusive champiñones\n(setas) salteados con crema. Sirve para acompañar carnes ó pollo y pescado (queda\nbien con todo)

\n\n

CALABAZAS RELLENAS CRIOLLAS

\n\n\n\n

Procedimiento:

\n\n

Se toman las calabazas y se les quita la “tapita” superior y con un sacabocados o\ncuchara se retira la mayor parte de la pulpa sin lastimar la piel exterior\ndejando un grosor de 1/2 centímetro aparte. Se corta la carne de cerdo en trozos\npequeños y en una sartén se pone a calentar el aceite. Se fríe la carne hasta que\ntome color, se le agrega el ajo, la cebolla y el jitomate. Se deja cocinar a\nfuego medio hasta que el jitomate suelte su jugo. Se sazona con sal y pimienta,\nse apaga el fuego y se espolvorea con el cilantro. Se rellenan las calabazas con\nla carne. Se pone un poco de queso y se hornea durante 20 minutos aproximadamente\no hasta que la piel de las calabazas este un poco suave.

\n\n

CALABAZAS RELLENAS

\n\n\n\n

Procedimiento:

\n\n

Cortar las calabazas al medio longitudinalmente, sacarle las semillas y ahuecar\nel sector que tiene pulpa. En una sartén rehogar las cebollas (picadas) cuando\nestén doradas agregarle el arroz, condimentar con sal y pimienta o jengibre a\ngusto y revolver todo. Rellenar las 4 mitades de las calabazas. En una asadera\ncolocar 1 dedo de agua con un chorrito de aceite de maíz y poner las calabazas\nrellenas, introducirlas en el horno bien caliente y cocinarlas a fuego lento.

\n\n

Calabaza Criolla Rellena

\n\n\n\n

Procedimiento:

\n\n

Cortar la calabaza al medio en forma longitudinal y quitar las semillas. Cocinar\nen el horno a temperatura fuerte hasta que esté media cocida. También puede\ncocinarse en el microondas. Ahuecar un poco con ayuda de una cuchara dejando un\nzócalo de 1 cm. Picar en trozos grandes la pulpa, y rehogar ligeramente en el\naceite caliente. Retirar y reservar. Agregar a la sartén el Sabor en Cubos de\nPanceta y Cebolla y fundir a fuego suave, mezclar con la calabaza, el choclo en\ngrano y el arroz. Incorporar los trocitos de queso y rellenar las mitades de\ncalabaza. Espolvorear con pan rallado y gratinar en horno fuerte. Servir.\nSugerencia: El relleno de la calabaza es a gusto y depende de los ingredientes\nque se dispongan. También puede incorporarse carne picada.

\n\n

Costillas de cerdo horneadas en cerveza negra

\n\n\n\n

Procedimiento:

\n\n

Salpimentar y sellar el costillar en una plancha bien caliente. Aparte, en un\nbol, mezclar el resto de los ingredientes. Reservar. En una fuente de horno,\ncolocar el costillar y bañarlo con la mezcla anterior. Meter en el horno a fuego\nbajo, durante 90 minutos. Sacar el costillar del horno y, si la salsa está muy\nlíquida, echarla en un cazo y espesarla con un poco de harina de maíz refinada.\nReservar. Separar las costillas, colocarlas en platos individual y bañarlas con\nla salsa de cerveza.

\n\n

Costillitas de cerdo a la naranja

\n\n\n\n

Procedimiento:

\n\n

Ponemos a calentar una sartén, colocamos las costillitas, las doramos de ambos\nlados y las retiramos. Reservamos. Agregamos a la sartén caliente, la manteca y\nel aceite. Cuando vemos que la manteca está fundida, le echamos el azúcar.\nTapamos y cocinamos en mínimo hasta obtener un caramelo claro. Añadimos el jugo\nde naranja, tapamos y seguimos cocinando a fuego mínimo hasta que se disuelva el\ncaramelo. Incorporamos nuevamente las costillitas a la sartén, tapamos y\ncontinuamos la cocción. Una vez caramelizadas de un lado, las damos vuelta hasta\nfinalizar la cocción. Condimentamos con sal y pimienta. Si desean, pueden agregar\ncomo guarnición unas zanahorias y chauchas hervidas, que se agregan a la sartén\npara caramelizarlas.

\n\n

Costillitas de cerdo a la mostaza

\n\n\n\n

Salpimentar a gusto las costillitas de cerdo, dorarlas en manteca, de ambos\nlados. En el mismo fondo de cocción rehogar las cebollas de verdeo picadas con el\naceite. Añadir el vino y cocinar unos minutos. Sumar el cubito de caldo diluído\nen 100 cc de agua caliente. Agregar granos de pimienta negra y hierbas\naromáticas. Cocinar 5´más e incorporar las costillitas. Cocinar 15´y añadir la\nmostaza con miel mezclada con la crema de leche. Cocer 2 o 3´y servir enseguida.

\n\n

Carne a la cacerola “mechada”

\n\n\n\n

Procedimiento:

\n\n

Quitar toda la grasa que pueda tener la carne. Pelar y cortar la zanahorias en\nbastones lo más largos posible. Pelar los dientes de ajo, cortar al medio,\nretirar los brotes centrales si los tuvieran y picar finamente. Retirar el cuero\nde la panceta. Si se está trabajando con un corte que no es alargado como la\npunta de paleta cortarlo de manera tal que queden dos trozos alargados. Con una\ncuchilla filosa hacer un corte que atraviese toda la carne a lo largo. Introducir\ndentro del orificio el ajo y el perejil, las zanahorias y la panceta. Atar la\ncarne firmemente alrededor, para que mantenga la forma, con un hilo de algodón,\ncomo si fuera un matambre. Llevar una cacerola al fuego, cuando esté caliente\nincorporar el aceite y luego la carne, bajar un poco el fuego y rotar la carne de\nmanera tal que se dore en toda su superficie. Incorporar el vino y dejar cocinar\na fuego entre suave y moderado al menos 2 horas, girando la carne de vez en\ncuando. Ir agregando caldo si fuera necesario. Cuando la carne esté muy tierna\nagregar las arvejas, (si son frescas dejarlas cocinar unos 15 minutos, si son de\nlata agregarlas a último momento). Disolver la maicena (fécula de maíz) en la\nleche o agua fría. Agregar la maicena a la salsa y revolver mientras hierve un\npar de minutos, si no se obtuvo la consistencia deseada agregar un poco más de\nmaicena, siempre disuelta previamente en un líquido en frío. Salpimentar, retirar\nlos hilos de la carne, cortar en rodajas, servir y cubrir con la salsa.

\n\n

Carne a la cacerola sencilla

\n\n\n\n

Salpimentar el trozo de carne. Calentar el aceite y la manteca y cocer la carne\ndándole vuelta varias veces durante 30 minutos a fuego bajo. Retirar la carne e\nincorporar las cebollas, las zanahorias y el ajo, junto con el tomillo, el laurel\ny el caldo. Dejar que tome punto de ebullición y agregar el vino. Debe quedar una\nbuena salsa, por eso si es necesario, se puede agregar más caldo. Servir bien\ncaliente acompañado con puré duquesa.

\n", "date_published": "2021-12-05T00:00:00-03:00" }, { "id": "https://pmoracho.github.io/blog/2021/11/05/linux-mint-20.2-en-lenovo-ideapad/", "url": "https://pmoracho.github.io/blog/2021/11/05/linux-mint-20.2-en-lenovo-ideapad/", "title": "Instalación y configuración de Linux Mint 20.2 en una Ideapad 540", "content_html": "

Antes que nada

\n\n

Copia de seguridad de home

\n\n

Instalación

\n\n\n\n

Cuidado con las particiones, en mi caso

\n\n\n\n

Wifi

\n\n

Y Mint sigue sin tener soporte en la instalación de la placa de red,\npor lo que de entrada no hay wifi y teniendo en cuenta que el equipo tampoco\ntiene un puerto ethernet, esto es bastante molesto. Pero a no deseperar,\nbuscando se encuentran soluciones. Y la solución pasa por compilar e instalar\nel driver de la placa, al menos en el caso de esta placa:

\n\n
> inxi -F|grep RTL8821CE\nNetwork:   Device-1: Realtek RTL8821CE 802.11ac PCIe Wireless Network Adapter driver: rtl8821ce\n
\n\n

Podemos usar el repositorio de los driver de Realtek RTL8821CE Driver para\nArchLinux. Claro que al no tener red, habrá que clonar el respoitorio en un\nmedio extraible (“pendrive”):

\n\n
git clone https://github.com/tomaspinho/rtl8821ce.git\n
\n\n

Atención: git lamentablemente no se instala por defecto. Para descargar este\ndriver habrá que hacerlo desde otro equipo que cuente con git o simplemente\ndesde github descargamos un zip del repositorio. Podemos compartir red desde\nun teléfono Android mediante usb, como alterntiva de emergencia suele funcionar\nmuy bien.

\n\n

En el caso de Mint, ya tenemos varias herramientas de compilación\ninstaladas, lo cual es postivo, por que no tenemos red.

\n\n
cd rtl8821ce\nsudo ./dkms-install.sh\n
\n\n

Y listo, solo hay que reiniciar y configurar la contraseña de la red.

\n\n

Post-instalación

\n\n

A continuación la lista de cosas que hacemos luego de instalar el equipo.

\n\n
    \n
  1. Habilitar el modo Legacy para las teclas de función.
  2. \n
\n\n

El comportamiento por defecto de las teclas F1..F12 unicamente se activa si\ncombinamos con la tecla Fn. Esto es posible modificarlo desde la BIOS, que de\npaso, se entra presionando F2, luego simplemente buscar el ítem “Hot Key”

\n\n
    \n
  1. \n

    Actualizar el sistema

    \n\n
     sudo apt update && sudo apt upgrade -y\n
    \n
  2. \n
  3. \n

    Instalar codecs multimedia

    \n\n
     sudo apt install mint-meta-codecs\n
    \n
  4. \n
  5. Crear un snapshot del sistema con timeshift
  6. \n
  7. Deshabilitar aplicaciones que se cargan al inicio del sistema
  8. \n
  9. Habilitar y configurara el firewall
  10. \n
  11. \n

    Limpiar el sistema

    \n\n
     sudo apt autoclean\n sudo apt clean\n sudo apt autoremove\n
    \n
  12. \n
\n\n

Eliminando lo innecesario

\n\n

En lo personal nunca le encontré utilidad al servidor [avahi-daemon][avahi],\npor lo que suelo eliminarlo de las instalaciones

\n\n
sudo apt remove avahi-daemon\nsudo apt remove avahi-utils\nsudo apt remove libnss-mdns\n
\n\n

Cuidado: hay muchos otros paquetes avahi*, que no deben ser eliminados\npor que son dependencias del sistema

\n\n

Eliminar tipos de letras innecearios

\n\n
sudo apt-get remove \"fonts-kacst*\" \"fonts-khmeros*\" fonts-lklug-sinhala fonts-guru-extra \"fonts-nanum*\" fonts-noto-cjk \"fonts-takao*\" fonts-tibetan-machine fonts-lao fonts-sil-padauk fonts-sil-abyssinica \"fonts-tlwg-*\" \"fonts-lohit-*\" fonts-beng-extra fonts-gargi fonts-gubbi fonts-gujr-extra fonts-kalapi \"fonts-samyak*\" fonts-navilu fonts-nakula fonts-orya-extra fonts-pagul fonts-sarai \"fonts-telu*\" \"fonts-wqy*\" \"fonts-smc*\" fonts-deva-extra fonts-sahadeva\nsudo dpkg-reconfigure fontconfig\n
\n\n

Audio decente

\n\n

Este equipo tiene según su especificaciones, audio DOLBY, por lo que\nsi lo quería aprovechar al máximo, seguí las recomendaciones de esta\nrespuesta. La idea entonces:

\n\n
    \n
  1. \n

    Instalar PulseEffects, esto desde el Gestor de Software, es una aplicación\nflatpack, o bien seguir estas\ninstrucciones

    \n
  2. \n
  3. \n

    Instalar estos presets

    \n
  4. \n
  5. \n

    Configurar el Convolver, y seleccionar el preset:

    \n\n
    \n

    Dolby ATMOS ((128K MP3)) 1.Default.irs

    \n
    \n
  6. \n
  7. \n

    Disfrutar la diferencia, el audio es notablemente mejor y sobre todo con un volumen superior.

    \n
  8. \n
\n\n

Gestores de sesiones

\n\n

Por defecto mint usa lightdm, pero puede usar gdm o kdm:

\n\n
sudo dpkg-reconfigure lightdm\nsudo dpkg-reconfigure gdm3\nsudo dpkg-reconfigure kdm\n
\n\n

Desarrollo

\n\n

Instalar herramientas básicas de desarrollo:

\n\n
sudo apt-get install build-essential gdb git\nsudo apt-get install docker.io\n
\n\n

Instalar R y RStudio (últimas versiones):

\n\n
# Agregamos certificados para el repositorio\nsudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9\n# Agregamos el repositorio\nsudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/'\nsudo apt update\nsudo apt install r-base\n\n# Instalar RStudio\ncd ~/Descargas\nwget https://download1.rstudio.org/desktop/bionic/amd64/rstudio-2021.09.0-351-amd64.deb\n
\n\n

Configurar git

\n\n
git config --global user.name \"John Doe\"\ngit config --global user.email johndoe@example.com\n
\n\n

Visual Code

\n\n
sudo apt-get install code\n
\n\n\n\n

Multimedia

\n\n

Instalar stremio desde el sitio, bajar paquete .deb

\n\n

Herramientas

\n\n

Descargar e instalar chrome desde su página

\n\n
sudo apt-get install keepassx\nsudo apt-get install mc\nsudo apt-get install gimp\nsudo apt-get install inkscape\nsudo apt-get install k3b\nsudo apt-get install deluge\n
\n\n

Kitty

\n\n
curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin\ncp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications/\nsed -i \"s|Icon=kitty|Icon=/home/$USER/.local/kitty.app/share/icons/hicolor/256x256/apps/kitty.png|g\" ~/.local/share/applications/kitty.desktop\n
\n\n

Double Commander

\n\n

Descargar archivo .tar.xz desde la página del proyecto.\nDescomprimir en carpeta bin local y armar un atajo en el escritorio. La\nconfiguración la tengo en un repo de GitHub.

\n\n
ln -s ~/Proyectos/environment/doublecmd.xml ~/bin/doublecmd/doublecmd.xml\n
\n\n

Rclone y Rclonebrowser

\n\n

Imposible no tener estas herramientas si tenés espacio en la nube que querés\nmontar como un disco cualquiera.

\n\n
cd Descargas\nwget https://downloads.rclone.org/rclone-current-linux-amd64.deb\napt-get install ./rclone-current-linux-amd64.deb\n
\n\n

Uso un fork propio del Rclonebrowser:

\n\n

Docky

\n\n

Hace años que uso este Dock, lamentablemente es un proyecto que no tiene\nmantenimiento desde hace varios años, por lo que cada vez se hace más complicado\ninstalarlo. En el caso de Mint 20.2, se instala con algunos paquetes\nantiguos que eventualmente podrían generar algún conflicto:

\n\n

Descargamos e instalamos las librerías:

\n\n
mkdir -p ~/Descargas/docky\ncd ~/Descargas/docky\n\nwget -c http://archive.ubuntu.com/ubuntu/pool/universe/g/gnome-sharp2/libgconf2.0-cil_2.24.2-4_all.deb\nwget -c http://archive.ubuntu.com/ubuntu/pool/main/g/glibc/multiarch-support_2.27-3ubuntu1_amd64.deb\nwget -c http://archive.ubuntu.com/ubuntu/pool/universe/libg/libgnome-keyring/libgnome-keyring-common_3.12.0-1build1_all.deb\nwget -c http://archive.ubuntu.com/ubuntu/pool/universe/libg/libgnome-keyring/libgnome-keyring0_3.12.0-1build1_amd64.deb\nwget -c http://archive.ubuntu.com/ubuntu/pool/universe/g/gnome-keyring-sharp/libgnome-keyring1.0-cil_1.0.0-5_amd64.deb\n\nsudo apt-get install ./*.deb\n
\n\n

Luego instalamos docky:

\n\n
wget -c http://archive.ubuntu.com/ubuntu/pool/universe/d/docky/docky_2.2.1.1-1_all.deb\nsudo apt-get install ./docky_2.2.1.1-1_all.deb\n
\n\n

Fuente: https://askubuntu.com/a/1237413/1050086

\n\n

O bien podemos intentar compilar docky desde el repositorio descargando los\nfuentes desde: https://launchpad.net/docky, pero hasta ahora este camino no es\nmás que un infierno de dependencias incumplidas.

\n\n

Bash

\n\n

Agregamos customización personal al .bashrc

\n\n
###\n### Personal Customization\n###\nif [ -f ~/.bashrc.personal ]; then\n    . ~/.bashrc.personal\nfi\n
\n\n

Apuntamos el .bashrc.personal a .bashrc al que ya tengo en git.

\n\n
ln -s Proyectos/environment/.bashrc.personal .bashrc.personal\n
\n\n

Atajos de teclado

\n\n

Me resulta muy cómodo asociar combinaciones de teclas a mi script run-or-raise\nque básicmente ejecuta un comando en caso de que no esté corriendo, o\neventualmente reactiva la ventana del mismo. Estos son mis atajos:

\n\n
# Alt-1\nsh /home/pmoracho/bin/run-or-raise kitty.kitty ~/bin/kitty\n# Alt-2\nsh /home/pmoracho/bin/run-or-raise google-chrome.Google-chrome google-chrome\n# Alt-4\nsh /home/pmoracho/bin/run-or-raise code.Code sh /usr/bin/code\n# Alt-5\nsh /home/pmoracho/bin/run-or-raise doublecmd.Doublecmd ~/bin/doublecmd/doublecmd\n
\n\n", "date_published": "2021-11-05T00:00:00-03:00" }, { "id": "https://pmoracho.github.io/patrones-desbloqueo-android/", "url": "https://pmoracho.github.io/patrones-desbloqueo-android/", "title": "Patrones de desbloqueo de Android", "content_html": "

Introducción

\n\n

Cuando me aburro, me pueden encontrar respondiendo preguntas en\nstackoverflow o haciendo\ndesafíos en codewars. De este último es el\ninteresante problema: Screen Locking\nPatterns. La\nidea es bien simple, dado un punto inicial en el patrón de bloqueo de\nAndroid, un cuadrado de 3x 3, y un número de puntos, calcular la\ncantidad de posibles patrones. Por supuesto:

\n\n\n\n

Y ¿qué es un patrón válido?

\n\n\n\n

Hay otra restricción no escrita, la solución debe poder correr en un\ntiempo razonable. ¿Cuán razonable? lo determina el servidor de\ncodewars.

\n\n

¿Cómo resolverlo?

\n\n

Esta fue la primer pregunta que me hice, ciertamente parece un problema\npara aplicar algún algoritmo de camino o incluso de árboles, pero como\nsoy cómodo, elegí la opción fácil: “fuerza bruta”, pero entonces\n¿podemos calcular previamente todos los caminos posibles y enfocarnos\nluego a encontrar los que son válidos descartando aquellos que no lo\nson?. Veamos, tenemos un patrón de 3 x 3, con puntos que no deben\nrepetirse, por lo que en definitiva hay un espacio de posibilidades de\nrespuesta, que seguro no es mayor a las permutaciones de los 9 puntos\nsin repeticiones por las 9 posibles longitudes pedidas:

\n\n
factorial(9) * 9\n
\n\n
## [1] 3265920\n
\n\n

O sea 3.26592^{6}, un número importante sin duda, pero no imposible de\nmanejar. Lógicamente no todas estas combinaciones son válidas, pero eso,\npor ahora es otro problema.

\n\n

NOTA: Como siempre, de acá a un par de días seguramente ya no me acuerde\nque son las permutaciones, bueno, si tenemos 9 elementos distintos, las\npermutaciones sin repetición son todas las formas en que se pueden\nordenar estos.

\n\n

Permutaciones en R

\n\n

Ya vimos que el número a manejar es importante pero razonable, ahora\nbien ¿Cómo podemos generar todas las permutaciones de 9 elementos en\nR? Bueno, algo sorprendido, debo decir que no hay ninguna rutina\n“base” para generar esto, tampoco es que sea nada del otro mundo, con un\nsimple código recursivo lo podemos realizar, pero en la red la mayoría\nde la recomendaciones pasan por usar paquetes adicionales, tales como:

\n\n\n\n

También hay algunas funciones de permutación interesantes para mantener\nel código simple y no recurrir a paquetes adicionales. no lo probé, pero\ndudo que codewars permita instalar paquetes\nde terceros:

\n\n\n\n

Veamos una recopilación de funciones interesantes y estudiemos su\nperformance con microbenchmark:

\n\n
# From: https://www.r-bloggers.com/2019/06/learning-r-permutations-and-combinations-with-base-r/\npermutate_1 <- function(v) {\n  n <- length(v)\n  if (n == 1) v\n  else {\n    X <- NULL\n    for (i in 1:n) X <- rbind(X, cbind(v[i], permutate_1(v[-i])))\n    X\n  }\n}\n\n# From: https://stackoverflow.com/a/20199902/6836377\npermutate_2 <- function(values) {\n  \n  permutations <- function(n){\n    if(n==1){\n      return(matrix(1))\n    } else {\n      sp <- permutations(n-1)\n      p <- nrow(sp)\n      A <- matrix(nrow=n*p,ncol=n)\n      for(i in 1:n){\n        A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))\n      }\n      return(A)\n    }\n  }\n  \n  n <- length(values)\n  matrix(values[permutations(n)], ncol=n)\n}\n\n# From: https://stackoverflow.com/a/20199902/6836377\npermutate_3 <- function(x){\n  stopifnot(is.atomic(x)) # for the matrix call to make sense\n  out <- as.matrix(expand.grid(\n    replicate(length(x), x, simplify = FALSE), stringsAsFactors = FALSE))\n  out[apply(out,1, anyDuplicated) == 0, ]\n}\n\n# From: https://stackoverflow.com/a/65354641/6836377\npermutate_4 <- function(x, prefix = c()){\n  if(length(x) == 1) # was zero before\n    return(list(c(prefix, x)))\n  out <- do.call(c, lapply(1:length(x), function(idx) \n    permutate_4(x[-idx], c(prefix, x[idx]))))\n  if(length(prefix) > 0L)\n    return(out)\n  \n  do.call(rbind, out)\n}\n\n# From: https://stackoverflow.com/a/34287541/6836377\npermutate_5 <- function(x) {\n    if (length(x) == 1) {\n        return(x)\n    }\n    else {\n        res <- matrix(nrow = 0, ncol = length(x))\n        for (i in seq_along(x)) {\n            res <- rbind(res, cbind(x[i], Recall(x[-i])))\n        }\n        return(res)\n    }\n}\n\ncasos <- LETTERS[1:6]\nmicrobenchmark::microbenchmark(permutate_1 = permutate_1(casos),\n                               permutate_2 = permutate_2(casos),\n                               permutate_3 = permutate_3(casos),\n                               permutate_4 = permutate_4(casos),\n                               permutate_5 = permutate_5(casos), times = 10) -> df\n
\n\n

Resultado:

\n\n
summary(df)\n
\n\n
##          expr        min         lq       mean     median         uq       max\n## 1 permutate_1   4065.715   4399.902   5624.935   5041.505   5467.740  12553.52\n## 2 permutate_2    190.860    207.353   1474.130    236.006    256.725  12669.85\n## 3 permutate_3 155386.740 158331.697 170237.758 165408.234 177839.048 211614.81\n## 4 permutate_4   4367.584   4714.645   6545.433   5317.123   5883.764  12588.24\n## 5 permutate_5   5439.218   5612.255   7676.531   6077.719  10172.385  13263.32\n##   neval\n## 1    10\n## 2    10\n## 3    10\n## 4    10\n## 5    10\n
\n\n

Visualmente:

\n\n
df %>% \n  ggplot(df, mapping=aes(y=expr, x=time, fill=expr)) +\n  geom_violin() +\n  theme_elegante_std() +\n  scale_x_log10(\n    breaks = scales::trans_breaks(\"log10\", function(x) 10^x),\n    labels = scales::trans_format(\"log10\", scales::math_format(10^.x))\n  ) +\n  labs(title = paste(\"Performance\"), \n     subtitle = paste(\"de varias rutinas de permutación\") , \n     caption = \"\", \n     y = \"\", \n     x = \"microsegundos\"\n    ) \n
\n\n

\n\n

La rutina dos, sin duda se lleva todos los premios, aunque parece tener\nuna larga cola producto de un “outlier”, algo curioso, ya que si bien\ntiene un funcionamiento bastante estable, se verifica siempre que la\nsegunda ejecución es dónde el tiempo crece hasta 5 veces el valor medio.

\n\n
library(tidyverse)\n\ndf %>% \n  as.data.frame() %>% \n  filter(expr == 'permutate_2')\n
\n\n
##           expr     time\n## 1  permutate_2   269532\n## 2  permutate_2 12669850\n## 3  permutate_2   226465\n## 4  permutate_2   256725\n## 5  permutate_2   238852\n## 6  permutate_2   190860\n## 7  permutate_2   200507\n## 8  permutate_2   247994\n## 9  permutate_2   233160\n## 10 permutate_2   207353\n
\n\n

Pero más allá de esta cuestión anectdotica, la rutina de\nmuseful parece ser la\nque mejores resultados ofrece en cuanto a tiempo.

\n\n

Ya tenemos una forma de generar todas las permutaciones de los 9 puntos:

\n\n
permutate <- function(values) {\n  permutations <- function(n){\n    if(n==1){\n      return(matrix(1))\n    } else {\n      sp <- permutations(n-1)\n      p <- nrow(sp)\n      A <- matrix(nrow=n*p,ncol=n)\n      for(i in 1:n){\n        A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))\n      }\n      return(A)\n    }\n  }\n  \n  n <- length(values)\n  matrix(values[permutations(n)], ncol=n)\n}\n\nM <- permutate(LETTERS[1:9])\nhead(M)\n
\n\n
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]\n## [1,] \"A\"  \"B\"  \"C\"  \"D\"  \"E\"  \"F\"  \"G\"  \"H\"  \"I\" \n## [2,] \"A\"  \"B\"  \"C\"  \"D\"  \"E\"  \"F\"  \"G\"  \"I\"  \"H\" \n## [3,] \"A\"  \"B\"  \"C\"  \"D\"  \"E\"  \"F\"  \"H\"  \"G\"  \"I\" \n## [4,] \"A\"  \"B\"  \"C\"  \"D\"  \"E\"  \"F\"  \"H\"  \"I\"  \"G\" \n## [5,] \"A\"  \"B\"  \"C\"  \"D\"  \"E\"  \"F\"  \"I\"  \"G\"  \"H\" \n## [6,] \"A\"  \"B\"  \"C\"  \"D\"  \"E\"  \"F\"  \"I\"  \"H\"  \"G\"\n
\n\n
length(M)\n
\n\n
## [1] 3265920\n
\n\n

Una de las restricciones, que se nos pide, es una longitud o cantidad de\npuntos, por lo que deberemos “recortar” la matriz en función de dicha\nlongitud, el problema es que al hacer esto, quedaran permutaciones\nrepetidas que tendremos que eliminar. La otra restricción es que se nos\npide comenzar de un determinado punto, por lo que deberemos filtrar\nnuestra matriz por el valor de la primer columna. Imaginemos que se nos\npide comenzar el patrón desde el punto D y que la longitud sea 3:

\n\n
l <- 3\nf <- \"D\"\ntodos <- apply(unique(M[M[,1] == f, 1:l]), 1, paste, collapse=\"\")\ntodos\n
\n\n
##  [1] \"DAB\" \"DAC\" \"DAE\" \"DAF\" \"DAG\" \"DAH\" \"DAI\" \"DBA\" \"DBC\" \"DBE\" \"DBF\" \"DBG\"\n## [13] \"DBH\" \"DBI\" \"DCA\" \"DCB\" \"DCE\" \"DCF\" \"DCG\" \"DCH\" \"DCI\" \"DEA\" \"DEB\" \"DEC\"\n## [25] \"DEF\" \"DEG\" \"DEH\" \"DEI\" \"DFA\" \"DFB\" \"DFC\" \"DFE\" \"DFG\" \"DFH\" \"DFI\" \"DGA\"\n## [37] \"DGB\" \"DGC\" \"DGE\" \"DGF\" \"DGH\" \"DGI\" \"DHA\" \"DHB\" \"DHC\" \"DHE\" \"DHF\" \"DHG\"\n## [49] \"DHI\" \"DIA\" \"DIB\" \"DIC\" \"DIE\" \"DIF\" \"DIG\" \"DIH\"\n
\n\n

Hemos logrado obtener todas las combinaciones comenzando en D y con\nuna longitud 3 de los 9 posibles puntos. El problema final, es que no\ntodas estas combinaciones son válidas. Ya habíamos comentado, que no se\npuede saltear un punto, por ejemplo D -> F es una combinación inválida\npor que en el medio está E igual ocurre con F -> D sin embargo, y\nacá está lo complejo, podría ser válido hacer E -> D -> F en este caso\nel conjunto D -> F es válido por que ya hemos pasado por E. Hay una\nresolución muy interesante en Python\naqui que calcula la\ncantidad de soluciones totales, y maneja un diccionario dónde se guardan\nlos movimientos inválidos y el punto para que eventualmente dicho patrón\nsea válido, en R sería algo como esto:

\n\n
invalidos <- read.table(text='patron, a_menos_que\n\"AC\", \"B\"\n\"AI\", \"E\"\n\"AG\", \"D\"\n\"BH\", \"E\"\n\"CA\", \"B\"\n\"CG\", \"E\"\n\"CI\", \"F\"\n\"DF\", \"E\"\n\"FD\", \"E\"\n\"GA\", \"D\"\n\"GI\", \"H\"\n\"GC\", \"E\"\n\"HB\", \"E\"\n\"IG\", \"H\"\n\"IC\", \"F\"\n\"IA\", \"E\"', header=TRUE, sep=\",\", strip.white=TRUE, stringsAsFactors = FALSE)\n
\n\n

Es decir, tenemos un data.frame con los movimientos inválidos y una\ncolumna a_menos_que que nos dice, para dicho patrón, el punto que\ndebería existir antes para considerarlo válido.

\n\n

Teniendo esto y las permutaciones arrancando de un punto dado y de la\nlongitud solicitada, lo único que restaría es eliminar efectivamente los\npatrones inválidos. Imagino que hay varias formas de hacerlo, yo elegí\nusar expresiones regulares, armando un patrón regex a partir de\ninvalidos dónde encontrar aquellos efectivamente inválidos, es decir\nque no tengan un a_menos_que antes:

\n\n
patrones <- paste(apply(invalidos, 1, function(x) {paste0(\"^[^\", x[2], \"]*\", x[1], \".*$|\", x[1], \".*\", x[2])}), collapse=\"|\")\npatrones\n
\n\n
## [1] \"^[^B]*AC.*$|AC.*B|^[^E]*AI.*$|AI.*E|^[^D]*AG.*$|AG.*D|^[^E]*BH.*$|BH.*E|^[^B]*CA.*$|CA.*B|^[^E]*CG.*$|CG.*E|^[^F]*CI.*$|CI.*F|^[^E]*DF.*$|DF.*E|^[^E]*FD.*$|FD.*E|^[^D]*GA.*$|GA.*D|^[^H]*GI.*$|GI.*H|^[^E]*GC.*$|GC.*E|^[^E]*HB.*$|HB.*E|^[^H]*IG.*$|IG.*H|^[^F]*IC.*$|IC.*F|^[^E]*IA.*$|IA.*E\"\n
\n\n
found_invalid <- sapply(gregexpr(patrones,todos), `[[`, 1) > -1\n\ntodos[!found_invalid]\n
\n\n
##  [1] \"DAB\" \"DAE\" \"DAF\" \"DAG\" \"DAH\" \"DBA\" \"DBC\" \"DBE\" \"DBF\" \"DBG\" \"DBI\" \"DCB\"\n## [13] \"DCE\" \"DCF\" \"DCH\" \"DEA\" \"DEB\" \"DEC\" \"DEF\" \"DEG\" \"DEH\" \"DEI\" \"DGA\" \"DGB\"\n## [25] \"DGE\" \"DGF\" \"DGH\" \"DHA\" \"DHC\" \"DHE\" \"DHF\" \"DHG\" \"DHI\" \"DIB\" \"DIE\" \"DIF\"\n## [37] \"DIH\"\n
\n\n
n <- length(todos[!found_invalid])\nn\n
\n\n
## [1] 37\n
\n\n

Implementamos todo esto en una función, agregamos lógica para los\ncaminos inferiores a 1 o superiores a 9, y un “truquito” para evitar el\ncalculo cuando la longitud es 1.

\n\n
count_patterns_from <- function(f, l) {\n    \n    if (l >= 10 | l <= 0) return(0)\n    if (l == 1) return(1)\n    \n    invalidos <- read.table(text='patron, a_menos_que\n    \"AC\", \"B\"\n    \"AI\", \"E\"\n    \"AG\", \"D\"\n    \"BH\", \"E\"\n    \"CA\", \"B\"\n    \"CG\", \"E\"\n    \"CI\", \"F\"\n    \"DF\", \"E\"\n    \"FD\", \"E\"\n    \"GA\", \"D\"\n    \"GI\", \"H\"\n    \"GC\", \"E\"\n    \"HB\", \"E\"\n    \"IG\", \"H\"\n    \"IC\", \"F\"\n    \"IA\", \"E\"', header=TRUE, sep=\",\", strip.white=TRUE, stringsAsFactors = FALSE)\n    \n    permutate <- function(values) {\n      permutations <- function(n){\n        if(n==1){\n          return(matrix(1))\n        } else {\n          sp <- permutations(n-1)\n          p <- nrow(sp)\n          A <- matrix(nrow=n*p,ncol=n)\n          for(i in 1:n){\n            A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))\n          }\n          return(A)\n        }\n      }\n      \n      n <- length(values)\n      matrix(values[permutations(n)], ncol=n)\n    }\n    \n    M <- permutate(LETTERS[1:9])\n    todos <- apply(unique(M[M[,1] == f, 1:l]), 1, paste, collapse=\"\")\n    patrones <- paste(apply(invalidos, 1, function(x) {paste0(\"^[^\", x[2], \"]*\", x[1], \".*$|\", x[1], \".*\", x[2])}), collapse=\"|\")\n    found_invalid <- sapply(gregexpr(patrones,todos), `[[`, 1) > -1\n    n <- length(todos[!found_invalid])\n    n\n    #list(n, todos, patrones, found_invalid)\n}\n
\n\n

Y ya tenemos la función solicitada en el desafío. Un momento: ¿seguro?,\nbueno en realidad no, si bien funciona bien y con un tiempo de calculo\nrazonable, lamentablemente no tan “razonable” para\ncodewars. Qué desepción! tanto trabajo para\nnada, a menos que… no no puede funcionar.. aparte sería una vergüenza..\nbueno al menos podríamos probarlo. ¿Y sí precalculamos el espacio de\nsolución? a ver.. tenemos 9 letras y 9 posibles longitudes, o sea 81\nposibilidades

\n\n
generate_all <- function() {\n  t <- data.frame(expand.grid(LETTERS[1:9], 1:9))\n  cnt <- c()\n  for (v in 1:nrow(t)){\n    cnt <- c(cnt, count_patterns_from(t[v,1], t[v,2]))\n  }\n  cnt\n}\n\nM <- generate_all()\nM\n
\n\n
##  [1]     1     1     1     1     1     1     1     1     1     5     7     5\n## [13]     7     8     7     5     7     5    31    37    31    37    48    37\n## [25]    31    37    31   154   188   154   188   256   188   154   188   154\n## [37]   684   816   684   816  1152   816   684   816   684  2516  2926  2516\n## [49]  2926  4248  2926  2516  2926  2516  7104  8118  7104  8118 12024  8118\n## [61]  7104  8118  7104 13792 15564 13792 15564 23280 15564 13792 15564 13792\n## [73] 13792 15564 13792 15564 23280 15564 13792 15564 13792\n
\n\n

Con la anterior matriz bien podemos hacer algo así:

\n\n
count_patterns_from <- function(f, l) {\n  if (l > 9| l <= 0) return(0)\n  m <- structure(c(1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 7, 5, 7, 8, 7, 5, 7, \n              5, 31, 37, 31, 37, 48, 37, 31, 37, 31, 154, 188, 154, 188, 256, \n              188, 154, 188, 154, 684, 816, 684, 816, 1152, 816, 684, 816, \n              684, 2516, 2926, 2516, 2926, 4248, 2926, 2516, 2926, 2516, 7104, \n              8118, 7104, 8118, 12024, 8118, 7104, 8118, 7104, 13792, 15564, \n              13792, 15564, 23280, 15564, 13792, 15564, 13792, 13792, 15564, \n              13792, 15564, 23280, 15564, 13792, 15564, 13792), .Dim = c(9L, \n                                                                         9L), .Dimnames = list(c(\"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \n                                                                                                 \"I\"), c(\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\")))\n  m[f, l]\n}\n
\n\n

Y funcionó! pareciera un poco tramposo, pero es totalmente válido,\ntenemos una función que resuelve la totalidad del problema,\ntécnicamente, no tiene lógica, solo una matriz de soluciones, después de\ntodo fue legítimo el esfuerzo para construir la matriz (vamos, que\nseguramente la podría haber copiado y pegado de algún lado). Igualmente,\nrevisando las soluciones de otros usuarios, me encontré que muchos\noptaron por hacer lo mismo:

\n\n
# From https://www.codewars.com/users/elmstedt\ncount_patterns_from_1 <- function(f, l) {\n  # Cheating Solution\n  if (l < 1 || l > 9) return(0)\n  ac <- structure(c(1, 1, 1, 1, 1, 1, 1, 1, 1,\n                    5, 7, 5, 7, 8, 7, 5, 7, 5,\n                    31, 37, 31, 37, 48, 37, 31, 37, 31,\n                    154, 188, 154, 188, 256, 188, 154, 188, 154,\n                    684, 816, 684, 816, 1152, 816, 684, 816, 684,\n                    2516, 2926, 2516, 2926, 4248, 2926, 2516, 2926, 2516,\n                    7104, 8118, 7104, 8118, 12024, 8118, 7104, 8118, 7104,\n                    13792, 15564, 13792, 15564, 23280, 15564, 13792, 15564, 13792,\n                    13792, 15564, 13792, 15564, 23280, 15564, 13792, 15564, 13792),\n                  .Dim = c(9, 9))\n  ac[match(f, LETTERS), l]\n}\n\n# From https://www.codewars.com/users/Schleiffer\ncount_patterns_from_2 <- function(f, l) {\n if (l<1 | l>9) return(0)\n res<-c(1, 5, 31, 154,  684, 2516,  7104, 13792, 13792, 1, 7, 37, 188,  816, 2926,  8118, 15564, 15564, 1, 8, 48, 256, 1152, 4248, 12024, 23280, 23280)\n sel<-0 + 1 * (f %in% c(\"B\",\"D\",\"F\",\"H\")) + 2 * (f == \"E\") \n return(res[l+sel*9])\n}\n\n# user8436785\ncount_patterns_from_3<- function(f, l) if (l > 9) 0 else if (l < 2) l else c(C2 = 5, C3 = 31, C4 = 154, C5 = 684, C6 = 2516, C7 = 7104, C8 = 13792, C9 = 13792, S2 = 7, S3 = 37, S4 = 188, S5 = 816, S6 = 2926, S7 = 8118, S8 = 15564, S9 = 15564, M2 = 8, M3 = 48, M4 = 256, M5 = 1152, M6 = 4248, M7 = 12024, M8 = 23280, M9 = 23280)[[paste0(if (f == 'E') 'M' else if (grepl(f, 'ACGI', fixed=TRUE)) \"C\" else \"S\", l)]]\n
\n\n

¿Y como se comportan estas funciones precalculadas?

\n\n

Midamos los tiempos:

\n\n
microbenchmark::microbenchmark(count_patterns_from = count_patterns_from(\"E\", 9),\n                               count_patterns_from_1 = count_patterns_from_1(\"E\", 9),\n                               count_patterns_from_2 = count_patterns_from_2(\"E\", 9),\n                               count_patterns_from_3 = count_patterns_from_3(\"E\", 9), times = 10) -> df\n\nsummary(df)\n
\n\n
##                    expr    min     lq     mean  median     uq      max neval\n## 1   count_patterns_from 10.729 11.736 592.3144 13.5375 15.871 5796.512    10\n## 2 count_patterns_from_1  8.828  9.656 637.8339 10.4460 14.651 6266.660    10\n## 3 count_patterns_from_2  3.193  4.183 747.3586  4.7925  8.414 7422.810    10\n## 4 count_patterns_from_3  6.916  7.313 459.2330  8.1025 10.659 4508.255    10\n
\n\n

Visualmente:

\n\n
df %>% \n  ggplot(df, mapping=aes(y=expr, x=time, fill=expr)) +\n  geom_violin() +\n  theme_elegante_std() +\n  scale_x_log10(\n    breaks = scales::trans_breaks(\"log10\", function(x) 10^x),\n    labels = scales::trans_format(\"log10\", scales::math_format(10^.x))\n  ) +\n  labs(title = paste(\"Performance\"), \n     subtitle = paste(\"de las rutinas precalculadas\") , \n     caption = \"\", \n     y = \"\", \n     x = \"microsegundos\"\n    ) \n
\n\n

\n\n

Como era de esperar se comportan bastante parecido todas. ¿Y las otras?\nhay varias soluciones no precalculads que me intrigan ver como\nfuncionan. (Veremos… TO BE CONTINUED)

\n\n

Lecciones aprendidas

\n\n\n", "date_published": "2021-07-07T00:00:00-03:00" }, { "id": "https://pmoracho.github.io/blog/2021/06/30/la-pasta-datos/", "url": "https://pmoracho.github.io/blog/2021/06/30/la-pasta-datos/", "title": "Pasta - Lo que aprendí hasta hoy", "content_html": "

La recetas clásicas

\n\n

Por persona/porción:

\n\n

Con huevo

\n\n\n\n

En un bowl la harina y la sal, en el centro el huevo y el aceite/agua, mezclar\nhasta poder amasar con la mano. Amasar sobre una superficie limpia, unos cuantos\nminutos hasta tener un lindo “bollo” de exterior suave y de consistencia\nelástica (lo apretás y la superficie vuelve a su lugar). Tapar y dejar descansar\nen la heladera unos 30 minutos al menos.

\n\n

Sin huevo

\n\n\n\n

Las formas

\n\n\n", "date_published": "2021-06-30T00:00:00-03:00" }, { "id": "https://pmoracho.github.io/blog/2020/07/25/Rstudio-Server-con-docker/", "url": "https://pmoracho.github.io/blog/2020/07/25/Rstudio-Server-con-docker/", "title": "Rstudio Server para múltiples usuarios con Docker", "content_html": "

Rstudio Server con docker

\n\n

Iniciamos el servicio de docker

\n\n
sudo systemctl start docker\n
\n\n

Rstudio es uno de los mejores IAE - Integrated análisis environment, si acabo de inventar el término. Es un placer trabajar con esta herramienta, es muy liviana y muy sencilla de instalar, de hecho una vez instalado es portable, yo suelo tener en un pendrive un Rstudio + R y tenerlo a mano por cualquier cosa. Como si fuera poco es multiplataforma.

\n\n

Primero que nada, hay que notar la diferencia entre imagen y contenedor, cuando haces algo como esto:

\n\n
docker run rocker/tidyverse\n
\n\n

Lo que hace docker es: (1) crear un contenedor que no es más que una instancia de la imagen rocker/tidyverse (2) Inicia dicho contenedor. En la práctica lo que vamos a intentar hacer es crear un contenedor especial que ajustaremos a nuestras necesidades y luego simplemente iniciaremos dicho contenedor.

\n\n

A partir de aquí trabajaremos por línea de comando, a modo de prueba de concepto usaré un usuario común, la maquina virtual funcionará perfectamente siempre que usemos el mismo usuario para crearla, crear las carpetas iniciales e iniciarla.

\n\n

1. Configuración del entorno en la maquina física

\n\n

Para cualquiera de lo usuarios que vayamos a crear en nuestra maquina virtual, necesitaremos una carpeta personal para cada uno, en ellos no solo se salvarán las configuraciones personales, sino que también se alojara cualquier paquete adicional que el usuario instale. Por lo que mínimamente necesitaremos una carpeta home general y obviamente que este fuera del ámbito del contenedor, para que los cambios sean persistentes. Podemos hacer esto:

\n\n
mkdir ~/rstudio_home\n
\n\n

2. Creamos el contenedor

\n\n

Ahora sí crearemos nuestra real maquina virtual, la imagen rocker/tidyverse requiere que definamos un usuario inicial, el puerto y asimismo, necesitaremos definir un volumen para el home de cualquier usuario

\n\n
docker run -d -p 8787:8787 -e USER=rstudio -e PASSWORD=rstudio --name rstudio-server -v ~/rstudio_home:/home rocker/tidyverse\n
\n\n

Detalle:

\n\n\n\n

Si esto funcionó correctamente, se habrá impreso por terminal el ID de este nuevo contenedor, y se habrá iniciado el mismo. Podemos verificarlo accediendo mediante el navegador a http://localhost:8787/, nos debiera aparecer la página de login, dónde podremos ingresar el hasta ahora único usuario que tenemos. También podremos verificar la existencia de este contenedor mediante docker container ls y a partir de ahora nos olvidamos de la imagen y trabajaremos con este contenedor, por ejemplo para detenerlo docker container stop rstudio-server, para iniciarlo docker container start rstudio-server, o incluso removerlo docker container rm rstudio-server.

\n\n

3. Agregar usuarios

\n\n

En la práctica, nuestra maquina o contenedor, está corriendo un Linux muy básico y una instancia de Rstudio Server, este último define sus usuarios a partir de los usuarios del sistema operativo, por lo que para conseguir más usuarios deberemos simplemente “entrar” al Linux del contenedor y darlos de alta.

\n\n

Vamos a abrir una terminal pero en nuestro rstudio-server:

\n\n
docker exec -it rstudio-server bash\n
\n\n

Esto abrirá un bash dentro de nuestro contenedor, nos daremos cuenta por que seguramente habrá cambiado nuestro prompt por algo así:

\n\n
root@38645db9730e:/#\n
\n\n

Y ahora, para crear un usuario nuevo, simplemente haremos algo así:

\n\n
root@096cb40493d3:/# adduser usuario1 --gid 1000\nAdding user `usuario1' ...\nAdding new user `usuario1' (1001) with group `rstudio' ...\nCreating home directory `/home/usuario1' ...\nCopying files from `/etc/skel' ...\nNew password:\nRetype new password:\npasswd: password updated successfully\nChanging the user information for usuario1\nEnter the new value, or press ENTER for the default\n\tFull Name []: Usuario 1\n\tRoom Number []:\n\tWork Phone []:\n\tHome Phone []:\n\tOther []:\nIs the information correct? [Y/n] Y\nroot@096cb40493d3:/#\n
\n\n

El comando adduser usuario1 --gid 1000 dará de alta un nuevo usuario con dicho nombre y nos solicitará una serie de datos (El --gid 1000 es para que pertenezcan al mismo grupo del Rstudio Server), luego de completarlos habremos creado un nuevo usuario. Con este procedimiento podremos crear los tantos como vayamos a necesitar, francamente desconozco si Rstudio Server, en particular esta versión Open Source, impone algún limite. F3inalmente para salir: exit.

\n\n

Podremos verificar que se hayan creado las carpetas de cada usuario, revisando nuestro rstudio_home:

\n\n
|---> # ls -l  ~/rstudio_home/\ntotal 16\ndrwxr-xr-x 2 xxxxxxxx yyyyyyyy 4096 jul 24 23:26 usuario1\ndrwxr-xr-x 2     1002 yyyyyyyy 4096 jul 24 23:27 usuario2\ndrwxr-xr-x 2     1003 yyyyyyyy 4096 jul 24 23:34 usuario3\ndrwxr-xr-x 2     1004 yyyyyyyy 4096 jul 24 23:34 usuario4\n
\n\n

Notarás que hay una nueva carpeta por cada usuario que has creado, en ella seguramente hay un directorio R dónde van a parar todos los paquetes que cada usuario descargue. Lo otro que vas a notar, son usuarios y grupos “extraños” o “inconsistentes”, lo que ocurre e que estás carpetas se han creado con ids de usuarios y grupos propios de la maquina virtual y que no tienen un concordancia con los usuarios y grupos reales del sistema host. Esto no debería traer dificultades a la maquina virtual, pero sí alguna molestia en el host. El tema permisos lo dejo afuera de mi respuesta pero es algo que sin duda deberías profundizar, o más bien aquel que se encargue de administrar el sistema. Aquí hay información interesante para consultar.

\n\n

A partir de este momento, recuerda detener el contenedor cuando apaguen el servidor:

\n\n
docker container stop rstudio-server\n
\n\n

O volverlo a iniciar en cualquier momento

\n\n
docker container start rstudio-server\n
\n\n

Cada usuario debería poder ingresar a la url ttp://ip-del-servidor:8787 y logearse con los datos que le hemos asignado a cada uno, crear y salvar archivos persistentes y descargar e instalar paquetes propios de su login.

\n\n", "date_published": "2020-07-25T00:00:00-03:00" }, { "id": "https://pmoracho.github.io/blog/2020/07/05/visual-code-data/", "url": "https://pmoracho.github.io/blog/2020/07/05/visual-code-data/", "title": "Visual Code", "content_html": "

Visual Code

\n\n

Creo que se está convirtiendo en mi editor favorito. Hay cosas que viniendo de Vim se extrañanan, pero:

\n\n\n\n

Atajos de teclado funadamentales

\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
DetalleAtajo
Paleta de comandosctrl + shift + p
Quick openctrl + p
Confguraciónctrl + ,
Cerrar pestañactrl + w
Ocultar sidebarctrl + b
Ocultar Panelctrl + j
Abrir previsualizaciónctrl + k v
Multiples cursores Upctrl + shift + Up (esc para salir)
Multiples cursores Dwnctrl + shift + Dwn (esc para salir)
Salvar archivoctrl + s
Salvar archivo comoctrl + shift + s
Seleccionar Lineactrl + l
Comentar líneactrl + k ctrl + c
DesComentar líneactrl + k ctrl + u
Toggle comentctrl + shif + 7
Toggle Erroresctrl + shif + m
Modo Zenctrl + kz
\n\n

Atajos de teclado customizados

\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
DetalleAtajoComando
Saliralt + xworkbench.action.quit
Nueva terminal integradaalt + tworkbench.action.terminal.newInActiveWorkspace
Duplicar líneactrl + Shift + deditor.action.copyLinesDownAction
Selecionar palabraalt + weditor.action.addSelectionToNextFindMatch
Comentar códigoalt + weditor.action.addSelectionToNextFindMatch
Reformatear parrafoalt + q 
\n\n

Latex Workshop (extenión)

\n\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
DetalleAliasAtajo
Font: TextoFITctrl + lkbd>ctrl + t
Font: ItalicaFIIctrl + lkbd>ctrl + i
Font: EmfasisFBFctrl + lkbd>ctrl + b
\n\n

Trucos

\n\n

Extensiones

\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
ExtensiónDetalle 
Reflow paragraphReajustar los parráfos a un ancho de línea determinadoext install TroelsDamgaard.reflow-paragraph
Latex WorkshopPara editar Latex, imprescindibleext install James-Yu.latex-workshop
\n\n", "date_published": "2020-07-05T00:00:00-03:00" }, { "id": "https://pmoracho.github.io/blog/2020/05/24/30-dias-de-graficos-en-r/", "url": "https://pmoracho.github.io/blog/2020/05/24/30-dias-de-graficos-en-r/", "title": "30 días de gráficos en R", "content_html": "

Introducción

\n\n

A raíz de que el 12 de mayo se conmemora el nacimiento de Florence\nNightingale, la enfermera creadora del diagrama de área polar y\nreferente femenina de la visualización de datos, la comunidad\n@R4DS_es lanzó un lindo desafío,\nproyecto,\nuno distinto por día. Esta es la lista\ncompleta:

\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
díafechadesafíoCompletado?
112 de mayobarras / columnas
213 de mayolíneas
314 de mayopuntos / burbujas
415 de mayográficos con facetas
516 de mayodiagramas de arco
617 de mayográficos de donut
718 de mayográficos ridgeline
819 de mayográficos de contorno
920 de mayográficos de áreas apiladas
1021 de mayo¡explorar paletas de colores!
1122 de mayomapas de calor (heatmap)
1223 de mayográficos de paleta (lollipop)
1324 de mayovisualizar datos temporales
1425 de mayográficos de rectángulos/árbol
1526 de mayodendorgamas
1627 de mayográficos de waffle
1728 de mayodiagramas de sankey
1829 de mayovisualizar datos espaciales
1930 de mayográficos de flujo (stream graph)
2031 de mayoredes
211 de juniográficos con anotaciones
222 de juniovisualizar datos textuales
233 de juniográficos de proyección solar (sunburst)
244 de juniocoropletas
255 de juniográficos de violín
266 de juniodiagramas de marimekko
277 de junio¡gráficos animados!
288 de juniodiagramas de cuerdas
299 de juniográficos de coordenadas paralelas
3010 de juniodiagramas de área polar o de Florence Nightingale
\n\n

Objetivos

\n\n

En lo personal, mi idea es aprovechar este desafío para:

\n\n\n\n

Día 1: Gráfico de barras / Columnas

\n\n

Una gráfica de barras o columnas, tal vez una de las más clásicas,\nmuestra comparaciones numéricas entre una variable discreta y los\nvalores continuos que toma cada una de estas variables o “categorías”. A\ndiferencia de un histograma, los gráficos de barra no muestran un\ndesarrollo continuo entre las categorías.

\n\n

Este ejemplo muestra las diferencia de situación con respecto al\nCOVID-19 en Argentina y los países vecinos, en cuanto a cantidad de\ncasos y fallecidos. Usamos una escala logarítmica en el caso del eje y\npara que los enormes números de Brasil no nos oculten los datos del\nresto.

\n\n

Preparamos los datos:

\n\n
library(\"tidyverse\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read.csv(\"https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", na.strings = \"\", fileEncoding = \"UTF-8-BOM\",\n#                        stringsAsFactors = FALSE)\n\n# Datos para reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.mundial.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$dateRep,\"%d/%m/%Y\"))\ncovid.data %>% \n  filter(countriesAndTerritories %in% c('Argentina','Brazil', 'Chile', 'Bolivia', 'Paraguay', 'Uruguay')) %>% \n  group_by(countriesAndTerritories) %>% \n  summarize(casos = sum(cases), fallecidos = sum(deaths)) %>% \n  ungroup() %>% \n  select(pais = countriesAndTerritories, casos, fallecidos) %>% \n  gather(referencia, cantidad, -pais) -> plot_data \n\nkable(plot_data)\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
paisreferenciacantidad
Argentinacasos24748
Boliviacasos14644
Brazilcasos739503
Chilecasos142759
Paraguaycasos1187
Uruguaycasos846
Argentinafallecidos717
Boliviafallecidos487
Brazilfallecidos38406
Chilefallecidos2283
Paraguayfallecidos11
Uruguayfallecidos23
\n\n

La gráfica

\n\n
plot_data %>% \n  ggplot(aes(x=pais, fill=referencia, y=cantidad)) +\n    geom_col(position=position_dodge(width=1)) +\n    geom_text(aes(label = format(cantidad, digits=0, big.mark = ',')),  vjust = .6, hjust=1.1,\n              position = position_dodge(width=1)) +\n    coord_flip() +\n    scale_y_log10(\n      breaks = scales::trans_breaks(\"log10\", function(x) 10^x),\n      labels = scales::trans_format(\"log10\", scales::math_format(10^.x))\n    ) +\n    labs(title = paste(\"COVID-19\"), \n       subtitle = paste(\"Relación Casos / fallecidos Argentina y vecinos al: \", last_date) , \n       caption = \"Fuente: https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", \n       y = \"log10(Cantidad)\", \n       x = \"\"\n    ) +\n    scale_fill_discrete(palette = function(x) c(\"#67a9cf\", \"#ef8a62\")) +\n    theme_elegante_std(base_family = \"Assistant\") +\n    theme(plot.caption=element_text( margin=margin(1, 0, -.1, 0, \"cm\")),\n          plot.subtitle = element_text(margin=margin(0, 0, .8, 0, \"cm\")))\n
\n\n

\n\n

Día 2: Gráfico de líneas

\n\n

Son gráficos que muestras la evolución de una o más variables continuas\nen un determinado intervalo, generalmente de tiempo. Lo habitual es que\nel eje Y tenga un valor cuantitativo y el eje X tiene la secuencia que\nrepresenta el intervalo, En el plano cartesiano, se establecen los\npuntos X, Y y luego se van conectando estos mediante líneas rectas.

\n\n

En este ejemplo, la idea es mostrar la evolución de los casos de\nCOVID-19 en las dos provincias más importantes en cantidad de casos\nde la Argentina, desde el primer infectado (día 1), el eje x muestra\nel número de días y el y la cantidad de casos detectados dicho día.\nDibujamos puntos en cada x, y y luego unimos cada uno con un segmento,\nadicionalmente agregamos una curva que refuerza la visión de la\ntendencia.

\n\n

Los datos

\n\n
library(\"tidyverse\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\n\ncovid.data %>% \n  filter(osm_admin_level_4 %in% c('CABA', 'Buenos Aires')) %>% \n  mutate(fecha = as.Date(fecha, \"%d/%m/%Y\")) %>% \n  select(dia=dia_inicio, distrito=osm_admin_level_4, cantidad=nue_casosconf_diff) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
diadistritocantidad
1CABA1
4Buenos Aires1
7Buenos Aires8
8CABA1
9Buenos Aires1
9CABA1
\n\n

La gráfica

\n\n
plot_data %>% \n  ggplot(mapping=aes(x=dia, color=distrito, y=cantidad)) +\n    geom_line() +\n    geom_point() +\n    geom_smooth(method = 'loess',\n                formula = 'y ~ x', alpha = 0.2, size = 1, span = .3, se=FALSE) + \n    labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Variación de los casos diarios en CABA y Buenos Aires por día (al: \", last_date, \")\") , \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\", \n       y = \"Casos\", \n       x = \"Número de días desde el 1er caso\"\n  ) +\n  scale_color_discrete(palette = function(x) c(\"#67a9cf\", \"#ef8a62\")) +\n  theme_elegante_std(base_family = \"Assistant\") \n
\n\n

\n\n

Día 3: Una gráfica de puntos

\n\n

También se los conoce como gráficos de dispersión o “Scatterplot”.\nSuelen intentar mostrar la relación entre dos variables continuas por\nmedio de los patrones que se forman.

\n\n

En este ejemplo, me pregunto sí, ¿Hay relación entre el desarrollo\nhumano y la cantidad de infecciones?, para esto armamos un gráfico de\ndispersión dónde cada país tiene un punto que correlaciona las\nvariables: números de infectados (x) y el índice de desarrollo humano\n(y), además agregamos unas etiquetas que marcan los países en el\nextremo de cada variable y la Argentina y una recta de regresión a modo\nde tendencia.

\n\n

Los datos

\n\n
library(\"tidyverse\")\nlibrary(\"ggrepel\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Para descarga de los datos actualizados\n# covid.data <- read.csv(\"https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", na.strings = \"\", fileEncoding = \"UTF-8-BOM\", stringsAsFactors = FALSE)\n# hdi <- read.csv(\"https://data.humdata.org/dataset/05b5d8f1-9e7f-4379-9958-125c203d12ac/resource/4a7fd374-7e35-4c04-b7c8-25e5943aa476/downlo\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.mundial.Rda\",\"rb\"))\nhdi <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/hdi.Rda\",\"rb\"))\n\nhdi %>% \n  group_by(country_code) %>% \n  arrange(year) %>% \n  slice(n()) %>% \n  select(country_code, country, year, value) -> last_hdi\n\nlast_date <- max(as.Date(covid.data$dateRep,\"%d/%m/%Y\"))\npaises_de_interes <- c( 'Argentina',\n                       \"Niger\", \"Norway\", \"EEUU\", \"Mauritania\")\ncovid.data %>% \n  group_by(countriesAndTerritories, countryterritoryCode) %>% \n  summarize(casos = sum(cases), fallecidos = sum(deaths)) %>% \n  ungroup() %>% \n  inner_join(last_hdi,\n            by = c(\"countryterritoryCode\" = \"country_code\")\n            ) %>% \n  mutate(pais = ifelse(countriesAndTerritories == 'United_States_of_America', 'EEUU', countriesAndTerritories)) %>% \n  select(pais, casos, HDI = value) %>% \n  mutate(pais_etiquetado = ifelse(pais %in% paises_de_interes, paste0(pais, \" (casos: \", format(casos, digits=0, big.mark = ',', trim=TRUE), \" hdi: \", HDI, \")\"), NA)) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
paiscasosHDIpais_etiquetado
Afghanistan275320.468NA
Albania17880.716NA
Algeria113850.717NA
Andorra8550.830NA
Angola1550.526NA
Antigua_and_Barbuda260.774NA
\n\n

La gráfica

\n\n
plot_data %>% \n  ggplot(aes(x=HDI, y=casos)) +\n    geom_point(color = \"#67a9cf\", alpha=.5, size=3) +\n    geom_smooth(method = 'lm',formula='y ~ x', se=FALSE, color=\"#ef8a62\") +\n    geom_label_repel(mapping = aes(label = pais_etiquetado),\n                     color=\"#67a9cf\",family = \"Assistant\", vjust = -1.2, hjust = 1.1) +\n                     # nudge_x = 1, nudge_y = 5, color=\"#67a9cf\",\n                     # vjust = -2, family = \"Assistant\",  \n                     # direction  = \"y\",\n                     # hjust = 2) +\n    scale_y_log10(\n      breaks = scales::trans_breaks(\"log10\", function(x) 10^x),\n      labels = scales::trans_format(\"log10\", scales::math_format(10^.x))\n    ) +\n    labs(title = paste(\"COVID-19\"), \n         subtitle = paste0(\"¿Hay relación entre el desarrollo humano y la cantidad de infecciones?\\n (Datos al: \", last_date, \")\") , \n         caption = \"Fuente: https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", \n         y = \"log10(Cantidad de infectados)\", \n         x = \"Human development Index (2013)\"\n    ) +\n    theme_elegante_std(base_family = \"Assistant\") \n
\n\n

\n\n

Día 4: Facetas

\n\n

Las “Facetas” no es un tipo de gráfico sino más bien una forma de\nmostrar uno de estos. Cuando se tiene múltiples variables, muchas veces\nresulta confuso verlas todas en un mismo gráfico, el facetado permite\ndividir cada variable o grupo en múltiples graficos similares.

\n\n

Los datos

\n\n
library(\"tidyverse\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\n\ncovid.data %>% \n  mutate(fecha = as.Date(fecha, \"%d/%m/%Y\")) %>% \n  select(dia=dia_inicio, distrito=osm_admin_level_4, cantidad=nue_casosconf_diff) %>% \n  complete(distrito, dia, fill=list(cantidad=0)) %>% \n  arrange(distrito, dia) -> data\n\ndata %>% \n  inner_join(data %>% \n               group_by(distrito) %>% \n               summarize(cantidad = sum(cantidad)) %>% \n               arrange(-cantidad) %>% \n               top_n(9), by = c(\"distrito\"), suffix=c(\"\",\".y\")) %>% \n  select(dia, distrito, cantidad) %>% \n  arrange(dia, distrito) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
diadistritocantidad
1Buenos Aires0
1CABA1
1Chaco0
1Córdoba0
1Mendoza0
1Neuquén0
\n\n

La gráfica

\n\n
plot_data %>% \n  ggplot(mapping=aes(x=dia, y=cantidad)) +\n  geom_line(color=\"#67a9cf\") +\n  geom_point(color=\"#67a9cf\") +\n  geom_smooth(method = 'loess',\n              formula = 'y ~ x', alpha = 0.2, size = 1, span = .3, se=FALSE, color=\"#ef8a62\") + \n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Variación de casos diarios en los distritos con más casos (al: \", last_date, \")\") , \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\", \n       y = \"Número de casos\", \n       x = \"Número de días desde el 1er caso\"\n  ) +\n  facet_wrap(~distrito,scales=\"free\") +\n  theme_elegante_std(base_family = \"Assistant\") \n
\n\n

\n\n

Una linda visualización mediante geofaceteAR:

\n\n

Este paquete permite facetar siguiendo la estructura geografica, en esta\ncaso el de las provincias de Argentina, da una visión muy atractiva y\nclara de los datos, ya no es necesario iterar visualmente hasta\nencontrar la información de un estado, sino que accedemos a la gráfica\nde forma más directa.

\n\n
library(\"geofaceteAR\")\n\nargentina_grid <-  data.frame(\n  col = c(1, 3, 5, 1, 2, 1, 3, 4, 2, 2, 4, 1, 3, 3, 4, 1, 2, 2, 1, 1, 2, 1, 1, 1),\n  row = c(1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 8, 9, 10),\n  code = c(\"AR-Y\", \"AR-P\", \"AR-N\", \"AR-A\", \"AR-T\", \"AR-K\", \"AR-H\", \"AR-W\", \"AR-G\", \"AR-X\", \"AR-E\", \"AR-F\", \"AR-S\", \"AR-B\", \"AR-C\", \"AR-J\", \"AR-D\", \"AR-L\", \"AR-M\", \"AR-Q\", \"AR-R\", \"AR-U\", \"AR-Z\", \"AR-V\"),\n  name_es = c(\"Jujuy\", \"Formosa\", \"Misiones\", \"Salta\", \"Tucumán\", \"Catamarca\", \"Chaco\", \"Corrientes\", \"Santiago del Estero\", \"Córdoba\", \n              \"Entre Ríos\", \"La Rioja\", \"Santa Fe\", \"Buenos Aires\", \"CABA\", \"San Juan\", \"San Luis\", \"La Pampa\", \"Mendoza\", \"Neuquén\", \"Río Negro\", \n              \"Chubut\", \"Santa Cruz\", \"Tierra del Fuego\"),\n  stringsAsFactors = FALSE\n)\n\ndata %>% \n  filter(distrito!='Indeterminado') %>% \n  ggplot(mapping=aes(x=dia, y=cantidad)) +\n  geom_line(color=\"#67a9cf\") +\n  geom_point(color=\"#67a9cf\") +\n  geom_smooth(method = 'loess',\n              formula = 'y ~ x', alpha = 0.2, size = 1, span = .3, se=FALSE, color=\"#ef8a62\") + \n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Variación de casos diarios en los distritos con más casos (al: \", last_date, \")\") , \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\", \n       y = \"Número de casos\", \n       x = \"Número de días desde el 1er caso\"\n  ) +\n  facet_geo(~ distrito, grid = argentina_grid, scales = \"free_y\") +\n  theme_elegante_std(base_family = \"Assistant\") \n
\n\n

\n\n

Día 5: Un gráfico de Arcos

\n\n

Los gráficos de arco forman parte de los diagramas de red, en este caso\nlos nodos se colocan sobre un eje horizontal y la líneas o arcos señalan\nlas relaciones entre cada nodo. Eventualmente se puede ajustar el grosor\nde la líne para incluir una nueva dimensión. En lo personal me resulta\ndifíciles de leer pero entiendo que para algunas aplicaciones\nespecíficas pueden ser útiles. En este ejemplo, trato de mostrar las\nrelaciones musicales interpresonales de Luis Alberto Spinetta en su\nprimera etapa como músico.

\n\n

Los datos

\n\n
library(\"tidyverse\")\nlibrary(\"tidygraph\")\nlibrary(\"ggraph\")\nlibrary(\"igraph\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\ndata <- structure(list(persona = structure(c(10L, 10L, 10L, 10L, 10L, \n                                             10L, 6L, 6L, 12L, 12L, 12L, 12L, 8L, 9L, 2L, 7L, 7L, 3L, 3L, \n                                             1L, 11L, 5L, 4L, 4L, 13L), .Label = c(\"Angel del Guercio\", \"Carlos Xartuch\", \n                                                                                   \"Daniel Albertelli\", \"Edelmiro Molinari\", \"Eduardo Miró\", \"Emilio del Guercio\", \n                                                                                   \"Guido Meda\", \"Hector Nuñez\", \"Horacio Soria\", \"Luis Alberto Spinetta\", \n                                                                                   \"Ricardo Miró\", \"Rodolfo Garcia\", \"Santiago Novoa\"), class = \"factor\"), \n                       grupo = c(\" Bundleman\", \" Los Larkings\", \" Los Masters\", \n                                 \" Los Mods\", \" Los Sbirros\", \" Almendra (1967-1969)\", \" Bundleman\", \n                                 \" Almendra (1967-1969)\", \" Los Larkings\", \" Los Masters\", \n                                 \" Los Mods\", \" Almendra (1967-1969)\", \" Los Larkings\", \" Los Larkings\", \n                                 \" Los Larkings\", \" Los Masters\", \" Los Mods\", \" Los Masters\", \n                                 \" Los Mods\", \" Los Sbirros\", \" Los Sbirros\", \" Los Sbirros\", \n                                 \" Los Sbirros\", \" Almendra (1967-1969)\", \" Los Sbirros\")), class = \"data.frame\", row.names = c(NA, \n                                                                                                                                -25L))\n\ndata %>% \n  select(from = persona, to = grupo, grupo=grupo, name=persona) -> prepared.data\n\nkable(head(prepared.data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
fromtogruponame
Luis Alberto SpinettaBundlemanBundlemanLuis Alberto Spinetta
Luis Alberto SpinettaLos LarkingsLos LarkingsLuis Alberto Spinetta
Luis Alberto SpinettaLos MastersLos MastersLuis Alberto Spinetta
Luis Alberto SpinettaLos ModsLos ModsLuis Alberto Spinetta
Luis Alberto SpinettaLos SbirrosLos SbirrosLuis Alberto Spinetta
Luis Alberto SpinettaAlmendra (1967-1969)Almendra (1967-1969)Luis Alberto Spinetta
\n\n

La gráfica

\n\n
tbl_graph(edges=prepared.data, directed = TRUE) %>% \n  ggraph(layout = \"linear\") +\n  geom_edge_arc(aes(color=grupo),  edge_width=1.5, edge_alpha = 0.5, fold = TRUE,) +\n  geom_node_point(size = 2, color=\"#67a9cf\") +\n  geom_node_text(aes(label = str_wrap(name,13)), size = 3, nudge_y =-.7, angle = 90, fontface = \"bold\",  hjust=.5) +\n  coord_cartesian(clip = \"off\") + \n  theme_elegante_std(base_family = \"Assistant\") +\n  theme(axis.title.x=element_blank(),\n        axis.text.x=element_blank(),\n        axis.ticks.x=element_blank(),\n        axis.title.y=element_blank(),\n        axis.text.y=element_blank(),\n        axis.ticks.y=element_blank(),\n        legend.position = \"none\") +\n  labs(title = \"Historia musical de Luis Albero Spinetta\", \n       subtitle = \"Los comienzos\"\n  ) \n
\n\n

\n\n

Día 6: Un gráfico de aros de cebolla

\n\n

Odio las donas, pero bueno, en realidad se llaman “donuts plots”, una\nvariante de un clásico gráfico de torta, solo sin el centro, a\ndiferencia de los últimos, los gráficos de donas, al no mostrar el área\ncompleta, logran que el usuario se enfoque más en la proporción de cada\nsector, lo cual mejora la percepción de los cambios. Además,\neventualmente permiten usar el área del centro para agregar más\ninformación.

\n\n

Los datos

\n\n
library(\"tidyverse\")\nlibrary(\"ggrepel\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nbreak_porc <- .95\ncovid.data %>% \n  select(distrito=osm_admin_level_4, casos=nue_casosconf_diff) %>% \n  group_by(distrito) %>% \n  summarise(casos=sum(casos)) %>% \n  mutate(porc = casos / sum(casos)) %>%\n  ungroup() %>% \n  arrange(-porc) %>% \n  mutate(cporc = cumsum(porc),\n         distrito = ifelse(cporc < break_porc, distrito, 'Resto')) %>% \n  group_by(distrito) %>% \n  summarise(casos = sum(casos),\n            porc = sum(round(porc*100,2))) -> data\n\ndata$porc[data$distrito == 'Resto'] <- 100 - sum(data$porc[data$distrito != 'Resto'])\ndata %>% \n  mutate( ymax = cumsum(porc),\n          ymin = lag(ymax, default=0)\n  ) -> data\n\nmac_perc <- sum(data$porc[data$distrito != 'Resto'])\ndata$distrito <- with(data, reorder(distrito, porc))\n\nkable(head(data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
distritocasosporcymaxymin
Buenos Aires959038.7338.730.00
CABA1196548.3287.0538.73
Chaco11184.5191.5687.05
Resto15986.4698.0291.56
Río Negro4911.98100.0098.02
\n\n

La gráfica

\n\n
data %>% \n  ggplot(aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=distrito)) +\n  geom_rect(color=\"gray90\", size=1.2) +\n  geom_label_repel(mapping = aes(x=3.5, y=ymin + (ymax - ymin)/2,\n                                 colour =  ifelse(porc > 10, 2, 0),\n                                 label = paste0(distrito, \": \", format(porc, digits=2, trim=FALSE), \"%\\nCasos:\", \n                                                format(casos, big.mark = \",\", trim=FALSE))),\n                   family = \"Assistant\", \n                   nudge_y = 1,\n                   nudge_x = 1) +\n  coord_polar(theta=\"y\") + # Try to remove that to understand how the chart is built initially\n  xlim(c(2, 4)) +\n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Distribución del \", mac_perc , \"% de los casos por distrito\\n (Datos al: \", last_date, \")\") , \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\"\n  ) +\n  theme_elegante_std(base_family = \"Assistant\") +\n  theme(axis.title.x=element_blank(),\n        axis.text.x=element_blank(),\n        axis.ticks.x=element_blank(),\n        axis.title.y=element_blank(),\n        axis.text.y=element_blank(),\n        axis.ticks.y=element_blank(),\n        legend.position = \"none\") +\n  scale_fill_brewer(palette = \"Blues\")\n
\n\n

\n\n

Día 7: Gráficos “Ridgeline”

\n\n

Los graficos “ridgeline” mapean la distribución de múltiples variables\ncontinuas con un conjunto de variables categoricas en la forma de curvas\n“suaves” que permite comparar cada categoría:

\n\n

Los datos:

\n\n
library(\"tidyverse\")\nlibrary(\"ggridges\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nbreak_porc <- .95\n\ncovid.data %>% \n  mutate(distrito = osm_admin_level_4, \n         casos = nue_casosconf_diff) %>% \n  select(distrito, casos) -> data\n\ndata %>% \n  group_by(distrito) %>% \n  summarise(casos=sum(casos)) %>% \n  mutate(porc = casos / sum(casos)) %>%\n  arrange(-porc) %>% \n  mutate(cporc = cumsum(porc),\n         distrito = ifelse(cporc < break_porc, distrito, 'Resto')) %>% \n  group_by(distrito) %>% \n  summarise(casos = sum(casos),\n            porc = sum(round(porc*100,2))) -> principales\n\nperc <- sum(principales$porc[principales$distrito != 'Resto'])\n\ndata %>% \n  left_join(principales, by=\"distrito\") %>% \n  mutate(distrito = ifelse(is.na(casos.y), 'Resto', distrito)) %>% \n  select(distrito, casos=casos.x) -> plot_data\n  \nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
distritocasos
CABA1
Resto0
Resto0
Buenos Aires1
Resto0
Resto0
\n\n

La gráfica:

\n\n
plot_data %>% \n  ggplot(aes(x = casos, y = distrito, fill = distrito)) +\n    geom_density_ridges() +\n    theme(legend.position = \"none\") +\n    labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Distribución de casos diarios (al: \", last_date, \")\\nDetalle en los distritos que suman el \", perc, \"% de los casos totales del país\") , \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\", \n       y = \"Distritos\", \n       x = \"Cantidades de casos diarios\"\n    ) +\n    scale_x_continuous(breaks = c(c(0,5, 10, 20, 50), seq(from=75, to=max(data$casos)+25, by = 25))) +\n    theme_elegante_std(base_family = \"Assistant\") +\n    theme(legend.position = \"none\")  \n
\n\n

\n\n

Día 8: Gráfico de contornos

\n\n

Este tipo de gráficos básicamente une puntos x e y que comparte un mismo\nvalor de una tercer variable z, el caso típico, son los mapa\ncartográficos , cuyas lineas unen puntos de semejante altura.

\n\n
library(\"tidyverse\")\nlibrary(\"ggrepel\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Para descarga de los datos actualizados\n# covid.data <- read.csv(\"https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", na.strings = \"\", fileEncoding = \"UTF-8-BOM\", stringsAsFactors = FALSE)\n# hdi <- read.csv(\"https://data.humdata.org/dataset/05b5d8f1-9e7f-4379-9958-125c203d12ac/resource/4a7fd374-7e35-4c04-b7c8-25e5943aa476/downlo\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.mundial.Rda\",\"rb\"))\nhdi <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/hdi.Rda\",\"rb\"))\n\nhdi %>% \n  group_by(country_code) %>% \n  arrange(year) %>% \n  slice(n()) %>% \n  select(country_code, country, year, value) -> last_hdi\n\n\nlast_date <- max(as.Date(covid.data$dateRep,\"%d/%m/%Y\"))\npaises_de_interes <- c( 'Argentina',\n                        \"Niger\", \"Norway\", \"EEUU\", \"Mauritania\")\ncovid.data %>% \n  group_by(countriesAndTerritories, countryterritoryCode) %>% \n  summarize(casos = sum(cases), fallecidos = sum(deaths)) %>% \n  ungroup() %>% \n  inner_join(last_hdi,\n             by = c(\"countryterritoryCode\" = \"country_code\")\n  ) %>% \n  mutate(pais = ifelse(countriesAndTerritories == 'United_States_of_America', 'EEUU', countriesAndTerritories)) %>% \n  select(pais, casos, fallecidos, HDI = value) %>% \n  mutate(pais_etiquetado = ifelse(pais %in% paises_de_interes, paste0(pais, \" (casos: \", format(casos, digits=0, big.mark = ',', trim=TRUE), \" hdi: \", HDI, \")\"), NA)) -> plot_data\n  \nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
paiscasosfallecidosHDIpais_etiquetado
Afghanistan275325460.468NA
Albania1788390.716NA
Algeria113858110.717NA
Andorra855520.830NA
Angola15570.526NA
Antigua_and_Barbuda2630.774NA
\n\n

La gráfica:

\n\n
plot_data %>% \n  ggplot(aes(x=HDI, y=casos)) +\n  geom_point(color = \"#67a9cf\", alpha=.5, size=3) +\n  geom_smooth(method = 'lm',formula='y ~ x', se=FALSE, color=\"#ef8a62\") +\n  geom_density2d(contour = TRUE, n = 1000) +\n  geom_label_repel(mapping = aes(label = pais_etiquetado),\n                   color=\"#67a9cf\",family = \"Assistant\", vjust = -1.2, hjust = 1.1, fontface=\"bold\") +\n\n  scale_y_log10(\n    breaks = scales::trans_breaks(\"log10\", function(x) 10^x),\n    labels = scales::trans_format(\"log10\", scales::math_format(10^.x))\n  ) +\n  labs(title = paste(\"COVID-19\"), \n       subtitle = paste0(\"¿Hay relación entre el desarrollo humano y la cantidad de infecciones?\\n (Datos al: \", last_date, \")\") , \n       caption = \"Fuente: https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", \n       y = \"log10(Cantidad de infectados)\", \n       x = \"Human development Index (2013)\"\n  ) +\n  theme_elegante_std(base_family = \"Assistant\")\n
\n\n

\n\n

Día 9: Areas apiladas

\n\n

Es una variante del gráfico de areas, que a su vez es una variante del\nde lineas, solo que en este caso se “apilan” más de una variable, lo que\nes útil para compararlas.

\n\n
library(\"tidyverse\")\nlibrary(\"ggrepel\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\ncovid.data %>% \n  mutate(fecha=as.Date(fecha,\"%d/%m/%Y\")) %>% \n  group_by(dia_inicio,fecha) %>% \n  summarize(casos = sum(nue_casosconf_diff),\n         fallecidos = sum(nue_fallecidos_diff)) %>% \n  select(dia = dia_inicio, fecha, casos, fallecidos) %>% \n  pivot_longer(-c(\"dia\", \"fecha\"), names_to = 'metrica', values_to='cantidades') -> data\n\ndata %>% \n  left_join(data %>% \n              group_by(metrica) %>%\n              summarise(cantidades = max(cantidades), maximo = TRUE),\n            by = c(\"metrica\", \"cantidades\")\n  ) %>% \n  mutate(maximo = ifelse(maximo, paste0(\"Pico de \", metrica, \" de \", cantidades, \"\\nel \", fecha), NA)) -> plot_data\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
diafechametricacantidadesmaximo
12020-03-02casos1NA
12020-03-02fallecidos0NA
22020-03-03casos0NA
22020-03-03fallecidos0NA
32020-03-04casos0NA
32020-03-04fallecidos0NA
\n\n

La gráfica:

\n\n
plot_data %>% \n  ggplot(aes(x=dia, y=cantidades, fill=metrica, color=metrica)) + \n  geom_area(alpha=0.6 , size=1) +\n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Variación de casos y fallecimientos por día (al: \", last_date, \")\") , \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\", \n       y = \"Cantidades diarias\", \n       x = \"Número de días desde el 1er caso\"\n  ) +\n  geom_label_repel(mapping = aes(label = maximo),\n                   color = \"white\",\n                   segment.color=\"gray90\",\n                   family = \"Assistant\", \n                   vjust = -1,\n                   hjust = 1.5,\n                   box.padding = 1,\n                   show.legend = FALSE) +\n  scale_fill_discrete(palette = function(x) c(\"#67a9cf\", \"#ef8a62\")) +\n  scale_color_discrete(palette = function(x) c(\"#67a9cf\", \"#ef8a62\")) +\n  guides(color = FALSE, label=FALSE) +\n  theme_elegante_std(base_family = \"Assistant\")\n
\n\n

\n\n

Día 10: Exploración de paletas de colores

\n\n

Nada del otro mundo, un script para generar una gráfica de ejemplo de\nuna paleta determinada de colores, en este ejemplo explorando la del\npaquete [wesanderson]

\n\n
library(\"tidyverse\")\nlibrary(\"wesanderson\")\nlibrary(\"gridExtra\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\ncolores <- 20\npaletas <- names(wes_palettes)\n\ndata.frame(x=factor(1:colores), y=1) %>% \n  ggplot(aes(x = x, y = y, fill = x)) + \n  geom_col() +\n  theme_elegante_std(base_family = \"Assistant\") +\n  theme(axis.text.x=element_blank(),\n        axis.ticks.x=element_blank(),\n        axis.title.y=element_blank(),\n        axis.text.y=element_blank(),\n        axis.ticks.y=element_blank(),\n        legend.position = \"none\")  -> g\n\nplots <- list()\nfor (p in paletas) {\n  plots[[p]] <- g + scale_fill_manual(values = wes_palette(colores, name = p, type = \"continuous\"), name = \"\") +\n    labs(x = p)\n}\ngrid.arrange(grobs = plots, ncol = 2)\n
\n\n

\n\n

Día 11: Mapa de Calor

\n\n

Un mapa de calor muestra la variación en una determinada variable (por\nlo general continua) mediante el uso del color. En este ejemplo mapeamos\ntres variables, el distrito o provincia (categórica), la cantidad de\ndías desde el primer contagio (categórica) y la variable continua de la\ncantidad de casos que es la que mapeamos a la dimensión del color.

\n\n
library(\"tidyverse\")\nlibrary(\"zoo\")\nlibrary(\"forcats\")\nlibrary(\"scales\")\n  if (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nfirst_date <- min(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nndias <- max(covid.data$dia_inicio)\n\n\ndias <- expand.grid(distrito = unique(covid.data$osm_admin_level_4),\n                    dia = 1:ndias,\n                    stringsAsFactors = FALSE)\ndias$fecha = first_date + dias$dia - 1\ndias$casos = 0\n\ndias_rolling <- 3\ndias_ventana <- 14\n\ndias %>% \n  left_join(covid.data, by=c(\"distrito\" = \"osm_admin_level_4\", \"dia\" = \"dia_inicio\")) %>% \n  mutate(casos = replace_na(nue_casosconf_diff, 0)) %>% \n  select(dia, distrito, fecha=fecha.x, casos)  %>% \n  group_by(dia, distrito, fecha) %>% \n  summarise(casos = sum(casos)) %>%\n  arrange(distrito, dia) %>% \n  group_by(distrito) %>% \n  filter(dia >= ndias - dias_ventana - dias_rolling,\n         distrito != 'Indeterminado') %>% \n  mutate(roll_casos_3 = rollmean(casos, dias_rolling, align='right', fill=0),\n         s_roll_casos_3 = replace_na((roll_casos_3-min(roll_casos_3))/(max(roll_casos_3)-min(roll_casos_3)),0),\n         label_casos = casos\n  ) %>% \n  filter(dia >= ndias - dias_ventana ) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
diadistritofechacasosroll_casos_3s_roll_casos_3label_casos
83Buenos Aires2020-05-23236197.00000.4371302236
84Buenos Aires2020-05-24315236.66670.5251479315
85Buenos Aires2020-05-25299283.33330.6286982299
86Buenos Aires2020-05-26273295.66670.6560651273
87Buenos Aires2020-05-27296289.33330.6420118296
88Buenos Aires2020-05-28254274.33330.6087278254
\n\n

La gráfica:

\n\n
plot_data %>% \n  ggplot(aes(x = dia, y =   fct_reorder(distrito, casos), fill = s_roll_casos_3)) + \n    geom_tile(colour=\"gray80\", size=0.2) +\n    geom_text(aes(label=label_casos, color = s_roll_casos_3 > .7)) +\n    scale_color_manual(guide = FALSE, values = c(\"gray30\", \"gray90\")) +\n    scale_fill_distiller(palette = \"YlGnBu\", direction = 1, na.value = \"white\") +\n    labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Evolución diaria de los casos por distrito (últimos \", dias_ventana, \" días al: \", last_date, \")\\n\",\n                         \"Los números son casos diarios, la escala de color en función del promedio de casos de los últimos \", dias_rolling, \" días\") , \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\", \n       x = \"Últimos días\"\n    ) +\n    theme_elegante_std(base_family = \"Assistant\") + \n    scale_x_continuous(breaks = seq(ndias - dias_ventana, ndias, by = 1)) +\n    theme(axis.title.y=element_blank(),\n        legend.position = \"none\") \n
\n\n

\n\n

Día 12: Un gráfico lolipop

\n\n

Es básicamente un gráfico de barras, pero se remplaza la barra por una\nlínea que se completa con un punto al final dela barra.

\n\n
library(\"tidyverse\")\nlibrary(\"forcats\")\nlibrary(\"countrycode\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Para descarga de los datos actualizados\n# covid.data <- read.csv(\"https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", na.strings = \"\", fileEncoding = \"UTF-8-BOM\", stringsAsFactors = FALSE)\n# hdi <- read.csv(\"https://data.humdata.org/dataset/05b5d8f1-9e7f-4379-9958-125c203d12ac/resource/4a7fd374-7e35-4c04-b7c8-25e5943aa476/downlo\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.mundial.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$dateRep,\"%d/%m/%Y\"))\ncovid.data %>% \n  group_by(countryterritoryCode) %>% \n  summarize(casos = sum(cases), fallecidos = sum(deaths)) %>% \n  arrange(-casos) %>% \n  mutate(nr = row_number()) %>% \n  select(code_pais = countryterritoryCode, casos, fallecidos, nr) -> data\n\nmedia_casos <- mean(data$casos)\nmedia_fallecidos <- mean(data$fallecidos)\n\ndata %>% \n  filter(nr <= 50) %>% \n  mutate(sobre_media = casos > media_casos,\n         pais = paste0(countrycode(code_pais, origin = 'iso3c', destination = 'un.name.es'), \" (\", nr, \")\")) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
code_paiscasosfallecidosnrsobre_mediapais
USA21910521184341TRUEEstados Unidos de América (1)
BRA978142477482TRUEBrasil (2)
RUS56109177903TRUEFederación de Rusia (3)
IND380532125734TRUEIndia (4)
GBR300469422885TRUEReino Unido de Gran Bretaña e Irlanda del Norte (5)
ESP245268NA6TRUEEspaña (6)
\n\n

La gráfica:

\n\n
plot_data %>% \n  ggplot(aes(x=fct_reorder(pais, -nr), y=casos, color = sobre_media)) +\n  geom_segment(aes( y=0 , xend = pais, yend = casos)) + \n  geom_point() +\n  coord_flip() +\n  geom_text(aes(label = format(abs(casos), digits=0, big.mark = ','),\n                vjust = .5,\n                hjust = -.1),\n            position = position_dodge(width=1)) +\n  labs(title = paste(\"COVID-19 en el mundo\"), \n       subtitle = paste(\"Casos por pais al: \", last_date, '\\nLos primeros 50 países') , \n       caption = \"Fuente: https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", \n       y = \"Casos\", \n       x = \"\"\n  ) +\n  scale_y_continuous(breaks = scales::pretty_breaks(n = 5), limits = c(0, max(data$casos) * 1.01),\n                     labels = scales::comma) +\n\n  scale_color_manual(labels = c(\"Sobre la media\", \"Debajo de la media\"), values = c(\"#67a9cf\", \"#ef8a62\")) +\n  theme_elegante_std(base_family = \"Assistant\") \n
\n\n

\n\n

Día 13: Serie temporal

\n\n

Nada del otro mundo, el clásico gráfico de lineas, en el eje X tenemos\nel tiempo y en el Y un precio, en este caso el vaalor del dólar en\nArgentina en los últimos años, con algunas anotaciones, como ser los\ncomiencos de cada presidencia.

\n\n
library(\"tidyverse\")\nlibrary(\"ggrepel\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\npresidencias <- data.frame(fecha = as.Date(c('2019-12-10', '2015-12-10')), presidencia=c('Alberto Fernández', 'Mauricio Macri'))\n\n\n# dolar <- read.csv(\"https://apis.datos.gob.ar/series/api/series/?ids=168.1_T_CAMBIOR_D_0_0_26&limit=5000&format=csv\", na.strings = \"\", fileEncoding = \"UTF-8-BOM\",\n#                        stringsAsFactors = FALSE)\ndolar <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/dolar.Rda\",\"rb\"))\n\ndolar$indice_tiempo = as.Date(dolar$indice_tiempo, format = \"%Y-%m-%d\")\n\nkable(head(dolar))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
indice_tiempotipo_cambio_bna_vendedor
2014-11-038.49
2014-11-048.51
2014-11-058.51
2014-11-068.51
2014-11-078.51
2014-11-088.51
\n\n

La gráfica:

\n\n
dolar %>% \n  ggplot(mapping = aes(x=indice_tiempo, y=tipo_cambio_bna_vendedor)) + \n  geom_line(size = 1, color=\"#67a9cf\") +\n  geom_vline(data = presidencias,\n             mapping = aes(xintercept=fecha),\n             color = \"#ef8a62\",\n             linetype=\"dashed\") +\n  geom_point(data = presidencias,\n             mapping = aes(x=fecha, y=10),\n             color = \"#ef8a62\",\n             size = 2) +\n  geom_label_repel(data = presidencias,\n                   mapping = aes(x=fecha, y=10, label = presidencia), \n                   hjust= -1,\n                   color = \"#ef8a62\",\n                   family = \"Assistant\", fontface = 'bold',\n                   arrow = arrow(length = unit(0.03, \"npc\"), type = \"closed\", ends = \"first\")\n  ) +      \n  \n  \n  labs(title = paste(\"Dólar en Argentina\"), \n       subtitle = paste(\"Cotización del Banco nación entre el\", min(dolar$indice_tiempo), \"y el\" , max(dolar$indice_tiempo)),\n       caption = \"Fuente: https://datos.gob.ar/\", \n       y = \"Cotización en $\", \n       x = \"\"\n  ) +\n  scale_x_date(date_breaks = \"12 month\", date_labels=\"%Y-%m\") +\n  theme_elegante_std(base_family = \"Assistant\") \n
\n\n

\n\n

Día 12: Treemap

\n\n

Los diagramas de árbol o “treemap” mapean dos variables, una categorica\ny otra cuantitativa, visualmente se construyen áreas por cada categoría\ncon una superficie consistente con la variable numérica. En este ejemplo\nmapeamos la cantidad de casos acumulada de COVID por provincia,\ndestacando las provincias que suman 95% de los casos totales

\n\n
library(\"tidyverse\")\nlibrary(\"ggrepel\")\nlibrary(\"treemapify\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nfirst_date <- min(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nndias <- max(covid.data$dia_inicio)\ndias <- expand.grid(distrito = unique(covid.data$osm_admin_level_4),\n                    dia = 1:ndias,\n                    stringsAsFactors = FALSE)\n\ndias %>% \n  left_join(covid.data, by=c(\"distrito\" = \"osm_admin_level_4\", \"dia\" = \"dia_inicio\")) %>% \n  mutate(casos = replace_na(nue_casosconf_diff, 0)) %>% \n  select(distrito, casos)  %>% \n  filter(distrito != 'Indeterminado') %>% \n  group_by(distrito) %>% \n  summarise(casos = sum(casos)) %>% \n  arrange(-casos) %>% \n  mutate(porc = cumsum(casos/sum(casos))) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
distritocasosporc
CABA119650.4832001
Buenos Aires95900.8704870
Chaco11180.9156369
Río Negro4910.9354656
Córdoba4660.9542848
Santa Fe2790.9655521
\n\n

La gráfica:

\n\n
plot_data %>%   \n  ggplot(aes(area = casos, fill = casos, label=paste0(distrito, \": \", format(casos, big.mark = \".\", decimal.mark = \",\")),\n             subgroup = ifelse(porc <= .95, \"95%\", \"\"))) +\n  geom_treemap() +\n  geom_treemap_subgroup_border() +\n  geom_treemap_subgroup_text(place = \"centre\", grow = T, alpha = .5, colour =\n                              \"White\", fontface = \"italic\", min.size = 0) +\n  geom_treemap_text(place = \"middle\", grow = T, reflow = T, alpha = 0.8, colour = \"black\", family= \"Assistant\",\n                    padding.x = grid::unit(3, \"mm\"),\n                    padding.y = grid::unit(3, \"mm\")) +\n  theme_elegante_std(base_family = \"Assistant\") +\n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Distribución de los casos por distritos al: \", last_date), \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\"\n  ) +\n  scale_fill_distiller(palette = \"YlGnBu\", direction = 1, na.value = \"white\") +\n  theme(legend.position = \"none\")\n
\n\n

\n\n

Día 15: Dendograma

\n\n
library(\"tidyverse\")\nlibrary(\"ggdendro\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\ndendro_data_k <- function(hc, k) {\n  \n  hcdata    <-  ggdendro::dendro_data(hc, type = \"rectangle\")\n  seg       <-  hcdata$segments\n  labclust  <-  cutree(hc, k)[hc$order]\n  segclust  <-  rep(0L, nrow(seg))\n  heights   <-  sort(hc$height, decreasing = TRUE)\n  height    <-  mean(c(heights[k], heights[k - 1L]), na.rm = TRUE)\n  \n  for (i in 1:k) {\n    xi      <-  hcdata$labels$x[labclust == i]\n    idx1    <-  seg$x    >= min(xi) & seg$x    <= max(xi)\n    idx2    <-  seg$xend >= min(xi) & seg$xend <= max(xi)\n    idx3    <-  seg$yend < height\n    idx     <-  idx1 & idx2 & idx3\n    segclust[idx] <- i\n  }\n  \n  idx                    <-  which(segclust == 0L)\n  segclust[idx]          <-  segclust[idx + 1L]\n  hcdata$segments$clust  <-  segclust\n  hcdata$segments$line   <-  as.integer(segclust < 1L)\n  hcdata$labels$clust    <-  labclust\n  \n  hcdata\n}\n\nset_labels_params <- function(nbLabels,\n                              direction = c(\"tb\", \"bt\", \"lr\", \"rl\"),\n                              fan       = FALSE) {\n  if (fan) {\n    angle       <-  360 / nbLabels * 1:nbLabels + 90\n    idx         <-  angle >= 90 & angle <= 270\n    angle[idx]  <-  angle[idx] + 180\n    hjust       <-  rep(0, nbLabels)\n    hjust[idx]  <-  1\n  } else {\n    angle       <-  rep(0, nbLabels)\n    hjust       <-  0\n    if (direction %in% c(\"tb\", \"bt\")) { angle <- angle + 45 }\n    if (direction %in% c(\"tb\", \"rl\")) { hjust <- 1 }\n  }\n  list(angle = angle, hjust = hjust, vjust = 0.5)\n}\n\nplot_ggdendro <- function(hcdata,\n                          direction   = c(\"lr\", \"rl\", \"tb\", \"bt\"),\n                          fan         = FALSE,\n                          scale.color = NULL,\n                          branch.size = 1,\n                          label.size  = 3,\n                          nudge.label = 0.01,\n                          expand.y    = 0.1,\n                          nbreaks     = 10) {\n  \n  direction <- match.arg(direction) # if fan = FALSE\n  ybreaks   <- pretty(segment(hcdata)$y, n = nbreaks)\n  ymax      <- max(segment(hcdata)$y)\n  \n  ## branches\n  p <- ggplot() +\n    geom_segment(data         =  segment(hcdata),\n                 aes(x        =  x,\n                     y        =  y,\n                     xend     =  xend,\n                     yend     =  yend,\n                     linetype =  factor(line),\n                     colour   =  factor(clust)),\n                 lineend      =  \"round\",\n                 show.legend  =  FALSE,\n                 size         =  branch.size)\n  \n  ## orientation\n  if (fan) {\n    p <- p +\n      coord_polar(direction = -1) +\n      scale_x_continuous(breaks = NULL,\n                         limits = c(0, nrow(label(hcdata)))) +\n      scale_y_reverse(breaks = ybreaks, labels = scales::comma)\n  } else {\n    p <- p + scale_x_continuous(breaks = NULL)\n    if (direction %in% c(\"rl\", \"lr\")) {\n      p <- p + coord_flip()\n    }\n    if (direction %in% c(\"bt\", \"lr\")) {\n      p <- p + scale_y_reverse(breaks = ybreaks, labels = scales::comma)\n    } else {\n      p <- p + scale_y_continuous(breaks = ybreaks, labels = scales::comma)\n      nudge.label <- -(nudge.label)\n    }\n  }\n  \n  # labels\n  labelParams <- set_labels_params(nrow(hcdata$labels), direction, fan)\n  hcdata$labels$angle <- labelParams$angle\n  \n  p <- p +\n    geom_text(data        =  label(hcdata),\n              aes(x       =  x,\n                  y       =  y,\n                  label   =  label,\n                  colour  =  factor(clust),\n                  angle   =  angle),\n              vjust       =  labelParams$vjust,\n              hjust       =  labelParams$hjust,\n              nudge_y     =  ymax * nudge.label,\n              size        =  label.size,\n              show.legend =  FALSE)\n  \n  # colors and limits\n  if (!is.null(scale.color)) {\n    p <- p + scale_color_manual(values = scale.color)\n  }\n  \n  ylim <- -round(ymax * expand.y, 1)\n  p    <- p + expand_limits(y = ylim)\n  \n  p\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nfirst_date <- min(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nndias <- max(covid.data$dia_inicio)\ndias <- expand.grid(distrito = unique(covid.data$osm_admin_level_4),\n                    dia = 1:ndias,\n                    stringsAsFactors = FALSE)\n\ndias %>% \n  left_join(covid.data, by=c(\"distrito\" = \"osm_admin_level_4\", \"dia\" = \"dia_inicio\")) %>% \n  mutate(casos = replace_na(nue_casosconf_diff, 0)) %>% \n  select(distrito, casos)  %>% \n  filter(distrito != 'Indeterminado') %>% \n  group_by(distrito) %>% \n  summarise(casos = sum(casos)) %>% \n  arrange(-casos) %>% \n  mutate(porc = cumsum(casos/sum(casos))) -> data\n\ndata_d <- as.data.frame(data[, 2])\nrownames(data_d) <- data$distrito\n\nD   <- dist(data_d)\nhc  <- hclust(D)\nhcdata <- dendro_data_k(hc, 5)\n\nplot_ggdendro(hcdata,\n              direction   = \"rl\",\n              label.size  = 3,\n              branch.size = .8,\n              nudge.label = 0.02,\n              expand.y    = 0.2,\n              nbreaks     = 10) +\n  # scale_y_continuous(labels = scales::comma) +\n  theme_elegante_std(base_family = \"Assistant\") +\n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Agrupación de provincias por cantidad de casos en 5 grupos principales (al: \", last_date, \")\"), \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\",\n       y = \"Cantidad de casos\",\n       x = \"\") \n
\n\n

\n\n

Día 16: Graficos de Waffle

\n\n

Este gráfico, en su forma más básica, trabaja con una variable\ncategoríca y una continua relacionada a la primera, normalmente una\nfrecuencia. Es de la familia de los gráficos de torta, aunque,\nseguramente es un poco mejor para entender las diferencias entre los\ndistintos niveles de una catgoría. Por lo general, se trabaja con una\nmatriz de cuadrados de 10 x 10 que representa el 100% de la muestra a\nrepresentar, cada categoría tendrá su porcentaje dentro de la muestra y\nel mismo se redondeará a múltiplos de 10 para asignar el numero de\ncuadrados que le va a tocar. Hay muchas variantes de este gráfico, dónde\nse usan otras formas, circulos, hexagonos o incluso pictogramas, pero la\nidea sigue siendo la misma.

\n\n

En este ejemplo, vemos como se distribuyen los casos de COVID-19 en\nArgentina, facetado por sexo, en este caso cada cuadrado representa el\n10% de su grupo y el 5% del total de casos.

\n\n
library(\"tidyverse\")\nlibrary(\"waffle\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read.csv(file='https://sisa.msal.gov.ar/datos/descargas/covid-19/files/Covid19Casos.csv', stringsAsFactors = FALSE, fileEncoding = \"UTF-16\")\n# Datos reproducibles\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.arg.Rda\",\"rb\"))\n\nlast_date <- max(covid.data$fecha_apertura, na.rm = TRUE)\n\ncovid.data %>% \n  filter(clasificacion_resumen == 'Confirmado',\n         sexo != 'NR') %>% \n  mutate(internado = fecha_internacion != \"\",\n         cui = fecha_cui_intensivo != \"\",\n         arm = replace_na(asistencia_respiratoria_mecanica == \"SI\",FALSE),\n         fallecido =    replace_na(fallecido == \"SI\", FALSE),\n         sexo = ifelse(sexo == 'M', 'Masculino', 'Femenino'),\n         internado = ifelse(internado, 'Internado', 'Ambulatorio'),\n         fallecido = ifelse(fallecido, 'Fallecido', 'Recuperado')) %>% \n  mutate(clasif_edad = case_when(edad <= 6 ~ '0 a 6',\n                                 edad > 6 &  edad <= 14 ~ '7 a 14',\n                                 edad > 14 & edad <= 35 ~ '15 a 35',\n                                 edad > 35 & edad <= 65 ~ '36 a 65',                          \n                                 edad > 65 ~ '>= 66',\n                          TRUE ~ 'Indeterminado')) %>% \n  select(sexo, edad, clasif_edad, internado, cui, arm, fallecido) %>% \n  group_by(sexo, clasif_edad) %>% \n  summarise(n = n()) %>%\n  mutate(freq = round(100*(n / sum(n)),0),\n         clasif_edad = factor(clasif_edad, c('0 a 6', '7 a 14', '15 a 35', '36 a 65', '>= 66'))) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
sexoclasif_edadnfreq
Femenino>= 66133911
Femenino0 a 65194
Femenino15 a 35450439
Femenino36 a 65458339
Femenino7 a 147056
FemeninoNA40
\n\n

La grafica:

\n\n
plot_data %>% \n  ggplot(aes(fill = clasif_edad, values = freq)) +\n  geom_waffle(n_rows = 10, size = 0.33, colour = \"white\", flip = TRUE) +\n  scale_y_continuous(breaks = seq(0, 10, by = 1), labels = function(x) x * 10) +\n  scale_x_continuous(breaks = seq(0, 10, by = 1), labels = function(x) x * 10) +\n  coord_equal() +\n  facet_wrap(~ sexo) +\n  scale_fill_manual(values=c(\"#E69F00\", \"#56B4E9\", \"#009E73\",  \"#0072B2\", \"#D55E00\", \"#CC79A7\")) +\n  theme_elegante_std(base_family = \"Assistant\") +\n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Clasificación etaria de infectados (al: \", last_date, \")\\n\"), \n       caption = \"Fuente: datos.gob.ar\",\n       y = \"\",\n       x = \"\") \n
\n\n

\n\n
  # theme(axis.text.x=element_blank())\n
\n\n

Día 17: Un Sankey o Alluvial

\n\n

Los diagramas de Sankey muestran flujos entre distintas variables\ncategorícas y sus cantidades en proporción entre sí. El ancho de las\nflechas o líneas se utiliza para mostrar sus magnitudes. Las flechas o\nlíneas de flujo pueden combinarse o dividirse a través de sus\ntrayectorias en cada etapa de un proceso. El color se suele utilizar\npara distingir mejor las diferentes categorías o para mostrar la\ntransición de un estado del proceso a otro. Normalmente, los gráficos de\nSankey se utilizan para mostrar visualmente la transferencia de energía,\ndinero o materiales, pero pueden usarse para mostrar el flujo de\ncualquier proceso aislado del sistema.

\n\n

En este ejemplo, tomamos los casos de COVID-19 en Argentina y\nanalizamos la evolución de los mismos. Los dos primeros niveles muestran\ncomo se componene los casos entre el sexo y el rango etario, y los\nsiguientes muestran la evolución posterior de los casos.

\n\n
library(\"tidyverse\")\nlibrary(\"ggalluvial\")\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read.csv(file='https://sisa.msal.gov.ar/datos/descargas/covid-19/files/Covid19Casos.csv', stringsAsFactors = FALSE, fileEncoding = \"UTF-16\")\n# Datos reproducibles\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.arg.Rda\",\"rb\"))\n\nlast_date <- max(covid.data$fecha_apertura, na.rm = TRUE)\n\ncovid.data %>% \n  filter(clasificacion_resumen == 'Confirmado',\n         !is.na(edad),\n         sexo != 'NR') %>% \n  mutate(internado = fecha_internacion != \"\",\n         cui = fecha_cui_intensivo != \"\",\n         arm = replace_na(asistencia_respiratoria_mecanica == \"SI\",FALSE),\n         fallecido =    replace_na(fallecido == \"SI\", FALSE),\n         sexo = ifelse(sexo == 'M', 'Masculino', 'Femenino'),\n         internado = ifelse(internado, 'Internado', 'Ambulatorio'),\n         fallecido = ifelse(fallecido, 'Fallecido', 'Recuperado')) %>% \n  mutate(clasif_edad = case_when(edad <= 6 ~ '0 a 6',\n                                 edad > 6 &  edad <= 14 ~ '7 a 14',\n                                 edad > 14 & edad <= 35 ~ '15 a 35',\n                                 edad > 35 & edad <= 65 ~ '36 a 65',                          \n                                 edad > 65 ~ '>= 66')) %>% \n  select(sexo, edad, clasif_edad, internado, cui, arm, fallecido) %>%\n  mutate(clasif_edad = factor(clasif_edad, c('0 a 6', '7 a 14', '15 a 35', '36 a 65', '>= 66')),\n         internado = factor(internado, c(\"Ambulatorio\", \"Internado\")),\n         fallecido = factor(fallecido, c(\"Recuperado\", \"Fallecido\"))\n         ) %>% \n  group_by(clasif_edad, sexo, internado, fallecido) %>% \n    summarise(n = n()) %>% \n  ungroup() -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
clasif_edadsexointernadofallecidon
0 a 6FemeninoAmbulatorioRecuperado366
0 a 6FemeninoInternadoRecuperado153
0 a 6MasculinoAmbulatorioRecuperado416
0 a 6MasculinoInternadoRecuperado165
7 a 14FemeninoAmbulatorioRecuperado552
7 a 14FemeninoInternadoRecuperado152
\n\n

La grafica:

\n\n
plot_data %>% \n  ggplot(mapping=aes(y = n,\n                     axis1 = fallecido, axis2 = internado, axis3 = sexo, axis4 = clasif_edad)) +\n  geom_alluvium(aes(fill = clasif_edad),\n                color = \"Gray30\",\n                width = 0, knot.pos = 0.1, reverse = FALSE) +\n  guides(fill = FALSE) +\n  geom_stratum(width = 1/8, reverse = FALSE, color=\"gray60\", linetype = 3) +\n  geom_text(stat = \"stratum\", infer.label = TRUE, reverse = FALSE) +\n  scale_x_continuous(breaks = 1:4, labels = c(\"Fallecido\", \"Internado\", \"Sexo\", \"Edad\")) +\n  coord_flip() +\n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Evolución de los caso por edad y sexo (al: \", last_date, \")\") , \n         caption = \"Fuente: datos.gob.ar\", \n       y = \"Casos Confirmados\", \n       x = \"\"\n  ) +\n  scale_fill_manual(values = c(\"firebrick3\", \"darkorange\", \"deepskyblue3\", \"darkorchid1\", \"seagreen\")) +\n  scale_color_manual(values = rep(\"Black\",5)) +\n  theme_elegante_std(base_family = \"Assistant\")\n
\n\n

\n\n

Día 18: Datos espaciales

\n\n

En este casos hacemos un mapa de puntos (“dot map”) dónde cada punto es\nuna coordenada geográfica y representa una ocurrencia de una variable\ncategórica. Usamos el mapa de la Ciudad de Buenos Aires y la\nestadísticas de delitos del año 2018, para ubicar estos\ngeográficamente.

\n\n
library(\"tidyverse\")\nlibrary(\"sf\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# delitos <- read.csv(\"http://cdn.buenosaires.gob.ar/datosabiertos/datasets/mapa-del-delito/delitos_2019.csv\", \n#                     na.strings = \"\", fileEncoding = \"UTF-8-BOM\", stringsAsFactors = FALSE)\n# comunas <- st_read('https://bitsandbricks.github.io/data/CABA_comunas.geojson')\n\ndelitos <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/delitos.caba.Rda\",\"rb\"))\ncomunas <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/comunas.caba.Rda\",\"rb\"))\n\ndelitos %>% \n  na.exclude() %>% \n  st_as_sf(coords = c(\"long\",\"lat\"), remove = FALSE,  crs = 4326) %>% \n  st_join(comunas)-> delitos_puntos\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
clasif_edadsexointernadofallecidon
0 a 6FemeninoAmbulatorioRecuperado366
0 a 6FemeninoInternadoRecuperado153
0 a 6MasculinoAmbulatorioRecuperado416
0 a 6MasculinoInternadoRecuperado165
7 a 14FemeninoAmbulatorioRecuperado552
7 a 14FemeninoInternadoRecuperado152
\n\n

La grafica:

\n\n
ggplot(delitos_puntos) +\n  geom_sf(data = comunas, fill = \"white\") +\n  geom_sf(data = delitos_puntos, aes(color=tipo_delito, alpha = 1), size=1) +\n  theme_elegante_std(base_family = \"Assistant\") + \n  labs(title = paste(\"CABA - Mapa del delito\"), \n       subtitle = paste0(\"Delitos por tipo en la Ciudad de Buenos Aires - Año 2018\\n\") , \n       caption = \"Fuente: data.buenosaires.gob.ar\", \n       y = \"\", \n       x = \"\"\n  ) +\n  theme(axis.text.x=element_blank(),\n        axis.ticks.x=element_blank(),\n        axis.title.y=element_blank(),\n        axis.text.y=element_blank(),\n        axis.ticks.y=element_blank(),\n        legend.position = \"none\") +\n  facet_grid(cols = vars(tipo_delito))\n
\n\n

\n\n

Día 19: Streamgraph

\n\n

Desde el Catálogo de Visualización de\nDatos\nleemos:

\n\n
También conocido como ThemeRiver.\n\nEste tipo de visualización es una variación del gráfico de área apilada, que en lugar de tener valores en un eje fijo y recto, tiene los valores alrededor de la línea base central variable. Los gráficos de flujo muestran los cambios en los datos a lo largo del tiempo de diferentes categorías a través del uso de formas fluidas y orgánicas que se asemejan un poco a un arroyo. Esto hace que los diagramas de flujo sean estéticamente agradables y más atractivos de mirar.\n\nEn un gráfico de flujo, el tamaño de cada forma de flujo individual es proporcional a los valores de cada categoría. El eje que fluye en paralelo al gráfico de flujo se utiliza para dar escala al tiempo. El color puede utilizarse para distinguir cada categoría o para visualizar los valores cuantitativos adicionales en cada categoría a través de la variación del tono de calor.\n\nLos gráficos de flujo son ideales para mostrar conjuntos de datos de alto volumen con el fin de descubrir tendencias y patrones a lo largo del tiempo en una amplia categoría. Por ejemplo, los picos estacionales y los valles en forma de arroyo pueden sugerir un patrón prehistórico. Un diagrama de flujo también puede ser utilizado para un gran grupo de activos durante un cierto período de tiempo.\n\nLa desventaja de los diagramas de flujo es que tienen problemas de legibilidad, ya que muy a menudo son confusos en diagramas de flujo con grandes conjuntos de datos. Las categorías con valores más pequeños a menudo se ahogan para dar paso a categorías con valores mucho más grandes, por lo que es imposible ver todos los datos. Además, es imposible leer los valores exactos visualizados, por lo que generalmente se utiliza un código.\n\nPor lo tanto, los diagramas de flujo deben reservarse a audiencias que no tengan intención de pasar mucho tiempo descifrando el gráfico y explorando sus datos. Los diagramas de flujo son mejores para dar una visión más general de los datos. También tienden a funcionar significativamente mejor como una pieza interactiva en lugar de un gráfico estático o impreso.\n
\n\n
library(\"tidyverse\")\nlibrary(\"ggTimeSeries\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nfirst_date <- min(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\nndias <- max(covid.data$dia_inicio)\ndias <- expand.grid(distrito = unique(covid.data$osm_admin_level_4),\n                    dia = 1:ndias,\n                    stringsAsFactors = FALSE)\n\nprovincias_de_interes <- c('CABA', 'Buenos Aires', 'Chaco','Córdoba', 'Río Negro', 'Tucumán')\ndias %>% \n  left_join(covid.data, by=c(\"distrito\" = \"osm_admin_level_4\", \"dia\" = \"dia_inicio\")) %>% \n  mutate(casos = replace_na(nue_casosconf_diff, 0)) %>% \n  select(dia, distrito, casos)  %>% \n  arrange(distrito, dia) %>% \n  filter(distrito %in% provincias_de_interes) %>% \n  ggplot(aes(x = dia, y = casos, group = distrito, fill = distrito)) +\n  stat_steamgraph(color=\"gray30\", size=.1, alpha=.8) +\n  theme_elegante_std(base_family = \"Assistant\") +\n  scale_fill_brewer(palette=\"Set1\") +\n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Variación de los casos diarios (al: \", last_date, \")\\nLas 6 Provincias con mayor número de casos\") , \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\", \n       y = \"Casos\", \n       x = \"Número de días desde el 1er caso\"\n  ) +\n  guides(fill = guide_legend(nrow = 1))\n
\n\n

\n\n

Día 20: Gráfico de redes

\n\n
library(\"tidyverse\")\nlibrary(\"ggraph\")\nlibrary(\"igraph\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read.csv(file='https://sisa.msal.gov.ar/datos/descargas/covid-19/files/Covid19Casos.csv', stringsAsFactors = FALSE, fileEncoding = \"UTF-16\")\n# Datos reproducibles\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.arg.Rda\",\"rb\"))\n\nlast_date <- max(covid.data$fecha_apertura, na.rm = TRUE)\n\ncovid.data %>% \n  filter(clasificacion_resumen == 'Confirmado',\n         !is.na(edad),\n         sexo != 'NR') %>% \n  mutate(internado = !is.na(fecha_internacion),\n         cui = !is.na(fecha_cui_intensivo),\n         arm = replace_na(asistencia_respiratoria_mecanica == \"SI\",FALSE),\n         fallecido =    replace_na(fallecido == \"SI\", FALSE),\n         sexo = ifelse(sexo == 'M', 'Masculino', 'Femenino'),\n         internado = ifelse(internado, 'Internado', 'Ambulatorio'),\n         fallecido = ifelse(fallecido, 'Fallecido', 'Recuperado')) %>% \n  mutate(clasif_edad = case_when(edad <= 6 ~ '0 a 6',\n                                 edad > 6 &  edad <= 14 ~ '7 a 14',\n                                 edad > 14 & edad <= 35 ~ '15 a 35',\n                                 edad > 35 & edad <= 65 ~ '36 a 65',                          \n                                 edad > 65 ~ '>= 66')) %>% \n  select(sexo, edad, clasif_edad, internado, cui, arm, fallecido) %>%\n  group_by(clasif_edad, sexo, internado, fallecido) %>% \n  summarise(n = n()) -> data\n\n\ndata %>% \n  group_by(sexo, clasif_edad) %>% \n  summarise(n=sum(n)) %>% \n  select(from=sexo, to=clasif_edad, n) -> sexo_edad\n\ndata %>% \n  group_by(internado, clasif_edad) %>% \n  summarise(n=sum(n)) %>% \n  select(to=internado, from=clasif_edad, n) -> internado_edad\n\ninternado_edad %>%\n  rbind(sexo_edad) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
tofromn
Internado>= 662479
Internado0 a 61100
Internado15 a 359003
Internado36 a 659539
Internado7 a 141381
>= 66Femenino1339
\n\n

La grafica:

\n\n
plot_data %>% \n  graph_from_data_frame() %>% \n  ggraph(layout = 'stress') +\n  geom_edge_link(aes(edge_width=n), show.legend = TRUE, alpha=0.5, color = \"#67a9cf\") +\n  geom_node_point(size=8, color =\"#ef8a62\") +\n  geom_node_text(aes(label = name), repel = TRUE, family=\"Assistant\") +\n  theme_elegante_std(base_family = \"Assistant\") +\n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"¿Cómo se distribuyen las internaciones entre el sexo y la edad?\\nDatos al: \", last_date) , \n       caption = \"Fuente: https://datos.gob.ar/\", \n       y = \"\", \n       x = \"\"\n  ) +\n  guides(fill = guide_legend(nrow = 1)) +\n  theme(axis.text.x=element_blank(),\n        axis.ticks.x=element_blank(),\n        axis.title.y=element_blank(),\n        axis.text.y=element_blank(),\n        axis.ticks.y=element_blank()) \n
\n\n

\n\n

Día 21: Anotaciones

\n\n

Ejemplo de anotaciones en ggplot, me entretengo un poco armando un\nclasico “meme”. Para esto necesitamos algunas cosas:

\n\n\n\n

Usamos [annotate()] que nos permite agregar no solo texto, sino\ncualquier otro geom.

\n\n
library(\"tidyverse\")\nlibrary(\"xkcd\")\n\n# Para instalar el font xkcd en Linux\n# download.file(\"http://simonsoftware.se/other/xkcd.ttf\", dest=\"xkcd.ttf\", mode=\"wb\")\n# system(\"mkdir ~/.fonts\")\n# system(\"cp xkcd.ttf ~/.fonts\")\n# font_import(pattern = \"[X/x]kcd\", prompt=FALSE)\n# loadfonts()\n\nxaxis <- c(1950,1960, 1970, 1980, 1990, 2000, 2010)\nxaxislbl <- paste0(xaxis, \"s\")\n\ndata.frame(year=seq(from=1940, to=2020, by=10),\n           quality=c(1.2, 1.3, 1.4, 1.8, 1.9, 1.8, 1, 1.5, 2)\n           ) -> df\ndf %>% \n  ggplot(mapping=aes(x=year, y=quality)) +\n  geom_smooth(method = 'loess',\n              color = \"black\",\n              formula = 'y ~ x', alpha = 0.2, size = 1, span = .6, se=FALSE) + \n  labs(title = paste(\"GENERAL QUALITY OF CHARTS AND\\nGRAPHS IN SCIENTIFIC PAPERS\\n\"), \n       y = \"\", \n       x = \"\"\n  ) +\n  xkcdaxis(c(1945,2020),c(1,2.2)) +\n  annotate(\"rect\", xmin = 1989, xmax = 2015, ymin = .98, ymax = 2.2,  alpha = .4) +\n  annotate(\"text\", x = 2002, y = 2, label = \"POWERPOINT/\\nMS PAINT ERA\", family=\"xkcd\", size=10,) +\n  scale_y_continuous(breaks = c(1,2), labels = c(\"BAD\", \"GOOD\")) +\n  scale_x_continuous(breaks = xaxis, labels = xaxislbl, limits=c(1930, 2020))  +\n  theme(plot.title=element_text(vjust=1.25, size=24, hjust = 0.5),\n        axis.text.x = element_text(size=24),\n        axis.text.y = element_text(size=20)\n        )\n
\n\n

\n\n

Día 22: visualizar datos textuales

\n\n

Una clásica “nube de palabras”, en este caso de mi cuenta de\ntwitter. Bastante fácil de implementar con ggwordcloud para la\ngráfica y rtweet para la parte de extracción de twitter.

\n\n
library(\"tidyverse\")\nlibrary(\"rtweet\")\nlibrary(\"tidytext\")\nlibrary(\"ggwordcloud\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# authenticate via web browser\n# token <- create_token(\n#   app = \"MarloweApp\",\n#   consumer_key = \"\",\n#   consumer_secret = \"\",\n#   access_token = \"\",\n#   access_secret = \"\")\n\n# Datos Originales\n# RAE_Corpus_1000 <- read.table(file=\"http://corpus.rae.es/frec/1000_formas.TXT\", skip=1, header=FALSE,\n#                               fileEncoding = \"Latin1\",\n#                               col.names = c(\"nr\", \"word\", \"Frec.absoluta\", \"Frec.normalizada\"),\n#                               stringsAsFactors = FALSE)\n# \n# stopwords <- read.csv(\"https://countwordsfree.com/stopwords/spanish/txt\",\n#                       col.names=\"word\", header=FALSE, stringsAsFactors = FALSE)\n\n# Datos reproducibles\nRAE_Corpus_1000 <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/rae_corpus_1000.Rda\",\"rb\"))\nstopwords <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/stopwords.Rda\",\"rb\"))\n\ntwits <- get_timeline(\"pmoracho\", n = 5000)\ntwits %>%\n  unnest_tokens(word, text) %>% \n  select(word) %>% \n  anti_join(stopwords, by = \"word\") %>%\n  inner_join(RAE_Corpus_1000, by = c(\"word\"=\"word\")) -> my_words\n  \nmy_words %>% \n  count(word, sort = TRUE)  -> my_words_count\n\nmy_words %>%\n  inner_join(my_words_count %>% head(100), by = \"word\") %>% \n  # filter(!(word %in% c('https', 'http'))) %>% \n  count(word) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
wordn
acuerdo4
agua3
alguien2
amigos3
análisis2
año5
\n\n

La grafica:

\n\n
plot_data %>% \n  ggplot(aes(label = word, size=n, color=n)) +\n  geom_text_wordcloud() +\n  scale_size_area(max_size = 20) +\n  theme_elegante_std(base_family = \"Assistant\") +\n  labs(title = paste(\"¿De qué habla @pmoracho?\"), \n       subtitle = paste0(\"Nube de palabras de las 100 palabras más usadas de la cuenta de twitter\"), \n       caption = \"Fuente:@pmoracho\",\n       y = \"\",\n       x = \"\")\n
\n\n

\n\n

Día 23: Sunburst

\n\n
library(\"tidyverse\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\n\nprovincias_de_interes <- c('Entre Ríos', 'Chaco', 'Córdoba', 'Santa Fe', 'Río Negro', 'Tucumán')\n\ncovid.data %>% \n  mutate(fecha = as.Date(fecha, \"%d/%m/%Y\")) %>% \n  select(dia=dia_inicio, fecha, distrito=osm_admin_level_4, cantidad=nue_casosconf_diff) %>% \n  filter(dia >= max(dia) - 6,\n         !(distrito %in% c('Indeterminado'))) %>% \n  arrange(distrito, dia) %>% \n  filter(distrito %in% provincias_de_interes) %>% \n  mutate(cantidad = ifelse(cantidad <= 0, 0, cantidad), nr=row_number()) -> plot_data\n\n\nplot_data %>% \n  mutate(angle = 90 - 360 * (nr-0.5) / n(),\n         hjust = ifelse( angle < -90, 1, 0),\n         angle = ifelse(angle < -90, angle+180, angle),\n         text = paste0(cantidad),\n         text2 = max(dia)-dia) -> label_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
diafechadistritocantidadnr
912020-06-03Chaco61
922020-06-04Chaco532
932020-06-05Chaco293
942020-06-06Chaco194
952020-06-07Chaco185
962020-06-08Chaco456
\n\n
kable(head(label_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
diafechadistritocantidadnranglehjusttexttext2
912020-06-03Chaco6185.90909066
922020-06-04Chaco53277.727270535
932020-06-05Chaco29369.545450294
942020-06-06Chaco19461.363640193
952020-06-07Chaco18553.181820182
962020-06-08Chaco45645.000000451
\n\n

La grafica:

\n\n
plot_data %>% \n  ggplot(aes(x=nr, y=cantidad+1, fill=distrito)) +\n  geom_bar(stat=\"identity\", alpha=0.5, color=\"black\", size=.05) +\n  ylim(-25,max(plot_data$cantidad)+2) +\n  geom_hline(aes(yintercept=0)) +\n  geom_text(data=label_data, aes(x=nr, y=cantidad+1.2, label=text, hjust=hjust), color=\"black\", fontface=\"bold\",alpha=0.6, size=3, angle = label_data$angle, inherit.aes = FALSE ) +\n  geom_text(data=label_data, aes(x=nr, y=-4, label=text2, hjust=hjust), color=\"black\", fontface=\"bold\",alpha=0.6, size=3, angle = label_data$angle, inherit.aes = FALSE ) +\n  coord_polar() +\n  theme_elegante_std(base_family = \"Assistant\") +\n  labs(title = \"COVID-19 en Argentina\", \n       subtitle = paste0(\"Casos en los últimos 7 días por distrito al: \", last_date, \"\\nEntre Ríos, Chaco, Córdoba, Santa Fe, Río Negro y Tucumán\"),  \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\",\n       y = \"\",\n       x = \"\") +\n  guides(fill = guide_legend(nrow = 1)) +\n  theme(\n    legend.position = \"bottom\",\n    axis.line.x = element_blank(),\n    axis.line.y = element_blank(),\n    axis.line= element_blank(),\n    axis.text = element_blank(),\n    axis.title = element_blank(),\n    axis.title.x = element_blank(),\n    axis.text.x = element_blank(),\n    axis.ticks.x = element_blank(),\n    axis.title.y = element_blank(),\n    axis.text.y = element_blank(),\n    axis.ticks.y = element_blank(),\n    panel.grid = element_blank(),\n    plot.margin = unit(rep(.2,4), \"cm\"),\n    axis.ticks = element_blank(),\n    legend.background = element_blank(),\n    legend.key = element_blank(),\n    panel.background = element_blank(),\n    panel.border = element_blank(),\n    strip.background = element_blank(),\n    plot.background = element_blank(),\n    panel.grid.major = element_blank(), \n    panel.grid.minor = element_blank()\n    ) \n
\n\n

\n\n

Día 24: Coropletas

\n\n
library(\"tidyverse\")\nlibrary(\"sf\")\nlibrary(\"viridis\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# delitos <- read.csv(\"http://cdn.buenosaires.gob.ar/datosabiertos/datasets/mapa-del-delito/delitos_2019.csv\", \n#                     na.strings = \"\", fileEncoding = \"UTF-8-BOM\", stringsAsFactors = FALSE)\n# comunas <- st_read('https://bitsandbricks.github.io/data/CABA_comunas.geojson')\n\ndelitos <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/delitos.caba.Rda\",\"rb\"))\ncomunas <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/comunas.caba.Rda\",\"rb\"))\n\n\ndelitos %>% \n  na.exclude() %>% \n  st_as_sf(coords = c(\"long\",\"lat\"), remove = FALSE,  crs = 4326) %>% \n  st_join(comunas)-> delitos_puntos\n\ndelitos_puntos %>% \n  mutate(n_delito = match(tipo_delito, c(\"Lesiones\", \"Hurto (sin violencia)\",\"Robo (con violencia)\",\"Homicidio\")),\n         comunas = factor(comuna)) %>% \n  group_by(barrios,comunas) %>% \n  summarize(nrank = n()) %>% \n  as.data.frame() %>% \n  select(barrios, comunas, nrank) -> ranking_comunas\n\ncomunas %>% \n  left_join(ranking_comunas,  by = \"comunas\") -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
barrios.xperimetroareacomunasbarrios.ynrankgeometry
CONSTITUCION - MONSERRAT - PUERTO MADERO - RETIRO - SAN NICOLAS - SAN TELMO35572.65178028071CONSTITUCION - MONSERRAT - PUERTO MADERO - RETIRO - SAN NICOLAS - SAN TELMO814MULTIPOLYGON (((-58.36854 -…
RECOLETA21246.6161408732RECOLETA296MULTIPOLYGON (((-58.39521 -…
BALVANERA - SAN CRISTOBAL10486.2663859913BALVANERA - SAN CRISTOBAL651MULTIPOLYGON (((-58.41192 -…
BARRACAS - BOCA - NUEVA POMPEYA - PARQUE PATRICIOS36277.44217012364BARRACAS - BOCA - NUEVA POMPEYA - PARQUE PATRICIOS1069MULTIPOLYGON (((-58.3552 -3…
ALMAGRO - BOEDO12323.4766605265ALMAGRO - BOEDO643MULTIPOLYGON (((-58.41287 -…
CABALLITO10990.9668510296CABALLITO536MULTIPOLYGON (((-58.43061 -…
\n\n

La grafica:

\n\n
plot_data %>% \n  ggplot() +\n    geom_sf(aes(fill = nrank), color=\"gray60\") +\n  scale_fill_viridis(option = \"inferno\", direction = -1) +\n  theme_elegante_std(base_family = \"Assistant\") + \n  labs(title = paste(\"CABA - Mapa del delito\"), \n       subtitle = paste0(\"Nivel de peligrosidad por comuna - Año 2018\\n\") , \n       caption = \"Fuente: data.buenosaires.gob.ar\", \n       y = \"\", \n       x = \"\",\n       fill = \"Delitos\"\n  ) + \n  theme(axis.text.x=element_blank(),\n        axis.ticks.x=element_blank(),\n        axis.title.y=element_blank(),\n        axis.text.y=element_blank(),\n        axis.ticks.y=element_blank(),\n        legend.title = element_text(face=\"bold\"),\n        legend.position = \"right\") \n
\n\n

\n\n

Día 25: Gráficas de violín

\n\n

Los datos:

\n\n
library(\"tidyverse\")\nlibrary(\"ggrepel\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\n\ncovid.data %>% \n  filter(osm_admin_level_4 %in% c('CABA', 'Buenos Aires')) %>% \n  mutate(distrito = factor(osm_admin_level_4)) %>% \n  select(dia=dia_inicio, distrito, cantidad=nue_casosconf_diff) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
diadistritocantidad
1CABA1
4Buenos Aires1
7Buenos Aires8
8CABA1
9Buenos Aires1
9CABA1
\n\n

El gráfico:

\n\n
plot_data %>% \n  ggplot(aes(x=distrito, y=cantidad, fill=distrito)) +\n    geom_violin() +\n    geom_boxplot(color=\"gray50\", alpha = 0.5, width=0.05) +\n    # scale_y_log10() +\n    # stat_summary(fun=mean, geom=\"point\", size=2, color = \"blue\") + \n    stat_summary(fun=median, geom=\"point\", size=2) +\n    geom_text_repel(data = plot_data %>% \n                              group_by(distrito) %>%\n                              summarise(mediana = median(cantidad)),\n                    aes(x = distrito, y = mediana, label=paste(\"Mediana:\",mediana)),\n                    family = \"Ralleway\",\n                    vjust= 8,\n                    hjust= -2) +\n    geom_text_repel(data = plot_data %>% \n                    group_by(distrito) %>%\n                    summarise(maximo = max(cantidad)),\n                  aes(x = distrito, y = maximo, label=paste(\"Cantidad máxima en un día:\",maximo, \"casos\")),\n                  family = \"Ralleway\",\n                  vjust= -8,\n                  hjust= 2) +\n    coord_flip() +\n    scale_fill_discrete(palette = function(x) c(\"#67a9cf\", \"#ef8a62\")) +\n    theme_elegante_std(base_family = \"Ralleway\")  +\n    labs(title = paste(\"COVID-19 en Argentina\"), \n         subtitle = paste(\"Distribución de los casos diarios en CABA y Buenos Aires al: \", last_date) , \n         caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\", \n         y = \"Cantidad de casos diarios\", \n         x = \"\"\n    ) +\n    theme(legend.position = \"none\")\n
\n\n

\n\n

Día 26: Gráfica de Marimeko

\n\n

Los datos:

\n\n
library(\"tidyverse\")\nlibrary(\"ggmosaic\") # devtools::install_github(\"haleyjeppson/ggmosaic\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# delitos <- read.csv(\"http://cdn.buenosaires.gob.ar/datosabiertos/datasets/mapa-del-delito/delitos_2019.csv\", \n#                     na.strings = \"\", fileEncoding = \"UTF-8-BOM\", stringsAsFactors = FALSE)\n\ndelitos <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/delitos.caba.Rda\",\"rb\"))\n\ndelitos %>% \n  mutate(tipo_delito=factor(tipo_delito, levels = c(\"Lesiones\", \"Hurto (sin violencia)\", \"Robo (con violencia)\", \"Homicidio\")),\n         comuna = factor(comuna)) %>% \n  na.exclude() %>% \n  select(comuna, tipo_delito) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
 comunatipo_delito
14Lesiones
315Lesiones
410Hurto (sin violencia)
54Robo (con violencia)
79Lesiones
812Hurto (sin violencia)
\n\n

El gráfico:

\n\n
plot_data %>% \n  ggplot() +\n  geom_mosaic(aes(x = product(comuna), fill=tipo_delito), offset= 0.003) +\n  theme_elegante_std(base_family = \"Ralleway\") +\n  labs(title = \"Delitos en CABA\", \n       subtitle = paste0(\"Por Comuna (año 2018)\"),  \n       caption = \"Fuente: data.buenosaires.gob.ar\",\n       y = \"\",\n       x = \"Comunas\"\n  ) +\n  scale_fill_manual(values=c(\"#56B4E9\", \"#009E73\",  \"#0072B2\", \"#E69F00\"))\n
\n\n

\n\n

Día 27: Gráficos animados

\n\n

Los gráficos animados son una muy útil herramienta para visualizar la\nevolución de variables, por lo general en el tiempo. En este ejemplo,\ntransformo una de las anteriores gráficas (lollipop) en una gráfica\nanimada.

\n\n

Los datos:

\n\n
library(\"tidyverse\")\nlibrary(\"countrycode\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Para descarga de los datos actualizados\n# covid.data <- read.csv(\"https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", na.strings = \"\", fileEncoding = \"UTF-8-BOM\", stringsAsFactors = FALSE)\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.mundial.Rda\",\"rb\"))\n\nrango_fechas <- range(unique(as.Date(covid.data$dateRep,\"%d/%m/%Y\")))\ntodas_las_fecha <- seq(from=rango_fechas[1], to=rango_fechas[2], by=1)\ntodos_los_paises <- unique(covid.data$countryterritoryCode)\ntodos_los_paises <- todos_los_paises[!is.na(todos_los_paises)]\n\nexpand_grid(countryterritoryCode=todos_los_paises, \n            fecha=todas_las_fecha) %>% \n  left_join(covid.data %>% \n              mutate(fecha = as.Date(dateRep, \"%d/%m/%Y\")), \n            by=c(\"countryterritoryCode\", \"fecha\")) %>%  \n  inner_join(codelist, by = c(\"countryterritoryCode\" = \"iso3c\")) %>% \n  mutate(pais = ifelse(is.na(un.name.es), iso.name.en, un.name.es),\n         continente = continent) %>% \n  group_by(pais, continente) %>% \n  mutate(casos = cumsum(replace_na(cases, 0)),\n         fallecidos = cumsum(replace_na(deaths, 0))) %>% \n  select(pais, continente, fecha, casos, fallecidos)  %>% \n  mutate(dia=row_number()) %>% \n  ungroup() %>% \n  select(pais, dia, fecha, casos) %>% \n  group_by(fecha) %>% \n  arrange(-casos) %>% \n  mutate(nr = row_number(),\n         media = mean(casos),\n         sobre_media = casos > media) %>% \n  select(pais, fecha, casos, media, sobre_media, nr) %>% \n  filter(nr <= 50,\n         fecha >= '2020-02-01') %>% \n  arrange(fecha, nr) -> plot_data\n\nout_folder <- tempdir(check = TRUE)\nfechas <- unique(plot_data$fecha)\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
paisfechacasosmediasobre_medianr
China2020-02-011180958.79803TRUE1
Tailandia2020-02-011958.79803FALSE2
Singapur2020-02-011658.79803FALSE3
Japón2020-02-011558.79803FALSE4
República de Corea2020-02-011258.79803FALSE5
Australia2020-02-01958.79803FALSE6
\n\n

La gráfica

\n\n
for (f in 1:length(fechas)) {\n  \n  fecha_actual =  fechas[f]\n  max_casos = max(plot_data$casos[plot_data$fecha == fecha_actual])\n  plot_data %>% \n    filter(fecha == fecha_actual) %>% \n    ggplot(aes(x=fct_reorder(pais, -nr), y = casos, color = sobre_media)) +\n    geom_segment(aes( y=0 , xend = pais, yend = casos)) + \n    geom_point() +\n    coord_flip() +\n    geom_text(aes(label = casos,\n                  vjust = .5,\n                  hjust = -.1),\n              position = position_dodge(width=1)) +\n    labs(title = paste(\"COVID-19 en el mundo\"), \n         subtitle = paste(\"Casos por pais al: \", fecha_actual, '\\nLos primeros 50 países') , \n         caption = \"Fuente: https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", \n         y = \"Casos\", \n         x = \"\"\n    ) +\n    scale_y_continuous(breaks = scales::pretty_breaks(n = 5), limits = c(0, max_casos * 1.03),\n                       labels = scales::comma) +\n    \n    scale_color_manual(labels = c(\"Sobre la media\", \"Debajo de la media\"), values = c(\"#67a9cf\", \"#ef8a62\")) +\n    theme_elegante_std(base_family = \"Ralleway\") -> p\n  \n    ggsave(filename = paste0(out_folder, \"/\", str_pad(f, 6, pad = \"0\"), \".png\"), plot =p, width = 36, height = 22, units = \"cm\", dpi = 100)\n}\n\nsystem(paste0('ffmpeg -y -framerate 2 -i ', out_folder, '/%06d.png -c:v libx264 -r 30 ', getwd(), '/dia27.mp4'))\nsystem(paste0('ffmpeg -y -ss 30 -t 3 -i ', getwd(), '/dia27.mp4', '-vf \"fps=10,scale=1028:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse\" -loop 0'), getwd(), '/dia27.gif')\n
\n\n

\"your

\n\n

Día 28: Diagramas de cuerdas

\n\n

Los diagramas de cuerda se usan para mostrar relaciones entre entidades\n(variables categoricas), la importancia de esa relación puede estar\ndefinido por una variable continua. De alguna manera es una variante de\nlos diagramas de redes, pero organizado de forma circular. Este tipo de\ndiagramas se popularizado en 2007 gracias a su uso en las infografías\npresentadas por el New York Times sobre el genoma humano.

\n\n

NOTA: Con este lamentablemente se murió la esperanza de resolver todo\ngon ggplot2

\n\n

Los datos:

\n\n
library(\"circlize\")\nlibrary(\"tidyverse\")\n\n# Datos originales\n# covid.data <- read.csv(file='https://sisa.msal.gov.ar/datos/descargas/covid-19/files/Covid19Casos.csv', stringsAsFactors = FALSE, fileEncoding = \"UTF-16\")\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.arg.Rda\",\"rb\"))\n\nlast_date <- max(covid.data$fecha_apertura, na.rm = TRUE)\n\ncovid.data %>% \n  filter(clasificacion_resumen == 'Confirmado',\n         !is.na(edad),\n         sexo != 'NR') %>% \n  mutate(internado = !is.na(fecha_internacion),\n         cui = !is.na(fecha_cui_intensivo),\n         arm = replace_na(asistencia_respiratoria_mecanica == \"SI\",FALSE),\n         fallecido =    replace_na(fallecido == \"SI\", FALSE),\n         sexo = ifelse(sexo == 'M', 'Masculino', 'Femenino'),\n         internado = ifelse(fecha_internacion != \"\", 'Internado', 'Ambulatorio'),\n         fallecido = ifelse(fallecido == \"SI\", 'Fallecido', 'Recuperado')) %>% \n  mutate(clasif_edad = case_when(edad <= 6 ~ '0 a 6',\n                                 edad > 6 &  edad <= 14 ~ '7 a 14',\n                                 edad > 14 & edad <= 35 ~ '15 a 35',\n                                 edad > 35 & edad <= 65 ~ '36 a 65',                          \n                                 edad > 65 ~ '>= 66')) %>% \n  select(sexo, edad, clasif_edad, internado, cui, arm, fallecido) %>%\n  mutate(clasif_edad = factor(clasif_edad, c('0 a 6', '7 a 14', '15 a 35', '36 a 65', '>= 66')),\n         internado = factor(internado, c(\"Ambulatorio\", \"Internado\")),\n         fallecido = factor(fallecido, c(\"Recuperado\", \"Fallecido\"))\n  ) %>% \n  group_by(clasif_edad, sexo, internado, fallecido) %>% \n  summarise(n = n()) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
clasif_edadsexointernadofallecidon
0 a 6FemeninoAmbulatorioRecuperado366
0 a 6FemeninoInternadoRecuperado153
0 a 6MasculinoAmbulatorioRecuperado416
0 a 6MasculinoInternadoRecuperado165
7 a 14FemeninoAmbulatorioRecuperado552
7 a 14FemeninoInternadoRecuperado153
\n\n

La gráfica:

\n\n
plot_data %>% \n  group_by(clasif_edad, sexo) %>% \n  summarize(n = sum(n)) %>% \n  select(from=clasif_edad, to=sexo, value=n) %>% \n  chordDiagram()\n
\n\n

\n\n

Día 29: gráficos de coordenadas paralelas

\n\n

Los datos:

\n\n
library(\"tidyverse\")\nlibrary(\"GGally\")\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read.csv(\"https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", na.strings = \"\", fileEncoding = \"UTF-8-BOM\",\n#                        stringsAsFactors = FALSE)\n\n# Datos para reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.mundial.Rda\",\"rb\"))\n\ncovid.data %>% \n  mutate(fecha = as.Date(dateRep, '%d/%m/%Y'),\n         pais = countriesAndTerritories) %>% \n  filter(continentExp %in% c('America')) %>% \n  # filter(pais %in% c('Argentina', 'Brazil', 'Chile', 'Paraguay', 'Uruguay', 'Colombia', 'Bolivia', 'Ecuador', 'Peru', 'Venezuela', 'México')) %>% \n  group_by(pais, popData2019) %>% \n  summarise(casos = sum(cases), fallecidos = sum(deaths)) %>% \n  arrange(-casos) %>% \n  head(10) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
paispopData2019casosfallecidos
United_States_of_America3290649172191052118434
Brazil21104951997814247748
Peru325104622443887461
Chile189520352251033841
Mexico12757552916545519747
Canada374110381002098300
\n\n

La gráfica:

\n\n
plot_data %>% \n  ggparcoord(columns = 2:4, groupColumn = 1) +\n    theme_elegante_std(base_family = \"Ralleway\") +\n    scale_x_discrete(labels = c(\"Población\", \"Casos\", \"Fallecidos\")) +\n    labs(title = paste(\"COVID-19\"), \n       subtitle = paste(\"Relación Población / Casos / fallecidos (Top 10 América)\") , \n       caption = \"Fuente: https://opendata.ecdc.europa.eu/covid19/casedistribution/csv\", \n       y = \"\", \n       x = \"\"\n  )\n
\n\n

\n\n

Día 30: diagramas de área polar o de Florence Nightingale

\n\n

Los datos:

\n\n
library(\"tidyverse\")\n\nif (\"ggelegant\" %in% rownames(installed.packages())) {\n  library(\"ggelegant\")\n} else {\n  # devtools::install_github(\"pmoracho/ggelegant\")\n  theme_elegante_std <- function(base_family) {}\n}\n\n# Datos originales\n# covid.data <- read_csv('https://docs.google.com/spreadsheets/d/16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA/export?format=csv&id=16-bnsDdmmgtSxdWbVMboIHo5FRuz76DBxsz_BbsEVWA&gid=0')\n\n# Datos reproducir la gráfica\ncovid.data <- readRDS(url(\"https://github.com/pmoracho/R/raw/master/data/covid.casos.arg.Rda\",\"rb\"))\n\nlast_date <- max(as.Date(covid.data$fecha,\"%d/%m/%Y\"))\n\ncovid.data %>% \n  filter(osm_admin_level_4 %in% c('CABA', 'Buenos Aires', 'Chaco', 'Río Negro', 'Córdoba')) %>% \n  group_by(distrito = osm_admin_level_4) %>% \n  summarise(casos = sum(nue_casosconf_diff), fallecidos=sum(nue_fallecidos_diff)) %>% \n  pivot_longer(-distrito) -> plot_data\n\nkable(head(plot_data))\n
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
distritonamevalue
Buenos Airescasos9590
Buenos Airesfallecidos304
CABAcasos11965
CABAfallecidos262
Chacocasos1118
Chacofallecidos64
\n\n

La gráfica:

\n\n
plot_data %>% \n  ggplot(aes(x = distrito, y=value, fill = name)) +\n  geom_col(width = 1, color = \"black\") +\n  scale_y_sqrt() +\n  coord_polar(start=3*pi/2) +\n  scale_fill_discrete(palette = function(x) c(\"#67a9cf\", \"#ef8a62\")) +\n  theme_elegante_std(base_family = \"Ralleway\") +\n  labs(title = paste(\"COVID-19 en Argentina\"), \n       subtitle = paste0(\"Total de casos y fallecidos por distrito (al: \", last_date, \")\") , \n       caption = \"Fuente: https://github.com/SistemasMapache/Covid19arData\", \n       y = \"\", \n       x = \"\"\n  ) +\n  theme(axis.text.y = element_blank())\n
\n\n

\n", "date_published": "2020-05-24T00:00:00-03:00" }, { "id": "https://pmoracho.github.io/blog/2020/02/13/El-texto-plano-nunca-fue-plano/", "url": "https://pmoracho.github.io/blog/2020/02/13/El-texto-plano-nunca-fue-plano/", "title": "El texto plano nunca fue plano", "content_html": "

Hubo un tiempo que fue hermoso

\n\n

Recuerdo mis primeros años en sistemas, debo admitirlo, fue en el siglo pasado.\nEn esos tiempo los que escribíamos código, distinguíamos entre los archivos\nbinarios, cualquier cosa que había que verla con un editor hexadecimal, y los\narchivos de texto, a los que les decíamos “son texto plano”, que eran esos\nque abríamos con cualquier editor de texto, tipo el edlin o alguno más\nmoderno. La vida era simple, el texto era una sucesión de\ncaracteres de un solo byte, podíamos saber cuantos había simplemente viendo el\ntamaño del archivo. Todo buen programador en ese entonces, tenía una hoja\nimpresa al lado del monitor con un montón de letras y caracteres extraños y un\nnúmero debajo de cada uno de ellos. La llamábamos la tabla ASCII. Para\nnosotros esa era la verdad absoluta, una de las tantas biblias que manejábamos,\ntal vez la mas importante de todas: cada caracter que se “tipeaba” tenía una\ncorrelación en esa tabla. Y escribíamos muchos, y a veces, encima,\nnecesitábamos escribir unos caracteres nada habituales en los teclados de esos\naños, letras ñ, acentos de todo tipo, y era entonces dónde apelábamos a\nnuestra biblia de una página. De tanto hacerlo, ya habíamos aprendido los\ntrucos, la tecla alt y 165 en el teclado numérico nos hacía aparecer por\narte de magia esa ñ imposible de encontrar en el teclado, o el alt y 160\npara hacer una simple á. También teníamos unos elegantes y algo esotéricos\ncaracteres especiales para dibujar todo tipo de recuadros, que nos cansábamos\nde usar en las interfaces de texto de nuestros programas, junto con alguna\nrutina escrita en assembler, copiada seguramente de alguna revista, para\nescribir directamente en la memoria de vídeo y hacer que nuestras ventanitas de\ntexto viajaran a la velocidad de la luz en nuestros monitores.

\n\n

De vez en cuando nos enterábamos que existían equipos a los que les decían\n“Mainframes” y que, particularmente los de IBM, usaban una codificación\ndistinta que se llamaba EBCDIC, pero iba pasar bastante tiempo hasta que\nnos cruzáramos con un archivo de esos, así que para nosotros, el texto seguía\nsiendo simple y sobre todo “plano”.

\n\n

Pero un día empezó la debacle

\n\n

Y fue el día que nos enteramos que la famosa tablita ASCII que usábamos, no\nnecesariamente era la misma que manejaba un programador en el país del tío Sam,\nni mucho menos uno detrás de la cortina de hierro (si.. todavía existía). Y fue\nduro, como cuando un compañerito nos revelaba que los reyes eran los padres. Se\nnos empezaba a caer la idea del texto “plano”, y sobre todo el concepto de\nuniversalidad de dicho texto. En ese entonces, teníamos que empezar a pensar en\nel “código de página”, o “codepage”, que, sin ser demasiado académico, eran\n“adaptaciones” regionales o mas bien de los fabricantes de hardware, sobre el\nestándar ASCII. La idea fundamental y tremendamente disruptiva de esto, es\nque el texto finalmente no es tan plano como pensábamos, y que teníamos que\nempezar a considerar el concepto de la codificación.

\n\n

¿Códificación?

\n\n

Un concepto básico: las computadoras no entienden de caracteres ni palabras ni\ntextos, son calculadoras avanzadas, solo manejan números. A la hora de definir\nun caracter cualquiera, se le asigna un número. El estándar ASCII es,\njustamente una forma de definir que número representa cada\nletra. Y desde 1967, establece que::

\n\n\n\n

Increíblemente, durante más de una década la informática mainstream, no\nconsideraba que existíamos los hispanohablantes, de hecho el estándar no\nsuponía que existiera otro idioma que no sea el inglés Americano. Hasta 1981,\ncada caracter tenía 7 bits, lo que es lo mismo decir, que se contemplaba un\ntotal de 128 caracteres, pero a partir de ese año, IBM por las suyas,\ndefine una extensión al código ASCCI sumándole un bit adicional para llegar\na los 8 bits que conocemos todos. Con lo que logra dar forma a otros 128\ncaracteres más, esta extensión se la llamó “código de página 437”, tenía\nalgunas modificaciones a los códigos de control por obsoletos y agregaba varios\ncaracteres gráficos y en particular varias letras latinas tan necesarias para\nla gente del occidente europeo. Está codificación se incorporó en la primera de\nlas máquinas conocida luego como computadora personal (PC), el resto es\nhistoria conocida. La versión “extendida”, se populariza y hoy cuando uno habla\nde ASCII se lo hace siempre suponiendo la versión extendida, que no es el\nestándar (esto es bueno tenerlo en claro).

\n\n

Agregar esta simple extensión, le dio la posibilidad a los fabricantes de\nhardware de adaptarla a las necesidades, normalmente regionales, y por que no,\neventualmente a caprichos de cada uno, después de todos, esos pocos bits no\nforman parte del estándar. Y este es el momento donde aparece el concepto\n“codepage” o el código de página, y por supuesto el comienzo de la pesadilla\nque aún nos acompaña.

\n\n

¿Pesadilla?

\n\n

Bueno, debo reconocer que soy un poco exagerado.

\n\n

Resumen

\n\n\n\n

Recomendaciones

\n\n\n\n", "date_published": "2020-02-13T00:00:00-03:00" } ] }