Una de las maneras de profesionalizar nuestras visualizaciones en R-Shiny es utilizando “wrappers”, es decir, librerías que “envuelven” código de otros lenguajes con estructuras en R para permitirnos ampliar funcionalidades de otros entornos sin conocer los lenguajes originales.
A continuación les presentamos una manera de construir una función “wrapper” propia para generar pirámides de población usando la librería AmCharts de JavaScript.
Consigna:
Recordatorio
La resolución del ejercicio debe subirse al campus virtual en un archivo .R o .RMD. En cualquiera de los dos formatos, el código debe poder ejecutarse de manera independiente en cualquier computadora (incluyendo el acceso a los datos y la carga de las librerías necesarias)
library(shiny)
library(htmltools)
library(jsonlite)
library(dplyr)
mostrar_piramide_poblacion_amcharts <- function(data_piramide) {
data_json <- as.character(toJSON(data_piramide))
html_js_content <- paste0('
<html>
<head>
<style>
body { margin: 0; padding: 0; }
#chartdiv {
width: 100%;
height: 500px;
}
</style>
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
</head>
<body>
<div id="chartdiv"></div>
<script>
am5.ready(function() {
var root = am5.Root.new("chartdiv");
root.setThemes([
am5themes_Animated.new(root)
]);
var chart = root.container.children.push(
am5xy.XYChart.new(root, {
panX: false,
panY: false,
wheelX: "panX",
wheelY: "zoomX",
layout: root.verticalLayout,
arrangeTooltips: false,
paddingLeft: 0,
paddingRight: 10
})
);
chart.getNumberFormatter().set("numberFormat", "#.#s");
var legend = chart.children.push(
am5.Legend.new(root, {
centerX: am5.p50,
x: am5.p50
})
);
var data = ', data_json, ';
var yAxis = chart.yAxes.push(
am5xy.CategoryAxis.new(root, {
categoryField: "age",
renderer: am5xy.AxisRendererY.new(root, {
inversed: true,
cellStartLocation: 0.1,
cellEndLocation: 0.9,
minorGridEnabled: true,
minGridDistance: 20
})
})
);
yAxis.data.setAll(data);
var xAxis = chart.xAxes.push(
am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererX.new(root, {
minGridDistance: 60,
strokeOpacity: 0.1
})
})
);
function createSeries(field, labelCenterX, pointerOrientation, rangeValue) {
var series = chart.series.push(
am5xy.ColumnSeries.new(root, {
xAxis: xAxis,
yAxis: yAxis,
valueXField: field,
categoryYField: "age",
sequencedInterpolation: true,
clustered: false,
tooltip: am5.Tooltip.new(root, {
pointerOrientation: pointerOrientation,
labelText: "{categoryY}: {valueX}"
})
})
);
series.columns.template.setAll({
height: am5.p100,
strokeOpacity: 0,
fillOpacity: 0.8
});
series.bullets.push(function() {
return am5.Bullet.new(root, {
locationX: 1,
locationY: 0.5,
sprite: am5.Label.new(root, {
centerY: am5.p50,
text: "{valueX}",
populateText: true,
centerX: labelCenterX
})
});
});
series.data.setAll(data);
series.appear();
var rangeDataItem = xAxis.makeDataItem({
value: rangeValue
});
xAxis.createAxisRange(rangeDataItem);
rangeDataItem.get("grid").setAll({
strokeOpacity: 0,
stroke: series.get("stroke")
});
var label = rangeDataItem.get("label");
label.setAll({
text: field.toUpperCase(),
fontSize: "1.1em",
fill: series.get("stroke"),
paddingTop: 10,
isMeasured: false,
centerX: labelCenterX
});
label.adapters.add("dy", function() {
return -chart.plotContainer.height();
});
return series;
}
createSeries("male", am5.p100, "right", -3);
createSeries("female", 0, "left", 4);
var cursor = chart.set("cursor", am5xy.XYCursor.new(root, {
behavior: "zoomY"
}));
cursor.lineY.set("forceHidden", true);
cursor.lineX.set("forceHidden", true);
chart.appear(1000, 100);
});
</script>
</body>
</html>
')
# Usamos tags$iframe para renderizar un documento HTML completo de forma aislada
return(tags$iframe(srcdoc = html_js_content,
width = "100%",
height = "550px",
style = "border: none; overflow: hidden;"))
}
# Datos de ejemplo
data_piramide <- data.frame(
age = c("70-74", "65-69", "60-64", "55-59", "50-54", "45-49", "40-44", "35-39", "30-34","25-29", "20-24", "15-19", "10-14", "5-9", "0-4"),
male = c(-0.5, -0.8, -1.1, -1.7, -2.2, -2.8, -3.4, -4.2, -5.2, -5.6, -5.1, -3.8, -3.2, -4.4, -5.0),
female = c(0.8, 1.0, 1.3, 1.9, 2.5, 3.0, 3.6, 4.1, 4.8, 5.1, 5.1, 3.8, 3.4, 4.1, 4.8)
)
browsable(mostrar_piramide_poblacion_amcharts(data_piramide))