Datos Rústicos Visualización de Datos con Plotters – Parte 1

Datos Rústicos - Visualización de Datos con Plotters - Parte 1

Una guía detallada sobre cómo transformar números en bruto en gráficos impresionantes en Rust

Varias características de Plotters (Imagen del autor)

TLDR;

Plotters es una biblioteca popular de Rust para crear visualizaciones de datos. Proporciona una amplia gama de herramientas y funciones para ayudarte a crear gráficos, diagramas y otras visualizaciones de alta calidad. Este artículo es la parte 1 de una serie de artículos que se centra en los aspectos estéticos de las visualizaciones preparadas con Plotters. Desde cambiar el esquema de color hasta agregar anotaciones, aprenderás cómo personalizar los aspectos cosméticos de las visualizaciones de Plotters.

Al final de este artículo, tendrás una comprensión sólida de cómo usar la biblioteca Plotters para crear visualizaciones de aspecto profesional que captarán a tu audiencia. La biblioteca Ndarray también será útil a lo largo de este artículo, ya que exploraremos el uso de diversas herramientas y métodos para la manipulación de datos. Así que, ya seas un aficionado o un programador de Rust experimentado, leer este artículo es imprescindible si te interesa crear visualizaciones informativas pero estéticamente agradables con Plotters.

Nota: Este artículo asume que tienes un entendimiento básico del lenguaje de programación Rust.

El cuaderno llamado 6-plotters-tutorial-part-1.ipynb fue desarrollado para este artículo y se encuentra en el siguiente repositorio:

GitHub – wiseaidev/rust-data-analysis: El curso de análisis de datos definitivo con Rust.

El curso de análisis de datos definitivo con Rust. Contribuye al desarrollo de wiseaidev/rust-data-analysis creando un…

github.com

Tabla de Contenidos(TOC)

∘ TLDR; ∘ Tabla de Contenidos(TOC) ∘ ¿Para quién es este artículo? ∘ ¿Qué es Plotters? ∘ Ventajas de Plotters ∘ Configuración de Plotters ∘ Gráficos de una sola línea ∘ Gráficos multilineales ∘ Cuadrícula, ejes y etiquetas ∘ Colores y marcadores ∘ Subgráficos ∘ Barras de error ∘ Gráfico de dispersión ∘ Histograma ∘ Conclusión ∘ Nota de cierre ∘ Recursos

¿Para quién es este artículo?

Foto de Myriam Jessier en Unsplash

Para aquellos interesados en crear visualizaciones de datos intuitivas en Rust, este artículo es una lectura obligada. Ya seas un científico de datos experimentado o recién estés comenzando, la biblioteca Plotters en Rust puede ayudarte a crear visualizaciones cautivadoras y llamativas que seguramente impresionarán a tu audiencia. Con conocimientos básicos de programación Rust, comenzar nunca ha sido tan fácil.

La biblioteca Plotters tiene un gran poder cuando se trata de crear visualizaciones impresionantes y efectivas rápidamente y fácilmente, perfectas para proyectos personales y también profesionales. Es una herramienta que te permitirá generar gráficos de alta calidad capaces de comunicar información compleja de manera efectiva.

Si te interesa llevar tus habilidades de visualización a otro nivel, ¡no busques más! Las explicaciones claras junto con los gráficos útiles hacen que sea fácil seguir el proceso, mientras que las instrucciones paso a paso garantizan un progreso rápido para producir visualizaciones impresionantes utilizando la biblioteca Plotters.

¿Qué es Plotters?

Foto de Stephen Phillips - Hostreviews.co.uk en Unsplash

Plotters es una biblioteca robusta y adaptable de Rust que permite a los desarrolladores, como tú, crear visualizaciones impresionantes con facilidad. Su versatilidad permite la creación de varios tipos de gráficos, incluyendo líneas, dispersión e histogramas, al tiempo que ofrece una gran flexibilidad en opciones de estilo y anotaciones personalizadas.

Esta herramienta todo en uno permite a los desarrolladores definir cualquier tipo de visualización necesaria, convirtiéndola en un recurso indispensable para tareas de análisis de datos. Una característica destacada es su compatibilidad con interfaces interactivas, lo que permite generar gráficos estáticos y crear aplicaciones web sin esfuerzo. Esta capacidad facilita la exploración de conjuntos de datos y la creación de diversos tipos de gráficos adecuados para proyectos de aprendizaje automático o ciencia de datos.

Además, Plotters se integra perfectamente en entornos de desarrollo populares como Jupyter Notebook, y también es compatible con paquetes avanzados dedicados exclusivamente a mejorar tu experiencia de visualización de datos. ¡Esto proporciona más razones por las cuales esta biblioteca debería ser parte del conjunto de herramientas de cada desarrollador!

Ya sea que estés comenzando tu viaje o ya estés analizando conjuntos de datos complejos, Plotters ofrece una adaptabilidad sin igual junto con facilidad de uso, ¡mereciendo realmente el reconocimiento entre las mejores herramientas disponibles en la actualidad!

Ventajas de Plotters

Foto de UX Indonesia en Unsplash

La visualización de datos es un aspecto crucial del análisis de datos, y la biblioteca Plotters proporciona varios beneficios para simplificar el proceso. Una ventaja significativa que la distingue de otras opciones es su facilidad de uso. La integración con bibliotecas comunes de análisis de datos como Ndarray hace que sea muy fácil de usar junto con estructuras familiares.

Otro beneficio notable de utilizar esta herramienta de código abierto radica en su bajo costo: los desarrolladores y analistas pueden utilizar la biblioteca sin ningún cargo o limitación en los derechos de uso. Además, cualquier persona interesada en contribuir a mejorar el software puede hacerlo como parte de un esfuerzo comunitario.

Además, al ser de código abierto, se puede obtener un soporte rápido en línea de otros miembros de la comunidad en todo el mundo a través de plataformas como foros como stackoverflow, ¡lo que hace que la resolución de problemas sea eficiente!

Configuración de Plotters

Para aprovechar al máximo las capacidades de Plotters, es crucial asegurarse de que hemos configurado nuestro entorno correctamente. La biblioteca ofrece una amplia gama de tipos de gráficos, como gráficos de línea, gráficos de dispersión, histogramas y gráficos circulares; sin embargo, sin una configuración adecuada, estas características quedan inaccesibles. Afortunadamente, configurar Plotters es un proceso sencillo: simplemente ejecuta un comando en tu Jupyter Notebook y ¡listo!

:dep plotters = { version = "^0.3.5", default_features = false, features = ["evcxr", "all_series", "all_elements"] }

Una vez importado en tu proyecto o sesión de bloc de notas, Plotters te permite explorar su amplia gama de opciones de personalización adaptadas específicamente a tus necesidades, ya sea que se requieran gráficos simples o complejos.

Gráficos de Línea Individual

Un gráfico lineal de una sola línea (Imagen del autor)

Los gráficos de línea son una herramienta fundamental de visualización en la biblioteca Plotters que nos permite representar puntos de datos conectados por líneas rectas. A lo largo de esta sección, exploraremos el concepto de gráficos de línea individual, que implican el uso de la estructura LineSeries para crear visualizaciones con una sola línea.

La estructura LineSeries en Plotters se utiliza ampliamente para visualizar datos, especialmente en la creación de gráficos de una sola línea. Estos gráficos son perfectos para ilustrar correlaciones entre dos variables o resaltar patrones dentro de datos de series temporales.

Para crear un gráfico unidimensional a través de Plotters, comienza importando la biblioteca y utilizando su función draw_series junto con la estructura LineSeries para dibujar tu gráfico de líneas con un conjunto de datos asignado. Por ejemplo, si queremos ilustrar las cifras de ventas por mes a través de un gráfico sencillo, así es como puedes usar la función draw_series:

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..5f32, 0f32..5f32)?;    let x_axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0];    chart.draw_series(LineSeries::new(        x_axis.map(|x| (x, x)),        &RED,    ))?;    Ok(())}).style("width:100%")

En el código anterior, tenemos un arreglo x que representa las coordenadas x e y. Continuando, examinemos un ejemplo diferente donde utilizamos un arreglo Ndarray para representar los datos del gráfico de una sola línea:

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..7f32, 0f32..7f32)?;        let x_axis = Array::range(1., 7., 1.);        chart.draw_series(LineSeries::new(        x_axis.into_raw_vec().into_iter().map(|x| (x, x)),        &RED,    ))?;    Ok(())}).style("width:100%")

Continuando, visualicemos un gráfico cuadrático representado por la ecuación y = f(x) = x³. Aquí está el código correspondiente:

let points_coordinates: Vec<(f32, f32)> = {    let x_axis = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];    let quadratic: Vec<f32> = x_axis.iter().map(|x| i32::pow(*x as i32, 3) as f32).collect::<Vec<f32>>();    x_axis.into_iter().zip(quadratic).collect()};points_coordinates// Output// [(1.0, 1.0), (2.0, 8.0), (3.0, 27.0), (4.0, 64.0), (5.0, 125.0), (6.0, 216.0)]

Ahora, necesitamos trazar este vector de la siguiente manera:

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..7f32, 0f32..220f32)?;    chart.draw_series(LineSeries::new(        points_coordinates.iter().map(|(x, y)| (*x, *y)),        &RED,    ))?;    Ok(())}).style("width:100%")
Un gráfico de función cúbica (Imagen por autor)

En resumen, los gráficos de línea en Plotters ofrecen un enfoque poderoso para ilustrar correlaciones y tendencias dentro de los conjuntos de datos. Podemos crear representaciones informativas y cautivadoras de nuestra información utilizando la estructura LineSeries mientras manipulamos arreglos/vectores de x-values y y-values. Ya sea que estés explorando hallazgos de investigación científica o analizando métricas empresariales, estos gráficos de línea son herramientas indispensables para explorar aún más tu conjunto de datos y comunicar eficazmente sus conocimientos a los demás.

Gráficos Multilínea

Un gráfico multilínea (Imagen del autor)

Plotters proporciona una capacidad excepcional para mostrar múltiples gráficos en una sola salida, lo que nos permite presentar numerosas curvas simultáneamente en la misma visualización. Este atributo notable facilita la comparación y el análisis de conjuntos de datos de manera sencilla. Para profundizar en esta noción, examinemos un ejemplo ilustrativo:

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..7f32, 0f32..220f32)?;    chart.draw_series(LineSeries::new(        linear_coordinates.iter().map(|(x, y)| (*x, *y)),        &RED,    ))?;    chart.draw_series(LineSeries::new(        quadratic_coordinates.iter().map(|(x, y)| (*x, *y)),        &GREEN,    ))?;    chart.draw_series(LineSeries::new(        cubic_coordinates.iter().map(|(x, y)| (*x, *y)),        &BLUE,    ))?;    Ok(())}).style("width:100%")

Utilizando el fragmento de código proporcionado, podemos generar numerosas curvas con facilidad. Esto se logra invocando la función draw_series varias veces y definiendo los valores de x a partir de un arreglo junto con los valores correspondientes de y derivados de diferentes expresiones matemáticas. Al ejecutar este código, se mostrará un gráfico completo que muestra todas estas curvas trazadas con fines de observación.

Sumerjámonos en otro ejemplo que demuestra la adaptabilidad de los gráficos de varias líneas. Observa el siguiente fragmento de código:

let points_coordinates: Vec<(f32, f32)> = {    let x_y_axes = array!([[1., 2., 3., 4.], [1., 2., 3., 4.]]);    let x_axis: Vec<f32> = x_y_axes.slice(s![0, 0, ..]).to_vec();    let y_axis: Vec<f32> = x_y_axes.slice(s![0, 1, ..]).to_vec();    x_axis.into_iter().zip(y_axis).collect()};// [(1.0, 1.0), (2.0, 2.0), (3.0, 3.0), (4.0, 4.0)]evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..5f32, 0f32..5f32)?;    chart.draw_series(LineSeries::new(        points_coordinates.iter().map(|(x, y)| (*x, *y)),        &RED,    ))?;    Ok(())}).style("width:100%")

El fragmento de código en cuestión involucra un arreglo Ndarray x con dos dimensiones, que contiene conjuntos de datos distintos. Cada fila denota valores únicos. Cuando la función draw_series se llama en todo el arreglo, Plotters lo percibe como múltiples curvas a trazar simultáneamente. El resultado muestra ambos conjuntos de datos uno al lado del otro para facilitar la comparación y el análisis de sus patrones, tendencias u otras características destacables de manera intuitiva, lo que nos permite obtener conclusiones significativas visualmente sin mucho esfuerzo involucrado.

Para mostrar la adaptabilidad de los gráficos multilínea, podemos crear una representación visual utilizando datos arbitrarios. Observa este fragmento de código como ejemplo:

let random_samples: Vec<(f32, f32)> = {    let x_y_axes = Array::random((2, 5), Uniform::new(0., 1.));    let x_axis: Vec<f32> = x_y_axes.slice(s![0, ..]).to_vec();    let y_axis: Vec<f32> = x_y_axes.slice(s![0, ..]).to_vec();    x_axis.into_iter().zip(y_axis).collect()};random_samplesevcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;    chart.draw_series(LineSeries::new(        random_samples.iter().map(|(x, y)| (*x, *y)),        &RED,    ))?;    Ok(())}).style("width:100%")

En este fragmento de código, utilizamos la función Ndarray Array::random para crear una matriz 2D de datos que se llena con valores arbitrarios. Cada vez que se utiliza este método, genera un conjunto exclusivo de puntos de datos. Al imprimir la matriz resultante, se pueden examinar estos números aleatorios de cerca. La llamada a draw_series muestra tanto las filas de nuestro conjunto de datos como curvas individuales en un solo gráfico. Dado que cada ejecución produce salidas aleatorias diferentes, cada gráfico generado será único e introducirá cierta imprevisibilidad y diversidad en su experiencia de visualización.

En resumen, la capacidad de visualizar múltiples gráficos en una sola salida con Plotters es una característica poderosa para la exploración y el análisis de datos. Ya sea trazando curvas distintas, comparando conjuntos de datos o aprovechando datos aleatorios, los gráficos de varias líneas ofrecen una vista completa de la información disponible. Al utilizar la funcionalidad de Plotters y experimentar con diferentes fuentes de datos, se pueden crear visualizaciones impactantes que faciliten una mejor comprensión y toma de decisiones.

Cuadrícula, Ejes y Etiquetas

Cuadrícula de Plotters (Imagen del autor)

En el mundo de la visualización de datos, es crucial tener la flexibilidad de presentar una cuadrícula en un gráfico. La biblioteca Plotters nos permite lograr esto al habilitar la función de malla. Simplemente incorporando la instrucción chart.configure_mesh().draw()?; en nuestro código, podemos mejorar el atractivo visual y la claridad de nuestros gráficos.

evcxr_figure((640, 240), |root| {    let mut chart = ChartBuilder::on(&root)        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;    chart.configure_mesh().draw()?;    Ok(())}).style("width:100%")

La línea ChartBuilder::on(&root).build_cartesian_2d(0f32..1f32, 0f32..1f32)?; nos permite establecer manualmente los límites del eje x desde 0 hasta 1 y del eje y desde 0 hasta 1. Al especificar estos rangos, tenemos un control preciso sobre la región mostrada en nuestro gráfico, asegurando que se enfaticen los puntos de datos más relevantes.

Para mejorar la claridad y comprensión de nuestros gráficos, es esencial proporcionar etiquetas adecuadas para los ejes y un título descriptivo. Consideremos el siguiente fragmento de código como ejemplo:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demostración del Gráfico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;        Ok(())}).style("width: 60%")
Etiquetas de Plotters (Imagen del autor)

En este código, hemos agregado la instrucción chart.configure_mesh().x_desc("x = Array::range(1., 7., 1.);").y_desc("y = f(x)").draw()?; para enriquecer nuestro gráfico con anotaciones significativas. Al incluir x_desc("x = Array::range(1., 7., 1.);"), etiquetamos el eje x con una descripción concisa de los datos que se están trazando. Del mismo modo, y_desc("y = f(x)") asigna una etiqueta al eje y, indicando la relación funcional. Además, Caption("Demostración del Gráfico", ("Arial", 20).into_font()) proporciona un título informativo para dar contexto al gráfico. Estos elementos mejoran colectivamente la interpretabilidad de la visualización, asegurando que los espectadores puedan comprender fácilmente el propósito y el contenido de los gráficos.

Además de las etiquetas y títulos, Plotters nos permite crear una leyenda para distinguir entre varias curvas dentro de un gráfico. Al pasar un argumento para el parámetro de etiqueta en la función label y posteriormente llamar a la función legend, podemos generar una leyenda. Considere el siguiente ejemplo de código:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demostración de Gráfico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..14f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 1.);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RED    )).unwrap()        .label("y = x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &RED));        chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x * 2.0)),        &GREEN    )).unwrap()        .label("y = 2 * x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));    chart.configure_series_labels()        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 60%")
Un gráfico multilineal con etiquetas, leyenda y cuadrícula (Imagen del autor)

Al ejecutar este código, creamos una leyenda que corresponde a las diversas curvas en nuestro gráfico. La función legend() genera automáticamente una leyenda en función de las etiquetas proporcionadas después de llamar a la función draw_series(). Ayuda a los espectadores a identificar y diferenciar entre las diferentes funciones que se están trazando. En conjunto con la cuadrícula, las etiquetas de los ejes y el título, la leyenda mejora la legibilidad y comprensión general del gráfico.

De forma predeterminada, el cuadro de la leyenda se posiciona en la parte media derecha del gráfico. Sin embargo, si preferimos cambiar la ubicación del cuadro de la leyenda, podemos hacerlo especificando un parámetro de posición SeriesLabelPosition dentro de la función position. Modifiquemos nuestro fragmento de código en consecuencia:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demostración de Gráfico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..14f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RED    )).unwrap()        .label("y = x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &RED));        chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x * 2.0)),        &GREEN    )).unwrap()        .label("y = 2 * x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));    chart.configure_series_labels()        .position(SeriesLabelPosition::UpperMiddle)        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 60%")
Un gráfico multilineal con una leyenda posicionada en la parte superior del medio del gráfico (Imagen del autor)

Incluyendo el parámetro position(SeriesLabelPosition::UpperMiddle) en la función configure_series_labels, reposicionamos la caja de la leyenda en la parte superior del medio del gráfico. Esto nos permite ajustar la ubicación de la leyenda, asegurándonos de que no interfiera con las curvas trazadas u otras anotaciones. La capacidad de personalizar la ubicación de la leyenda añade versatilidad y estética a nuestro gráfico.

Al comprender y utilizar estas características en Plotters, podemos crear gráficos visualmente atractivos e informativos, personalizar los límites de los ejes, agregar etiquetas y títulos, incorporar leyendas y guardar nuestras visualizaciones como archivos de imagen. Estas capacidades nos permiten comunicar y presentar nuestros datos de manera efectiva y significativa.

Colores y Marcadores

Plotters ofrece una amplia gama de estilos y marcadores para diseñar gráficos visualmente cautivadores y comprensibles. Los estilos te permiten modificar la apariencia de tus líneas, mientras que los marcadores ayudan a enfatizar puntos de datos particulares en tu gráfico. Al combinar colores, estilos y marcadores diversos con las características de Plotters, puedes crear gráficos distintivos adaptados específicamente a tus necesidades.

Plotters ofrece mapas de colores avanzados que permiten la visualización de datos complejos con un espectro de colores. Con el parámetro style de Plotters, puedes seleccionar entre una variedad de mapas de colores predefinidos o diseñar uno personalizado utilizando una estructura incorporada como RGBColor. Este parámetro resulta particularmente beneficioso al representar datos que abarcan rangos de valores extensos o al enfatizar líneas de trazado específicas o cualquier otra forma. Puedes consultar la paleta completa para obtener diferentes valores de colores RGB.

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demostración de Gráfico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..14f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RGBColor(0,0,255) // rojo: 0, verde: 0, azul: 255 -> el color es azul     ))?;        Ok(())}).style("width: 60%")
Un gráfico de una sola línea con color azul (imagen del autor)

En este ejemplo, hemos cambiado el color de la línea a azul. También puedes utilizar otros formatos de colores, como HSLColor, para especificar colores personalizados utilizando los valores del espectro HSL.

Para elevar el atractivo visual de tus gráficos de líneas en Plotters, considera incorporar marcadores para representar símbolos distintos para cada trazado. Si deseas un toque personalizado, hay varias formas de personalizar estos marcadores. Primero, podemos utilizar el método draw_series trazando tus datos dos veces con un estilo de marcador como el tamaño y el color según tus preferencias personales o características específicas del conjunto de datos.

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demostración de Gráfico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..8f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RED    ))?;    chart.draw_series(x.map(|x| {        EmptyElement::at((*x, *x))        + Cross::new((0, 0), 2, GREEN) // coordenadas relativas a EmptyElement    }))?;    Ok(())}).style("width: 60%")
Un gráfico lineal de una sola línea con marcadores (imagen del autor)

Alternativamente, podemos establecer el tamaño del marcador utilizando el método point_size, que permite crear un marcador de círculo lleno o abierto.

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demostración de Gráfico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..8f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        &RED    ).point_size(2))?; // marcador de círculo abierto    Ok(())}).style("width: 60%")
Un gráfico de línea con marcadores (imagen del autor)

Puedes combinar todas estas técnicas (por ejemplo, colores, marcadores, leyendas) para personalizar la visualización de la siguiente manera:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Demostración de Gráfico", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..342f32)?;        let x = Array::range(1., 7., 0.1);        chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, *x)),        RED.filled()    ).point_size(2)).unwrap()        .label("y = x")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &RED));    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, (*x).powi(3))),        BLUE    ).point_size(2)).unwrap()        .label("y = x ^ 3")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &BLUE));    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, (*x).powi(2))),        &GREEN    )).unwrap()        .label("y = x ^ 2")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));    chart.draw_series(x.map(|x| {        EmptyElement::at((*x, (*x).powi(2)))        + Cross::new((0, 0), 2, WHITE) // coordenadas relativas a EmptyElement    }))?;    chart.configure_series_labels()        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 60%")
Un gráfico multilineal con diferentes colores de líneas, marcadores, etiquetas, título y leyenda (imagen del autor)

En general, Plotters ofrece una forma simple y sencilla de personalizar colores y marcadores, lo que te permite crear visualizaciones excepcionales. Al seleccionar las paletas de colores adecuadas, tus gráficos pueden comunicar información valiosa con facilidad. Elegir el color y el marcador adecuados puede marcar la diferencia al transmitir tu mensaje con éxito.

Subgráficos

Subgráficos de Plotters (imagen del autor)

La técnica de los subgráficos es una forma poderosa de mostrar múltiples gráficos en la misma salida. Este método resulta especialmente útil cuando deseas comparar diferentes conjuntos de datos o mostrar varios aspectos de un conjunto de datos. Con Plotters, crear subgráficos se convierte en una tarea sencilla, ya que te permite crear una disposición de cuadrícula donde se puede especificar la posición de cada gráfico en relación con su predecesor.

Además, cada subgráfico tiene especificaciones personalizables como títulos y etiquetas que facilitan a los usuarios adaptar sus resultados según sus necesidades específicas. Los subgráficos son especialmente útiles al tratar información compleja en contextos de análisis científico y de datos, ya que ayudan a transmitir hallazgos importantes de manera concisa y efectiva.

Para generar subgráficos en Plotters, puedes utilizar el método split_evenly que requiere un parámetro: una tupla que consiste en el número de filas y el número de columnas. Por ejemplo, si deseas crear un diseño de 1×2 para tus subgráficos mientras trazas datos en el primero, utiliza este fragmento de código:

let linear_coordinates: Vec<(f32, f32)> = {    let x_y_axes = array!([[1., 2., 3., 4.], [1., 2., 3., 4.]]);    let x_axis: Vec<f32> = x_y_axes.slice(s![0, 0, ..]).to_vec();    let y_axis: Vec<f32> = x_y_axes.slice(s![0, 1, ..]).to_vec();    x_axis.into_iter().zip(y_axis).collect()};let quadratic_coordinates: Vec<(f32, f32)> = {    let x_y_axes = array!([[1., 2., 3., 4.], [1., 4., 9., 16.]]);    let x_axis: Vec<f32> = x_y_axes.slice(s![0, 0, ..]).to_vec();    let y_axis: Vec<f32> = x_y_axes.slice(s![0, 1, ..]).to_vec();    x_axis.into_iter().zip(y_axis).collect()};evcxr_figure((640, 480), |root| {    let sub_areas = root.split_evenly((1,2)); // cuadrícula de 1 fila y 2 columnas    let graphs = vec![        ("y = x", linear_coordinates.clone(), &RED),        ("y= x ^ 2", quadratic_coordinates.clone(), &GREEN),    ];    for ((idx, area), graph) in (1..).zip(sub_areas.iter()).zip(graphs.iter()) {        let mut chart = ChartBuilder::on(&area)            .caption(graph.0, ("Arial", 15).into_font())            .x_label_area_size(40)            .y_label_area_size(40)            .build_cartesian_2d(0f32..5f32, 0f32..17f32)?;        chart.draw_series(LineSeries::new(            graph.1.iter().map(|(x, y)| (*x, *y)),            graph.2,        )).unwrap()            .label(graph.0)            .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));        chart.configure_mesh()            .y_labels(10)            .light_line_style(&TRANSPARENT)            .disable_x_mesh()            .x_desc("x = Array::range(1., 7., 0.1);")            .y_desc(graph.0)            .draw()?;    }    Ok(())}).style("width:100%")

Esto creará una cuadrícula de subgráficos de 1×2 y trazará los datos en ambos subgráficos, con un título y etiquetas de ejes especificados. El argumento de tupla pasado a split_evenly representa la cuadrícula (1 fila y 2 columnas). Hay muchas formas de hacer subgráficos en Plotters, utilizando split_vertically, split_horizontally, split_evenly y split_by_breakpoints.

Al utilizar las capacidades de sub-trazado de Plotters, se logran visualizaciones impresionantes que ayudan a la comunicación al presentar ideas de manera clara y precisa.

Barras de Error

Un solo gráfico con barras de error verticales (imagen del autor)

Para representar los datos de manera precisa, es crucial reconocer y hacer transparente el potencial de error. Esto se puede lograr mediante el uso de barras de error, representaciones gráficas que muestran la variabilidad en las mediciones e indican los niveles de incertidumbre. Plotters ofrece una solución sencilla con su función ErrorBar, que permite a los usuarios agregar estos elementos visuales esenciales a cualquier gráfico especificando las coordenadas x/y, las preferencias de color/estilo y proporcionando los valores de error pertinentes. Veamos el siguiente fragmento de código:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Gráfico con Barras de Error Verticales", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..50f32)?;        let x = Array::range(1., 7., 0.1);    chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, (*x as f32).powi(2))),        &GREEN    )).unwrap()        .label("y = x ^ 2")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));      chart.draw_series(x.map(|x| {        ErrorBar::new_vertical(*x, (*x as f32).powi(2) - 1.5, (*x as f32).powi(2), (*x as f32).powi(2) + 1.4, RED.filled(), 2)    })).unwrap();    chart.configure_series_labels()        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 100%")

En este ejemplo, hemos elegido mostrar el error en el eje y ya que suele ser más relevante. La siguiente imagen es una representación visual de nuestros datos y muestra barras de error distintas alrededor de cada punto de datos. Estas barras indican el rango de valores que probablemente se encuentren dentro de un cierto nivel de confianza; barras más largas significan una mayor incertidumbre en la medición.

Sin embargo, puede haber ocasiones en las que mostrar los datos de error en ambos ejes resulte beneficioso, especialmente al tratar con series de tiempo o datos experimentales que contienen múltiples variables independientes. En tales casos, utilizar el método ErrorBar::new_horizontal y pasar un arreglo de errores del eje x (similarmente al hecho para los errores del eje y) será suficiente.

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Gráfico con Barras de Error Horizontales", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(1f32..7f32, 1f32..50f32)?;        let x = Array::range(1., 7., 0.1);    chart.configure_mesh()        .x_desc("x = Array::range(1., 7., 0.1);")        .y_desc("y = f(x)")        .draw()?;    chart.draw_series(LineSeries::new(        x.iter().map(|x| (*x, (*x as f32).powi(2))),        &GREEN    )).unwrap()        .label("y = x ^ 2")        .legend(|(x,y)| PathElement::new(vec![(x,y), (x + 20,y)], &GREEN));      chart.draw_series(x.map(|x| {        ErrorBar::new_horizontal((*x as f32).powi(2), *x - 0.3, *x, *x + 0.3, RED.filled(), 2)    })).unwrap();    chart.configure_series_labels()        .background_style(&WHITE)        .border_style(&BLACK)        .draw()?;    Ok(())}).style("width: 100%")
Una sola gráfica con barras de error horizontales (imagen del autor)

Al incorporar estos elementos en tus visualizaciones, ya sea como científico compartiendo resultados de investigación o como analista de negocios mostrando cifras de ventas, el público puede entender mejor cualquier incertidumbre asociada con la información presentada. Por lo tanto, utilizar esta característica esencial garantizará que los detalles precisos se transmitan de manera precisa y se mantenga la claridad en las presentaciones sin confusión causada por errores en los conjuntos de datos representados gráficamente utilizando las características de Error Bars de Plotters.

Gráfica de dispersión

Las gráficas de dispersión son una herramienta crucial para visualizar datos y obtener información sobre la relación entre dos variables. Plotters facilita la creación de gráficas de dispersión en Rust asignando una variable al eje x y otra al eje y, y trazando cada punto en sus coordenadas correspondientes. Manipulando los colores y tamaños de los puntos, puedes representar dimensiones adicionales dentro de tu conjunto de datos.

La principal ventaja de utilizar gráficas de dispersión es que revelan patrones o grupos en los datos que no son evidentes solo con tablas o gráficos. Los valores atípicos también son fácilmente identificables a través de este método.

Además, estos gráficos tienen una naturaleza intuitiva que permite a cualquier persona, independientemente de su experiencia estadística, comprender rápidamente las relaciones entre diferentes aspectos, por lo que son herramientas de comunicación útiles al presentar hallazgos.

El siguiente fragmento de código generará una gráfica de dispersión de muestras de datos con distribución uniforme:

evcxr_figure((640, 480), |root| {    _ = root.fill(&WHITE);    let mut chart = ChartBuilder::on(&root)        .caption("Gráfica de dispersión con distribución uniforme", ("Arial", 20).into_font())        .x_label_area_size(40)        .y_label_area_size(40)        .build_cartesian_2d(0f32..1f32, 0f32..1f32)?;    chart.configure_mesh()        .disable_x_mesh()        .disable_y_mesh()        .y_labels(5)        .x_label_formatter(&|x| format!("{:.1}", *x as f64 / 100.0))        .y_label_formatter(&|y| format!("{}%", (*y * 100.0) as u32))        .draw()?;    let _ = chart.draw_series(random_samples.iter().map(|(x,y)| Circle::new((*x,*y), 3, GREEN.filled())));        Ok(())}).style("width:100%")

La gráfica de dispersión resultante es la siguiente:

Una gráfica de dispersión de muestras de datos con distribución uniforme (imagen del autor)

En resumen, las gráficas de dispersión ofrecen capacidades de visualización poderosas que nos permiten comprender mejor nuestros conjuntos de datos y proporcionar formas sencillas de compartir información con otros, gracias principalmente a las características de facilidad de uso proporcionadas por las funciones de la biblioteca de Plotters disponibles en el entorno de programación Rust!

Histograma

Los histogramas son un recurso invaluable cuando se trata de analizar la distribución de datos. Ofrecen una representación visual de cómo se distribuye la información en diferentes categorías o intervalos, lo que facilita nuestra comprensión e interpretación de conjuntos de datos complejos. Plotters simplifica este proceso utilizando la función Histogram::vertical con arreglos lineales que agrupan los puntos de datos en barras que representan la frecuencia por tamaño de intervalo.

Por ejemplo, si necesitamos trazar una distribución uniforme generada aleatoriamente, la creación de histogramas mostraría la frecuencia de cada resultado posible en detalle y revelaría cualquier patrón o tendencia presente en el conjunto de datos. El análisis de estos gráficos puede ayudar a descubrir información valiosa sobre distribuciones subyacentes, como la demografía de grupos de edad en poblaciones, los niveles de exposición a la luz capturados en fotografías o las tasas mensuales de precipitación observadas en ciudades.

El siguiente fragmento de código es un ejemplo de trazado de muestras de datos de distribución uniforme generadas aleatoriamente:

evcxr_figure((640, 480), |root| {    let mut chart = ChartBuilder::on(&root)        .caption("Histograma", ("Arial", 20).into_font())        .x_label_area_size(50)        .y_label_area_size(50)        .build_cartesian_2d(0u32..100u32, 0f64..0.5f64)?;    chart.configure_mesh()        .disable_x_mesh()        .disable_y_mesh()        .y_labels(5)        .x_label_formatter(&|x| format!("{:.1}", *x as f64 / 100.0))        .y_label_formatter(&|y| format!("{}%", (*y * 100.0) as u32))        .draw()?;    let hist = Histogram::vertical(&chart)        .style(RED.filled())        .margin(0)        .data(random_samples.iter().map(|(x,_)| ((x*100.0) as u32, 0.01)));    let _ = chart.draw_series(hist);        Ok(())}).style("width:100%")

El histograma producido es el siguiente:

Un gráfico de histograma de muestras de datos de distribución uniforme (imagen por el autor)

En resumen, los histogramas proporcionan herramientas poderosas para comprender diversos conjuntos de datos e identificar de manera precisa los factores críticos que los afectan a lo largo del tiempo. Al utilizar las funciones personalizables de Plotters, como tamaños de intervalo adaptados específicamente a nuestras necesidades, obtenemos una mayor flexibilidad al interpretar grandes cantidades de información rápidamente sin sacrificar la precisión.

Conclusión

Foto de Aaron Burden en Unsplash

Este artículo ha destacado la importancia de las visualizaciones y cómo Plotters puede adaptarse a diversas necesidades. Plotters resulta invaluable para crear diferentes tipos de gráficos, como gráficos de una sola línea o multilineales, gráficos de dispersión e histogramas. Además, hemos aprendido sobre la personalización de funciones como elecciones de diseño de diseño para líneas de color, marcadores, leyendas, etc.

Con el conocimiento adquirido, puedes navegar con confianza por las diversas funciones de Plotters con facilidad. El aprovechamiento efectivo de estos métodos mejorará tu comprensión de los datos y permitirá una mejor comunicación de los hallazgos.

En la próxima serie de artículos, especialmente en la parte 2, exploraremos visualizaciones de datos cautivadoras, que incluyen, entre otras, gráficos circulares y visualizaciones en 3D. El objetivo es empoderarte para que te conviertas en un hábil narrador visual con tus datos, revelando información oculta como nunca antes.

Nota de cierre

Foto de Nick Morrison en Unsplash

Al concluir este tutorial, me gustaría expresar mi sincero agradecimiento a todos aquellos que han dedicado su tiempo y energía a completarlo. Ha sido un placer absoluto demostrar las extraordinarias capacidades del lenguaje de programación Rust contigo.

Siendo apasionado por la ciencia de datos, te prometo que voy a escribir al menos un artículo completo cada semana o así sobre temas relacionados a partir de ahora. Si te interesa estar al tanto de mi trabajo, considera conectarte conmigo en varias plataformas de redes sociales o contactarme directamente si necesitas ayuda con cualquier otra cosa.

¡Gracias!

Recursos

GitHub – wiseaidev/rust-data-analysis: The ultimate data analysis with Rust course.

The ultimate data analysis with Rust course. Contribute to wiseaidev/rust-data-analysis development by creating an…

github.com

plotters – Rust

Plotters – Una biblioteca de dibujo en Rust que se enfoca en trazar datos para aplicaciones WASM y nativas 🦀📈🚀

docs.rs

evcxr-jupyter-integration

Debido a que evcxr utiliza solo imágenes SVG y todo tipo de series, no necesitamos otros tipos de backend. Por lo tanto, deberíamos poner…

plotters-rs.github.io

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Regs necesarias para la IA de alto riesgo, dice ACM Es el Viejo Oeste

El documento de ACM recomienda que se establezcan nuevas leyes para limitar el uso de IA generativa en ciertas situac...

Inteligencia Artificial

AI Sesgo Desafíos y Soluciones

¿De dónde proviene el sesgo en la inteligencia artificial? Una vez que lo encontramos, ¿cómo podemos reducirlo o elim...

Inteligencia Artificial

IA y el futuro del fútbol universitario

El panorama del atletismo universitario ha vuelto a cambiar gracias al dinero y al fútbol americano. La SEC fue la pr...