From b9cb0118ccfe6fab97633c3dadb37a64a1258fd9 Mon Sep 17 00:00:00 2001 From: Aayush Badoni Date: Tue, 9 Jul 2024 18:02:56 +0530 Subject: [PATCH 1/6] Data Manipulation Lessons added --- _sources/index_en.rst | 1 + _sources/index_es.rst | 1 + _sources/lectures/TWP66/TWP66_1.rst | 115 ++++++++++++++++ _sources/lectures/TWP66/TWP66_1_en.rst | 115 ++++++++++++++++ _sources/lectures/TWP66/TWP66_2.rst | 59 ++++++++ _sources/lectures/TWP66/TWP66_2_en.rst | 60 ++++++++ _sources/lectures/TWP66/TWP66_3.rst | 129 ++++++++++++++++++ _sources/lectures/TWP66/TWP66_3_en.rst | 129 ++++++++++++++++++ _sources/lectures/TWP66/toctree.rst | 19 +++ _sources/lectures/TWP66/toctree_en.rst | 19 +++ _sources/lectures/_static/TWP66/TWP66_1.html | 70 ++++++++++ .../lectures/_static/TWP66/TWP66_1_en.html | 70 ++++++++++ _sources/lectures/img/TWP66_001.png | Bin 0 -> 48250 bytes 13 files changed, 787 insertions(+) create mode 100644 _sources/lectures/TWP66/TWP66_1.rst create mode 100644 _sources/lectures/TWP66/TWP66_1_en.rst create mode 100644 _sources/lectures/TWP66/TWP66_2.rst create mode 100644 _sources/lectures/TWP66/TWP66_2_en.rst create mode 100644 _sources/lectures/TWP66/TWP66_3.rst create mode 100644 _sources/lectures/TWP66/TWP66_3_en.rst create mode 100644 _sources/lectures/TWP66/toctree.rst create mode 100644 _sources/lectures/TWP66/toctree_en.rst create mode 100644 _sources/lectures/_static/TWP66/TWP66_1.html create mode 100644 _sources/lectures/_static/TWP66/TWP66_1_en.html create mode 100644 _sources/lectures/img/TWP66_001.png diff --git a/_sources/index_en.rst b/_sources/index_en.rst index 07582b56c2..5d9affd01f 100644 --- a/_sources/index_en.rst +++ b/_sources/index_en.rst @@ -34,6 +34,7 @@ Contents: lectures/TWP58/toctree_en lectures/TWP60/toctree_en lectures/TWP65/toctree_en + lectures/TWP66/toctree_en quiz/Quiz1_en.rst quiz/Quiz2_en.rst quiz/Quiz3_en.rst diff --git a/_sources/index_es.rst b/_sources/index_es.rst index ecf1551c24..4bb0dbc9c4 100644 --- a/_sources/index_es.rst +++ b/_sources/index_es.rst @@ -34,6 +34,7 @@ Contenidos: lectures/TWP58/toctree lectures/TWP60/toctree lectures/TWP65/toctree + lectures/TWP66/toctree quiz/Quiz1.rst quiz/Quiz2.rst quiz/Quiz3.rst diff --git a/_sources/lectures/TWP66/TWP66_1.rst b/_sources/lectures/TWP66/TWP66_1.rst new file mode 100644 index 0000000000..0c0a724bc1 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_1.rst @@ -0,0 +1,115 @@ +==================== +Introducción a NumPy +==================== + +.. image:: ../img/TWP66_001.png + :height: 9.258cm + :width: 14.925cm + :align: center + :alt: + +Introducción +------------ +Esta completa lección se centra en dominar NumPy, una de las bibliotecas más populares en Python para cálculos numéricos. Exploraremos diversas funcionalidades de NumPy, comprendiendo cómo crear y manipular matrices para realizar operaciones numéricas de manera efectiva. + +Parte 1: Entendiendo los Fundamentos de NumPy +--------------------------------------------- + +.. contents:: + :local: + +Visión general +~~~~~~~~~~~~~~ +NumPy es una potente biblioteca para cálculos numéricos en Python. Proporciona soporte para grandes matrices y matrices multidimensionales, junto con una colección de funciones matemáticas para operar en estas matrices. + +Instalación de NumPy +~~~~~~~~~~~~~~~~~~~~ +Instala NumPy usando pip:: + + pip install numpy + +Importar NumPy +~~~~~~~~~~~~~~ +Importa NumPy en tu script de Python:: + + import numpy as np + +Creación de Arrays +~~~~~~~~~~~~~~~~~~ +**Array 1D**:: + + import numpy as np + + # Crear un array 1D + arr = np.array([1, 2, 3, 4, 5]) + print("Array 1D:", arr) + +**Array 2D**:: + + import numpy as np + + # Crear un array 2D + arr_2d = np.array([[1, 2, 3], [4, 5, 6]]) + print("Array 2D:\n", arr_2d) + +Operaciones con Arrays +~~~~~~~~~~~~~~~~~~~~~~ +**Operaciones Básicas**:: + + import numpy as np + + # Crear un array + arr = np.array([1, 2, 3, 4, 5]) + + # Realizar operaciones básicas + print("Suma:", np.sum(arr)) + print("Media:", np.mean(arr)) + +**Operaciones Elemento a Elemento**:: + + import numpy as np + + # Crear arrays + arr1 = np.array([1, 2, 3]) + arr2 = np.array([4, 5, 6]) + + # Adición elemento a elemento + print("Adición Elemento a Elemento:", arr1 + arr2) + + # Multiplicación elemento a elemento + print("Multiplicación Elemento a Elemento:", arr1 * arr2) + +Manipulación de Forma +~~~~~~~~~~~~~~~~~~~~~ +**Reformatear Arrays**:: + + import numpy as np + + # Crear un array 1D + arr = np.array([1, 2, 3, 4, 5, 6]) + + # Reformatear el array a 2x3 + arr_reformateado = np.reshape(arr, (2, 3)) + print("Array Reformateado:\n", arr_reformateado) + +**Aplanamiento de Arrays**:: + + import numpy as np + + # Crear un array 2D + arr_2d = np.array([[1, 2, 3], [4, 5, 6]]) + + # Aplanar el array + arr_aplanado = arr_2d.flatten() + print("Array Aplanado:", arr_aplanado) + +Conclusión +---------- +NumPy es fundamental para cálculos numéricos en Python. Comprender los fundamentos de la creación y manipulación de arrays es crucial para la ciencia de datos y el aprendizaje automático. + +Asegúrate de explorar la documentación de NumPy para conocer características y funcionalidades más avanzadas. + +Quiz +---- +.. raw:: html + :file: ../_static/TWP66/TWP66_1.html diff --git a/_sources/lectures/TWP66/TWP66_1_en.rst b/_sources/lectures/TWP66/TWP66_1_en.rst new file mode 100644 index 0000000000..cb3e1d4127 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_1_en.rst @@ -0,0 +1,115 @@ +===================== +Introduction to NumPy +===================== + +.. image:: ../img/TWP66_001.png + :height: 9.258cm + :width: 14.925cm + :align: center + :alt: + +Introduction +------------ +This comprehensive lecture focuses on mastering NumPy, one of the most popular libraries in Python for numerical computations. We will explore various functionalities of NumPy, understanding how to create and manipulate arrays to effectively perform numerical operations. + +Part 1: Understanding NumPy Basics +---------------------------------- + +.. contents:: + :local: + +Overview +~~~~~~~~ +NumPy is a powerful library for numerical computations in Python. It provides support for large multi-dimensional arrays and matrices, along with a collection of mathematical functions to operate on these arrays. + +Installing NumPy +~~~~~~~~~~~~~~~~ +Install NumPy using pip:: + + pip install numpy + +Importing NumPy +~~~~~~~~~~~~~~~ +Import NumPy in your Python script:: + + import numpy as np + +Creating Arrays +~~~~~~~~~~~~~~~ +**1D Array**:: + + import numpy as np + + # Create a 1D array + arr = np.array([1, 2, 3, 4, 5]) + print("1D Array:", arr) + +**2D Array**:: + + import numpy as np + + # Create a 2D array + arr_2d = np.array([[1, 2, 3], [4, 5, 6]]) + print("2D Array:\n", arr_2d) + +Array Operations +~~~~~~~~~~~~~~~~ +**Basic Operations**:: + + import numpy as np + + # Create an array + arr = np.array([1, 2, 3, 4, 5]) + + # Perform basic operations + print("Sum:", np.sum(arr)) + print("Mean:", np.mean(arr)) + +**Element-wise Operations**:: + + import numpy as np + + # Create arrays + arr1 = np.array([1, 2, 3]) + arr2 = np.array([4, 5, 6]) + + # Element-wise addition + print("Element-wise Addition:", arr1 + arr2) + + # Element-wise multiplication + print("Element-wise Multiplication:", arr1 * arr2) + +Shape Manipulation +~~~~~~~~~~~~~~~~~~ +**Reshaping Arrays**:: + + import numpy as np + + # Create a 1D array + arr = np.array([1, 2, 3, 4, 5, 6]) + + # Reshape the array to 2x3 + reshaped_arr = np.reshape(arr, (2, 3)) + print("Reshaped Array:\n", reshaped_arr) + +**Flattening Arrays**:: + + import numpy as np + + # Create a 2D array + arr_2d = np.array([[1, 2, 3], [4, 5, 6]]) + + # Flatten the array + flat_arr = arr_2d.flatten() + print("Flattened Array:", flat_arr) + +Conclusion +---------- +NumPy is essential for numerical computations in Python. Understanding the basics of array creation and manipulation is crucial for data science and machine learning. + +Make sure to explore the NumPy documentation for more advanced features and functionalities. + +Quiz +---- +.. raw:: html + :file: ../_static/TWP66/TWP66_1_en.html \ No newline at end of file diff --git a/_sources/lectures/TWP66/TWP66_2.rst b/_sources/lectures/TWP66/TWP66_2.rst new file mode 100644 index 0000000000..d3a9137c29 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_2.rst @@ -0,0 +1,59 @@ +=================================== +NumPy: Temas Avanzados y Ejercicios +=================================== + +Overview +-------- +En esta conferencia, profundizaremos en NumPy, explorando temas avanzados y proporcionando ejercicios para reforzar tu comprensión. + +Parte 1: Operaciones Avanzadas en NumPy +--------------------------------------- + +Broadcasting +~~~~~~~~~~~~ +La transmisión (broadcasting) en NumPy permite que funciones universales trabajen con arrays de diferentes formas. Por ejemplo: + +.. activecode:: ac_l66_es_2a + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + import numpy as np + + a = np.array([1, 2, 3]) + b = np.array([10, 20, 30]) + c = a[:, np.newaxis] + b + print(c) + +Ejercicio 1: Broadcasting +~~~~~~~~~~~~~~~~~~~~~~~~~ +1. Crea un array NumPy `x` de forma (3, 4) con enteros aleatorios. +2. Crea un array NumPy `y` de forma (3, 1) con enteros aleatorios. +3. Realiza broadcasting para sumar `y` a `x` elemento por elemento. + +Indexación y Segmentación +~~~~~~~~~~~~~~~~~~~~~~~~~ +Los arrays NumPy admiten potentes operaciones de indexación y segmentación: + +.. activecode:: ac_l66_es_2b + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + import numpy as np + + arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + slice = arr[:2, 1:] + print(slice) + +Ejercicio 2: Indexación y Segmentación +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1. Crea un array NumPy `z` de forma (5, 5) con enteros secuenciales comenzando desde 1. +2. Extrae la submatriz 3x3 de la esquina inferior derecha utilizando segmentación. + +Conclusion +---------- +En esta conferencia, hemos cubierto operaciones avanzadas en NumPy y ejercicios para reforzar tu aprendizaje. Practica estos conceptos para profundizar tu comprensión de los arrays NumPy y sus funcionalidades. + +.. note:: + Asegúrate de tener NumPy instalado (`pip install numpy`) para ejecutar los ejemplos de código. diff --git a/_sources/lectures/TWP66/TWP66_2_en.rst b/_sources/lectures/TWP66/TWP66_2_en.rst new file mode 100644 index 0000000000..8ee095c671 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_2_en.rst @@ -0,0 +1,60 @@ +==================================== +NumPy: Advanced Topics and Exercises +==================================== + +Overview +-------- +In this lecture, we'll dive deeper into NumPy, exploring advanced topics and providing exercises to help reinforce your understanding. + +Part 1: Advanced NumPy Operations +--------------------------------- + +Broadcasting +~~~~~~~~~~~~ +Broadcasting in NumPy allows universal functions to work with arrays of different shapes. For example: + +.. activecode:: ac_l66_2a + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + import numpy as np + + a = np.array([1, 2, 3]) + b = np.array([10, 20, 30]) + c = a[:, np.newaxis] + b + print(c) + +Exercise 1: Broadcasting +~~~~~~~~~~~~~~~~~~~~~~~~ +1. Create a NumPy array `x` of shape (3, 4) with random integers. +2. Create a NumPy array `y` of shape (3, 1) with random integers. +3. Perform broadcasting to add `y` to `x` element-wise. + +Indexing and Slicing +~~~~~~~~~~~~~~~~~~~~ +NumPy arrays support powerful indexing and slicing operations: + +.. activecode:: ac_l66_2b + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + import numpy as np + + arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + slice = arr[:2, 1:] + print(slice) + +Exercise 2: Indexing and Slicing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1. Create a NumPy array `z` of shape (5, 5) with sequential integers starting from 1. +2. Extract the bottom-right 3x3 sub-array using slicing. + +Conclusion +---------- +In this lecture, we've covered advanced NumPy operations and exercises to reinforce your learning. Practice these concepts to deepen your understanding of NumPy arrays and their functionalities. + +.. note:: + Ensure you have NumPy installed (`pip install numpy`) to run the code examples. + diff --git a/_sources/lectures/TWP66/TWP66_3.rst b/_sources/lectures/TWP66/TWP66_3.rst new file mode 100644 index 0000000000..b7d8e1b2cf --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_3.rst @@ -0,0 +1,129 @@ +================== +El Poder de Pandas +================== + +Introduction +------------ +Esta conferencia se centra en Pandas, una poderosa biblioteca de Python para manipulación y análisis de datos. Exploraremos sus capacidades en el manejo efectivo de datos estructurados. + +Understanding Pandas Basics +--------------------------- +Pandas proporciona estructuras de datos como Series y DataFrame. Está construido sobre NumPy, lo que facilita trabajar con datos estructurados. + +.. code-block:: python + :caption: Importando Pandas y Cargando Datos Ficticios + + import pandas as pd + + # Datos ficticios + data = { + 'Nombre': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Edad': [28, 23, 25, 24, 30], + 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] + } + + # Creando un DataFrame + df = pd.DataFrame(data) + + # Mostrando el DataFrame + print(df) + +Análisis Exploratorio de Datos (EDA) con Pandas +----------------------------------------------- +Verifica las dimensiones de los datos y examina su estructura: + +.. code-block:: python + :caption: Verificando Dimensiones de los Datos e Información + + # Forma del DataFrame + print(df.shape) + + # Información sobre el DataFrame + print(df.info()) + +Limpieza y Transformación de Datos +---------------------------------- +Renombra columnas, maneja datos faltantes y convierte tipos de datos: + +.. code-block:: python + :caption: Limpieza y Transformación de Datos + + # Renombrando columnas + df.rename(columns={'Nombre': 'Nombre Completo', 'Ciudad': 'Ubicación'}, inplace=True) + + # Manejo de datos faltantes (no aplicable para estos datos ficticios) + + # Conversión de tipos de datos (no necesario para estos datos ficticios) + +Manipulación y Agregación de Datos +---------------------------------- +Selecciona, filtra, agrupa y agrega datos: + +.. code-block:: python + :caption: Manipulación y Agregación de Datos + + # Seleccionando columnas + print(df[['Nombre', 'Edad']]) + + # Filtrando datos + datos_filtrados = df[df['Edad'] > 25] + print(datos_filtrados) + + # Agrupando y agregando datos + estadisticas_grupo_edad = df.groupby('Edad').size() + print(estadisticas_grupo_edad) + +Visualización de Datos con Pandas y Matplotlib +---------------------------------------------- +Utiliza Matplotlib para visualizaciones: + +.. code-block:: python + :caption: Visualización de Datos + + import matplotlib.pyplot as plt + + # Ejemplo de gráfico + df['Edad'].plot(kind='hist', bins=5) + plt.title('Distribución de Edades') + plt.xlabel('Edad') + plt.ylabel('Frecuencia') + plt.show() + +Ejemplo Interactivo +------------------- +Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame por edad y visualizar los resultados: + +.. note:: + Estamos usando PyScript para ejecutar Pandas en el navegador. Utiliza `plt.show()` en lugar de `display()` para mostrar los resultados. + +.. activecode:: ac_l66_es_3a + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + import pandas as pd + import matplotlib.pyplot as plt + + # Datos ficticios + data = { + 'Nombre': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Edad': [28, 23, 25, 24, 30], + 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] + } + + # Crear DataFrame + df = pd.DataFrame(data) + + # Filtrar DataFrame por edad + df_filtrado = df[df['Edad'] > 25] + + # Graficar datos filtrados + df_filtrado.plot(kind='bar', x='Nombre', y='Edad', color='skyblue') + plt.title('Distribución de Edades para Individuos Mayores de 25 Años') + plt.xlabel('Nombre') + plt.ylabel('Edad') + display(plt) + +Ejercicio +--------- +Escribe código para calcular la edad promedio de las personas en el DataFrame. diff --git a/_sources/lectures/TWP66/TWP66_3_en.rst b/_sources/lectures/TWP66/TWP66_3_en.rst new file mode 100644 index 0000000000..822554ba6a --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_3_en.rst @@ -0,0 +1,129 @@ +=============== +Power of Pandas +=============== + +Introduction +------------ +This lecture focuses on Pandas, a powerful Python library for data manipulation and analysis. We'll explore its capabilities in handling structured data effectively. + +Understanding Pandas Basics +--------------------------- +Pandas provides data structures like Series and DataFrame. It is built on top of NumPy, making it easy to work with structured data. + +.. code-block:: python + :caption: Importing Pandas and Loading Dummy Data + + import pandas as pd + + # Dummy data + data = { + 'Name': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Age': [28, 23, 25, 24, 30], + 'City': ['New York', 'Paris', 'Berlin', 'London', 'Tokyo'] + } + + # Creating a DataFrame + df = pd.DataFrame(data) + + # Displaying the DataFrame + print(df) + +Exploratory Data Analysis (EDA) with Pandas +------------------------------------------- +Check data dimensions and examine its structure: + +.. code-block:: python + :caption: Checking Data Dimensions and Info + + # Shape of the DataFrame + print(df.shape) + + # Information about the DataFrame + print(df.info()) + +Data Cleaning and Transformation +-------------------------------- +Rename columns, handle missing data, and convert data types: + +.. code-block:: python + :caption: Cleaning and Transforming Data + + # Rename columns + df.rename(columns={'Name': 'Full Name', 'City': 'Location'}, inplace=True) + + # Handle missing data (not applicable for this dummy data) + + # Convert data types (not necessary for this dummy data) + +Data Manipulation and Aggregation +--------------------------------- +Select, filter, group, and aggregate data: + +.. code-block:: python + :caption: Data Manipulation and Aggregation + + # Selecting columns + print(df[['Name', 'Age']]) + + # Filtering data + filtered_data = df[df['Age'] > 25] + print(filtered_data) + + # Grouping and aggregating data + age_group_stats = df.groupby('Age').size() + print(age_group_stats) + +Data Visualization with Pandas and Matplotlib +---------------------------------------------- +Utilize Matplotlib for visualizations: + +.. code-block:: python + :caption: Data Visualization + + import matplotlib.pyplot as plt + + # Plotting example + df['Age'].plot(kind='hist', bins=5) + plt.title('Age Distribution') + plt.xlabel('Age') + plt.ylabel('Frequency') + plt.show() + +Interactive Example +-------------------- +Here's an interactive example where you can filter the DataFrame based on age and visualize the results: + +.. note:: + We are using PyScript to run Pandas in the browser. Use `plt.show()` instead of `display()` for displaying results. + +.. activecode:: ac_l66_3a + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + import pandas as pd + import matplotlib.pyplot as plt + + # Dummy data + data = { + 'Name': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Age': [28, 23, 25, 24, 30], + 'City': ['New York', 'Paris', 'Berlin', 'London', 'Tokyo'] + } + + # Create DataFrame + df = pd.DataFrame(data) + + # Filter DataFrame by age + filtered_df = df[df['Age'] > 25] + + # Plotting filtered data + filtered_df.plot(kind='bar', x='Name', y='Age', color='skyblue') + plt.title('Age Distribution for Individuals Older than 25') + plt.xlabel('Name') + plt.ylabel('Age') + display(plt) + +Exercise +-------- +Write code to calculate the average age of the individuals in the DataFrame. \ No newline at end of file diff --git a/_sources/lectures/TWP66/toctree.rst b/_sources/lectures/TWP66/toctree.rst new file mode 100644 index 0000000000..f10eda5a66 --- /dev/null +++ b/_sources/lectures/TWP66/toctree.rst @@ -0,0 +1,19 @@ +===================== +Manipulación de Datos +===================== + + +.. image:: ../img/TWP10_001.jpeg + :height: 14.832cm + :width: 9.2cm + :align: center + :alt: + +.. toctree:: + :caption: Contenido + :maxdepth: 1 + :numbered: + + TWP66_1.rst + TWP66_2.rst + TWP66_3.rst diff --git a/_sources/lectures/TWP66/toctree_en.rst b/_sources/lectures/TWP66/toctree_en.rst new file mode 100644 index 0000000000..c96de1c11a --- /dev/null +++ b/_sources/lectures/TWP66/toctree_en.rst @@ -0,0 +1,19 @@ +================= +Data Manipulation +================= + + +.. image:: ../img/TWP10_001.jpeg + :height: 14.832cm + :width: 9.2cm + :align: center + :alt: + +.. toctree:: + :caption: Contenido + :maxdepth: 1 + :numbered: + + TWP66_1_en.rst + TWP66_2_en.rst + TWP66_3_en.rst diff --git a/_sources/lectures/_static/TWP66/TWP66_1.html b/_sources/lectures/_static/TWP66/TWP66_1.html new file mode 100644 index 0000000000..3cb316ba1f --- /dev/null +++ b/_sources/lectures/_static/TWP66/TWP66_1.html @@ -0,0 +1,70 @@ + + + + + + Examen de NumPy + + +

Quiz: Pon a prueba tu conocimiento

+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+ +
+ +

+ + + + diff --git a/_sources/lectures/_static/TWP66/TWP66_1_en.html b/_sources/lectures/_static/TWP66/TWP66_1_en.html new file mode 100644 index 0000000000..fd4e09545a --- /dev/null +++ b/_sources/lectures/_static/TWP66/TWP66_1_en.html @@ -0,0 +1,70 @@ + + + + + + NumPy Quiz + + +

Quiz: Test Your Knowledge

+ +
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ +
+ +
+ +

+ + + + diff --git a/_sources/lectures/img/TWP66_001.png b/_sources/lectures/img/TWP66_001.png new file mode 100644 index 0000000000000000000000000000000000000000..a7aba120bc50e613e9b4db60ac3e9429107251ff GIT binary patch literal 48250 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

yvHQx;dPj$oH9WSQ! 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 Date: Wed, 14 Aug 2024 19:49:32 +0530 Subject: [PATCH 2/6] adds pycon lessons --- _sources/lectures/TWP66/TWP66_1.rst | 4 +- _sources/lectures/TWP66/TWP66_1_en.rst | 12 +- _sources/lectures/TWP66/TWP66_2.rst | 157 ++++++++++++++++++------- _sources/lectures/TWP66/TWP66_2_en.rst | 155 +++++++++++++++++------- _sources/lectures/TWP66/TWP66_3.rst | 129 -------------------- _sources/lectures/TWP66/TWP66_3_en.rst | 144 +++++++---------------- _sources/lectures/TWP66/TWP66_4_en.rst | 89 ++++++++++++++ _sources/lectures/TWP66/TWP66_5_en.rst | 144 +++++++++++++++++++++++ _sources/lectures/TWP66/TWP66_6_en.rst | 142 ++++++++++++++++++++++ _sources/lectures/TWP66/toctree.rst | 2 +- _sources/lectures/TWP66/toctree_en.rst | 3 + _sources/lectures/img/TWP66_001.png | Bin 48250 -> 3090 bytes _sources/lectures/img/TWP66_002.png | Bin 0 -> 3094 bytes build_info | 1 + 14 files changed, 658 insertions(+), 324 deletions(-) delete mode 100644 _sources/lectures/TWP66/TWP66_3.rst create mode 100644 _sources/lectures/TWP66/TWP66_4_en.rst create mode 100644 _sources/lectures/TWP66/TWP66_5_en.rst create mode 100644 _sources/lectures/TWP66/TWP66_6_en.rst create mode 100644 _sources/lectures/img/TWP66_002.png create mode 100644 build_info diff --git a/_sources/lectures/TWP66/TWP66_1.rst b/_sources/lectures/TWP66/TWP66_1.rst index 0c0a724bc1..616288aae0 100644 --- a/_sources/lectures/TWP66/TWP66_1.rst +++ b/_sources/lectures/TWP66/TWP66_1.rst @@ -50,7 +50,7 @@ Creación de Arrays # Crear un array 2D arr_2d = np.array([[1, 2, 3], [4, 5, 6]]) - print("Array 2D:\n", arr_2d) + print("Array 2D:", arr_2d) Operaciones con Arrays ~~~~~~~~~~~~~~~~~~~~~~ @@ -90,7 +90,7 @@ Manipulación de Forma # Reformatear el array a 2x3 arr_reformateado = np.reshape(arr, (2, 3)) - print("Array Reformateado:\n", arr_reformateado) + print("Array Reformateado:", arr_reformateado) **Aplanamiento de Arrays**:: diff --git a/_sources/lectures/TWP66/TWP66_1_en.rst b/_sources/lectures/TWP66/TWP66_1_en.rst index cb3e1d4127..0e67489417 100644 --- a/_sources/lectures/TWP66/TWP66_1_en.rst +++ b/_sources/lectures/TWP66/TWP66_1_en.rst @@ -3,8 +3,6 @@ Introduction to NumPy ===================== .. image:: ../img/TWP66_001.png - :height: 9.258cm - :width: 14.925cm :align: center :alt: @@ -50,7 +48,7 @@ Creating Arrays # Create a 2D array arr_2d = np.array([[1, 2, 3], [4, 5, 6]]) - print("2D Array:\n", arr_2d) + print("2D Array:", arr_2d) Array Operations ~~~~~~~~~~~~~~~~ @@ -90,7 +88,7 @@ Shape Manipulation # Reshape the array to 2x3 reshaped_arr = np.reshape(arr, (2, 3)) - print("Reshaped Array:\n", reshaped_arr) + print("Reshaped Array:", reshaped_arr) **Flattening Arrays**:: @@ -103,12 +101,6 @@ Shape Manipulation flat_arr = arr_2d.flatten() print("Flattened Array:", flat_arr) -Conclusion ----------- -NumPy is essential for numerical computations in Python. Understanding the basics of array creation and manipulation is crucial for data science and machine learning. - -Make sure to explore the NumPy documentation for more advanced features and functionalities. - Quiz ---- .. raw:: html diff --git a/_sources/lectures/TWP66/TWP66_2.rst b/_sources/lectures/TWP66/TWP66_2.rst index d3a9137c29..e27ab36bfb 100644 --- a/_sources/lectures/TWP66/TWP66_2.rst +++ b/_sources/lectures/TWP66/TWP66_2.rst @@ -1,59 +1,132 @@ -=================================== -NumPy: Temas Avanzados y Ejercicios -=================================== +===================== +Introducción a Pandas +===================== -Overview --------- -En esta conferencia, profundizaremos en NumPy, explorando temas avanzados y proporcionando ejercicios para reforzar tu comprensión. +Introduction +------------ +Esta conferencia se centra en Pandas, una poderosa biblioteca de Python para manipulación y análisis de datos. Exploraremos sus capacidades en el manejo efectivo de datos estructurados. -Parte 1: Operaciones Avanzadas en NumPy ---------------------------------------- +Understanding Pandas Basics +--------------------------- +Pandas proporciona estructuras de datos como Series y DataFrame. Está construido sobre NumPy, lo que facilita trabajar con datos estructurados. -Broadcasting -~~~~~~~~~~~~ -La transmisión (broadcasting) en NumPy permite que funciones universales trabajen con arrays de diferentes formas. Por ejemplo: +.. code-block:: python + :caption: Importando Pandas y Cargando Datos Ficticios -.. activecode:: ac_l66_es_2a - :nocodelens: - :language: python3 - :python3_interpreter: pyscript + import pandas as pd + + # Datos ficticios + data = { + 'Nombre': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Edad': [28, 23, 25, 24, 30], + 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] + } + + # Creando un DataFrame + df = pd.DataFrame(data) + + # Mostrando el DataFrame + print(df) + +Análisis Exploratorio de Datos (EDA) con Pandas +----------------------------------------------- +Verifica las dimensiones de los datos y examina su estructura: + +.. code-block:: python + :caption: Verificando Dimensiones de los Datos e Información + + # Forma del DataFrame + print(df.shape) + + # Información sobre el DataFrame + print(df.info()) + +Limpieza y Transformación de Datos +---------------------------------- +Renombra columnas, maneja datos faltantes y convierte tipos de datos: - import numpy as np +.. code-block:: python + :caption: Limpieza y Transformación de Datos - a = np.array([1, 2, 3]) - b = np.array([10, 20, 30]) - c = a[:, np.newaxis] + b - print(c) + # Renombrando columnas + df.rename(columns={'Nombre': 'Nombre Completo', 'Ciudad': 'Ubicación'}, inplace=True) + + # Manejo de datos faltantes (no aplicable para estos datos ficticios) + + # Conversión de tipos de datos (no necesario para estos datos ficticios) -Ejercicio 1: Broadcasting -~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Crea un array NumPy `x` de forma (3, 4) con enteros aleatorios. -2. Crea un array NumPy `y` de forma (3, 1) con enteros aleatorios. -3. Realiza broadcasting para sumar `y` a `x` elemento por elemento. +Manipulación y Agregación de Datos +---------------------------------- +Selecciona, filtra, agrupa y agrega datos: -Indexación y Segmentación -~~~~~~~~~~~~~~~~~~~~~~~~~ -Los arrays NumPy admiten potentes operaciones de indexación y segmentación: +.. code-block:: python + :caption: Manipulación y Agregación de Datos -.. activecode:: ac_l66_es_2b + # Seleccionando columnas + print(df[['Nombre', 'Edad']]) + + # Filtrando datos + datos_filtrados = df[df['Edad'] > 25] + print(datos_filtrados) + + # Agrupando y agregando datos + estadisticas_grupo_edad = df.groupby('Edad').size() + print(estadisticas_grupo_edad) + +Visualización de Datos con Pandas y Matplotlib +---------------------------------------------- +Utiliza Matplotlib para visualizaciones: + +.. code-block:: python + :caption: Visualización de Datos + + import matplotlib.pyplot as plt + + # Ejemplo de gráfico + df['Edad'].plot(kind='hist', bins=5) + plt.title('Distribución de Edades') + plt.xlabel('Edad') + plt.ylabel('Frecuencia') + display(plt) + +.. note:: + use `plt.show()` en lugar de `display(plt)` si lo recrea en su máquina local. + + +Ejemplo Interactivo +------------------- +Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame por edad y visualizar los resultados: + +.. note:: + +.. activecode:: ac_l66_2_1es :nocodelens: :language: python3 :python3_interpreter: pyscript - import numpy as np + import pandas as pd + import matplotlib.pyplot as plt + + # Datos ficticios + data = { + 'Nombre': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Edad': [28, 23, 25, 24, 30], + 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] + } - arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - slice = arr[:2, 1:] - print(slice) + # Crear DataFrame + df = pd.DataFrame(data) -Ejercicio 2: Indexación y Segmentación -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Crea un array NumPy `z` de forma (5, 5) con enteros secuenciales comenzando desde 1. -2. Extrae la submatriz 3x3 de la esquina inferior derecha utilizando segmentación. + # Filtrar DataFrame por edad + df_filtrado = df[df['Edad'] > 25] -Conclusion ----------- -En esta conferencia, hemos cubierto operaciones avanzadas en NumPy y ejercicios para reforzar tu aprendizaje. Practica estos conceptos para profundizar tu comprensión de los arrays NumPy y sus funcionalidades. + # Graficar datos filtrados + df_filtrado.plot(kind='bar', x='Nombre', y='Edad', color='skyblue') + plt.title('Distribución de Edades para Individuos Mayores de 25 Años') + plt.xlabel('Nombre') + plt.ylabel('Edad') + display(plt) -.. note:: - Asegúrate de tener NumPy instalado (`pip install numpy`) para ejecutar los ejemplos de código. +Ejercicio +--------- +Escribe código para calcular la edad promedio de las personas en el DataFrame. diff --git a/_sources/lectures/TWP66/TWP66_2_en.rst b/_sources/lectures/TWP66/TWP66_2_en.rst index 8ee095c671..b271992cf6 100644 --- a/_sources/lectures/TWP66/TWP66_2_en.rst +++ b/_sources/lectures/TWP66/TWP66_2_en.rst @@ -1,60 +1,135 @@ -==================================== -NumPy: Advanced Topics and Exercises -==================================== +====================== +Introduction to Pandas +====================== -Overview --------- -In this lecture, we'll dive deeper into NumPy, exploring advanced topics and providing exercises to help reinforce your understanding. +.. image:: ../img/TWP66_002.png + :align: center + :alt: + + +Introduction +------------ +This lecture focuses on Pandas, a powerful Python library for data manipulation and analysis. We'll explore its capabilities in handling structured data effectively. + +Understanding Pandas Basics +--------------------------- +Pandas provides data structures like Series and DataFrame. It is built on top of NumPy, making it easy to work with structured data. + +.. code-block:: python + :caption: Importing Pandas and Loading Dummy Data + + import pandas as pd + + # Dummy data + data = { + 'Name': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Age': [28, 23, 25, 24, 30], + 'City': ['New York', 'Paris', 'Berlin', 'London', 'Tokyo'] + } + + # Creating a DataFrame + df = pd.DataFrame(data) + + # Displaying the DataFrame + print(df) + +Exploratory Data Analysis (EDA) with Pandas +------------------------------------------- +Check data dimensions and examine its structure: + +.. code-block:: python + :caption: Checking Data Dimensions and Info + + # Shape of the DataFrame + print(df.shape) + + # Information about the DataFrame + print(df.info()) -Part 1: Advanced NumPy Operations +Data Cleaning and Transformation +-------------------------------- +Rename columns: + +.. code-block:: python + :caption: Cleaning and Transforming Data + + # Rename columns + df.rename(columns={'Name': 'Full Name', 'City': 'Location'}, inplace=True) + + +Data Manipulation and Aggregation --------------------------------- +Select, filter, group, and aggregate data: -Broadcasting -~~~~~~~~~~~~ -Broadcasting in NumPy allows universal functions to work with arrays of different shapes. For example: +.. code-block:: python + :caption: Data Manipulation and Aggregation -.. activecode:: ac_l66_2a - :nocodelens: - :language: python3 - :python3_interpreter: pyscript + # Selecting columns + print(df[['Name', 'Age']]) + + # Filtering data + filtered_data = df[df['Age'] > 25] + print(filtered_data) + + # Grouping and aggregating data + age_group_stats = df.groupby('Age').size() + print(age_group_stats) - import numpy as np +Data Visualization with Pandas and Matplotlib +---------------------------------------------- +Utilize Matplotlib for visualizations: - a = np.array([1, 2, 3]) - b = np.array([10, 20, 30]) - c = a[:, np.newaxis] + b - print(c) +.. code-block:: python + :caption: Data Visualization -Exercise 1: Broadcasting -~~~~~~~~~~~~~~~~~~~~~~~~ -1. Create a NumPy array `x` of shape (3, 4) with random integers. -2. Create a NumPy array `y` of shape (3, 1) with random integers. -3. Perform broadcasting to add `y` to `x` element-wise. + import matplotlib.pyplot as plt -Indexing and Slicing -~~~~~~~~~~~~~~~~~~~~ -NumPy arrays support powerful indexing and slicing operations: + # Plotting example + df['Age'].plot(kind='hist', bins=5) + plt.title('Age Distribution') + plt.xlabel('Age') + plt.ylabel('Frequency') + display(plt) -.. activecode:: ac_l66_2b +.. note:: + We are using PyScript to run NumPy and Matplotlib in the browser. + Use `plt.show()` instead of `display(plt)` to show the plots if you are running code locally. + +Interactive Example +-------------------- +Here's an interactive example where you can filter the DataFrame based on age and visualize the results: + +.. activecode:: ac_l66_2_1 :nocodelens: :language: python3 :python3_interpreter: pyscript - import numpy as np + import pandas as pd + import matplotlib.pyplot as plt - arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - slice = arr[:2, 1:] - print(slice) + # Dummy data + data = { + 'Name': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Age': [28, 23, 25, 24, 30], + 'City': ['New York', 'Paris', 'Berlin', 'London', 'Tokyo'] + } -Exercise 2: Indexing and Slicing -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Create a NumPy array `z` of shape (5, 5) with sequential integers starting from 1. -2. Extract the bottom-right 3x3 sub-array using slicing. + # Create DataFrame + df = pd.DataFrame(data) -Conclusion ----------- -In this lecture, we've covered advanced NumPy operations and exercises to reinforce your learning. Practice these concepts to deepen your understanding of NumPy arrays and their functionalities. + # Filter DataFrame by age + filtered_df = df[df['Age'] > 25] + + # Plotting filtered data + filtered_df.plot(kind='bar', x='Name', y='Age', color='skyblue') + plt.title('Age Distribution for Individuals Older than 25') + plt.xlabel('Name') + plt.ylabel('Age') + display(plt) .. note:: - Ensure you have NumPy installed (`pip install numpy`) to run the code examples. + Ensure you run all the code blocks provided to see the complete results and understand the functionalities demonstrated. +Exercise +-------- +Write code to calculate the average age of the individuals in the DataFrame. \ No newline at end of file diff --git a/_sources/lectures/TWP66/TWP66_3.rst b/_sources/lectures/TWP66/TWP66_3.rst deleted file mode 100644 index b7d8e1b2cf..0000000000 --- a/_sources/lectures/TWP66/TWP66_3.rst +++ /dev/null @@ -1,129 +0,0 @@ -================== -El Poder de Pandas -================== - -Introduction ------------- -Esta conferencia se centra en Pandas, una poderosa biblioteca de Python para manipulación y análisis de datos. Exploraremos sus capacidades en el manejo efectivo de datos estructurados. - -Understanding Pandas Basics ---------------------------- -Pandas proporciona estructuras de datos como Series y DataFrame. Está construido sobre NumPy, lo que facilita trabajar con datos estructurados. - -.. code-block:: python - :caption: Importando Pandas y Cargando Datos Ficticios - - import pandas as pd - - # Datos ficticios - data = { - 'Nombre': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], - 'Edad': [28, 23, 25, 24, 30], - 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] - } - - # Creando un DataFrame - df = pd.DataFrame(data) - - # Mostrando el DataFrame - print(df) - -Análisis Exploratorio de Datos (EDA) con Pandas ------------------------------------------------ -Verifica las dimensiones de los datos y examina su estructura: - -.. code-block:: python - :caption: Verificando Dimensiones de los Datos e Información - - # Forma del DataFrame - print(df.shape) - - # Información sobre el DataFrame - print(df.info()) - -Limpieza y Transformación de Datos ----------------------------------- -Renombra columnas, maneja datos faltantes y convierte tipos de datos: - -.. code-block:: python - :caption: Limpieza y Transformación de Datos - - # Renombrando columnas - df.rename(columns={'Nombre': 'Nombre Completo', 'Ciudad': 'Ubicación'}, inplace=True) - - # Manejo de datos faltantes (no aplicable para estos datos ficticios) - - # Conversión de tipos de datos (no necesario para estos datos ficticios) - -Manipulación y Agregación de Datos ----------------------------------- -Selecciona, filtra, agrupa y agrega datos: - -.. code-block:: python - :caption: Manipulación y Agregación de Datos - - # Seleccionando columnas - print(df[['Nombre', 'Edad']]) - - # Filtrando datos - datos_filtrados = df[df['Edad'] > 25] - print(datos_filtrados) - - # Agrupando y agregando datos - estadisticas_grupo_edad = df.groupby('Edad').size() - print(estadisticas_grupo_edad) - -Visualización de Datos con Pandas y Matplotlib ----------------------------------------------- -Utiliza Matplotlib para visualizaciones: - -.. code-block:: python - :caption: Visualización de Datos - - import matplotlib.pyplot as plt - - # Ejemplo de gráfico - df['Edad'].plot(kind='hist', bins=5) - plt.title('Distribución de Edades') - plt.xlabel('Edad') - plt.ylabel('Frecuencia') - plt.show() - -Ejemplo Interactivo -------------------- -Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame por edad y visualizar los resultados: - -.. note:: - Estamos usando PyScript para ejecutar Pandas en el navegador. Utiliza `plt.show()` en lugar de `display()` para mostrar los resultados. - -.. activecode:: ac_l66_es_3a - :nocodelens: - :language: python3 - :python3_interpreter: pyscript - - import pandas as pd - import matplotlib.pyplot as plt - - # Datos ficticios - data = { - 'Nombre': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], - 'Edad': [28, 23, 25, 24, 30], - 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] - } - - # Crear DataFrame - df = pd.DataFrame(data) - - # Filtrar DataFrame por edad - df_filtrado = df[df['Edad'] > 25] - - # Graficar datos filtrados - df_filtrado.plot(kind='bar', x='Nombre', y='Edad', color='skyblue') - plt.title('Distribución de Edades para Individuos Mayores de 25 Años') - plt.xlabel('Nombre') - plt.ylabel('Edad') - display(plt) - -Ejercicio ---------- -Escribe código para calcular la edad promedio de las personas en el DataFrame. diff --git a/_sources/lectures/TWP66/TWP66_3_en.rst b/_sources/lectures/TWP66/TWP66_3_en.rst index 822554ba6a..5f59b4c73c 100644 --- a/_sources/lectures/TWP66/TWP66_3_en.rst +++ b/_sources/lectures/TWP66/TWP66_3_en.rst @@ -1,129 +1,73 @@ -=============== -Power of Pandas -=============== +========================= +Advanced NumPy Operations +========================= Introduction ------------ -This lecture focuses on Pandas, a powerful Python library for data manipulation and analysis. We'll explore its capabilities in handling structured data effectively. +In this exercise, we will use Python to explore the use of the NumPy and Matplotlib libraries. -Understanding Pandas Basics ---------------------------- -Pandas provides data structures like Series and DataFrame. It is built on top of NumPy, making it easy to work with structured data. - -.. code-block:: python - :caption: Importing Pandas and Loading Dummy Data - - import pandas as pd - - # Dummy data - data = { - 'Name': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], - 'Age': [28, 23, 25, 24, 30], - 'City': ['New York', 'Paris', 'Berlin', 'London', 'Tokyo'] - } - - # Creating a DataFrame - df = pd.DataFrame(data) - - # Displaying the DataFrame - print(df) +Code Example +------------ +We will use the NumPy library to define the domain and range of a function, and Matplotlib to plot the results. -Exploratory Data Analysis (EDA) with Pandas -------------------------------------------- -Check data dimensions and examine its structure: +**Define the Domain and Range** .. code-block:: python - :caption: Checking Data Dimensions and Info - # Shape of the DataFrame - print(df.shape) - - # Information about the DataFrame - print(df.info()) + import numpy as np -Data Cleaning and Transformation --------------------------------- -Rename columns, handle missing data, and convert data types: + # Define the DOMAIN of a FUNCTION + N = 55 + X = np.linspace(-5, 5, N) # -5 lower limit, 5 upper limit, N number of points to generate + # Display the values + print(X) -.. code-block:: python - :caption: Cleaning and Transforming Data - - # Rename columns - df.rename(columns={'Name': 'Full Name', 'City': 'Location'}, inplace=True) - - # Handle missing data (not applicable for this dummy data) - - # Convert data types (not necessary for this dummy data) + # Calculate the RANGE of a FUNCTION + Y = np.sin(X) + # Display the calculated values + print(Y) -Data Manipulation and Aggregation ---------------------------------- -Select, filter, group, and aggregate data: +**Plot the Values** .. code-block:: python - :caption: Data Manipulation and Aggregation - - # Selecting columns - print(df[['Name', 'Age']]) - - # Filtering data - filtered_data = df[df['Age'] > 25] - print(filtered_data) - - # Grouping and aggregating data - age_group_stats = df.groupby('Age').size() - print(age_group_stats) -Data Visualization with Pandas and Matplotlib ----------------------------------------------- -Utilize Matplotlib for visualizations: + from matplotlib import pyplot as plt -.. code-block:: python - :caption: Data Visualization + # Plot the values of X and Y with red circles + plt.plot(X, Y, 'ro') + plt.grid(True) - import matplotlib.pyplot as plt + # Plot the values of X and Y with blue lines + plt.plot(X, Y, 'b-') + plt.grid(True) - # Plotting example - df['Age'].plot(kind='hist', bins=5) - plt.title('Age Distribution') - plt.xlabel('Age') - plt.ylabel('Frequency') - plt.show() - -Interactive Example --------------------- -Here's an interactive example where you can filter the DataFrame based on age and visualize the results: + # Display the plot + diplay(plt) .. note:: - We are using PyScript to run Pandas in the browser. Use `plt.show()` instead of `display()` for displaying results. + use `plt.show()` instead of `display(plt)` if recreating on local machine. + +**Interactive Code Editor** + +To experiment with the code interactively, use the provided interactive code blocks below. Run all the code blocks to see the results and explore different functionalities. -.. activecode:: ac_l66_3a +.. activecode:: ac_l66_1a :nocodelens: :language: python3 :python3_interpreter: pyscript - import pandas as pd + import numpy as np import matplotlib.pyplot as plt - # Dummy data - data = { - 'Name': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], - 'Age': [28, 23, 25, 24, 30], - 'City': ['New York', 'Paris', 'Berlin', 'London', 'Tokyo'] - } - - # Create DataFrame - df = pd.DataFrame(data) - - # Filter DataFrame by age - filtered_df = df[df['Age'] > 25] + # Define the domain + N = 55 + X = np.linspace(-5, 5, N) + Y = np.sin(X) - # Plotting filtered data - filtered_df.plot(kind='bar', x='Name', y='Age', color='skyblue') - plt.title('Age Distribution for Individuals Older than 25') - plt.xlabel('Name') - plt.ylabel('Age') + # Plotting the values + plt.plot(X, Y, 'b-') + plt.grid(True) display(plt) -Exercise --------- -Write code to calculate the average age of the individuals in the DataFrame. \ No newline at end of file +.. note:: + Ensure you run all the code blocks provided to see the complete results and understand the functionalities demonstrated. \ No newline at end of file diff --git a/_sources/lectures/TWP66/TWP66_4_en.rst b/_sources/lectures/TWP66/TWP66_4_en.rst new file mode 100644 index 0000000000..86e9ae98cc --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_4_en.rst @@ -0,0 +1,89 @@ +================================== +Exploring Python Libraries Further +================================== + +Introduction +------------ +In this section, we will delve deeper into the use of Python libraries, specifically focusing on advanced operations with NumPy and visualizations using Matplotlib. + +**Working with Functions** + +We'll start by defining the domain of a function and calculating its corresponding range, followed by plotting these values. + +.. code-block:: python + + import numpy as np + + # Define the DOMAIN of a FUNCTION + N = 35 + X = np.linspace(-5, 5, N) # -5 lower limit, 5 upper limit, N number of points to generate + # Display the values + print(X) + + # Calculate the CO-DOMAIN of a FUNCTION + Y = np.sin(X) / X + # Display the calculated values + print(Y) + +**Plotting Complex Functions** + +Let's plot the calculated values and explore more advanced plotting techniques. + +.. code-block:: python + + from matplotlib import pyplot as plt + + # Plot the values of X and Y with red circles + plt.plot(X, Y, 'ro') + plt.grid(True) + + # Plot the values of X and Y with cyan circles + plt.plot(X, Y, 'co') + plt.grid(True) + + # Plot the values of X and Y with blue lines + plt.plot(X, Y, 'b-') + plt.grid(True) + display(plt) + +**Exploring and Composing Functions** + +We can also explore and compose functions using NumPy and Matplotlib. + +.. code-block:: python + + Z = (np.sin(X)) ** 2 + plt.plot(X, Z, '.-') + plt.grid(True) + display(plt) + +**Interactive Code Editor** + +To experiment with the code interactively, use the provided interactive code blocks below. Run all the code blocks to see the results and explore different functionalities. + +.. activecode:: ac_l66_2b + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + import numpy as np + import matplotlib.pyplot as plt + + # Define the domain + N = 35 + X = np.linspace(-5, 5, N) + Y = np.sin(X) / X + + # Plotting the values + plt.plot(X, Y, 'b-') + plt.grid(True) + display(plt) + + # Exploring function composition + Z = (np.sin(X)) ** 2 + plt.plot(X, Z, '.-') + plt.grid(True) + display(plt) + +.. note:: + use `plt.show()` instead of `display(plt)` if recreating on local machine. \ No newline at end of file diff --git a/_sources/lectures/TWP66/TWP66_5_en.rst b/_sources/lectures/TWP66/TWP66_5_en.rst new file mode 100644 index 0000000000..e90abb3b86 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_5_en.rst @@ -0,0 +1,144 @@ +========================================== +Interactive Data Visualization with Python +========================================== + +In this lesson, we will explore the use of Python libraries for creating interactive data visualizations. You will learn how to generate various types of plots, including line plots, bar charts, and pie charts. We will also cover how to interact with these plots dynamically. By the end of this lesson, you'll have a solid understanding of how to create and manipulate visual data representations in Python. + +.. contents:: Table of Contents + :depth: 2 + :local: + +.. note:: + Ensure you have all the necessary Python libraries installed. This lesson assumes you are already familiar with NumPy and Matplotlib. + +Line Plots +---------- + +Let's start with a simple line plot to compare the average temperatures in Argentina between the years 1991 and 2020. + +.. code-block:: python + + import matplotlib.pyplot as plt + + temp_1991 = [20.5, 20.0, 18.9, 14.8, 11.9, 8.2, 7.3, 8.9, 12.4, 13.8, 17.3, 18.6] + temp_2020 = [21.5, 20.1, 20.0, 14.9, 11.0, 8.3, 6.4, 9.7, 12.5, 15.5, 19.0, 20.3] + + plt.plot(temp_1991, linewidth=3, label='1991') + plt.plot(temp_2020, linestyle='dashed', linewidth=3, label='2020') + + plt.ylabel('Temperaturas') + plt.title('Comparativa de 1991 y 2020') + plt.xlabel('Mes') + plt.legend() + plt.grid(True) + display(plt) # Replace plt.show() if running locally + +.. note:: + Replace `display(plt)` with `plt.show()` if running the code locally. + +Now, let's label the months on the x-axis: + +.. code-block:: python + + meses = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', + 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'] + + plt.plot(meses, temp_1991, linewidth=3, label='1991') + plt.plot(meses, temp_2020, linestyle='dashed', linewidth=3, label='2020') + + plt.ylabel('Temperaturas') + plt.title('Comparativa de 1991 y 2020') + plt.xlabel('Mes') + plt.legend() + plt.grid(True) + display(plt) # Replace plt.show() if running locally + +Bar Charts +---------- + +Let's compare the temperatures using a bar chart: + +.. code-block:: python + + import numpy as np + + ancho = 0.35 + x = np.arange(len(temp_1991)) + fig, ax = plt.subplots() + rects1 = ax.bar(x - ancho/2, temp_1991, ancho, color='b', label='1991') + rects2 = ax.bar(x + ancho/2, temp_2020, ancho, color='g', label='2020') + + ax.set_ylabel('Temperaturas') + ax.set_title('Comparativa') + ax.set_xticks(x) + ax.set_xticklabels(meses) + ax.legend() + + display(plt) # Replace plt.show() if running locally + +Pie Charts +---------- + +Visualize the distribution of female students across different study areas in 2018 using a pie chart: + +.. code-block:: python + + est_mujeres = [10512, 4774, 16232, 22904, 36700] + etiquetas = ['Ciencias Aplicadas', 'Ciencias Básicas', + 'Ciencias de la Salud', 'Ciencias Humanas', + 'Ciencias Sociales'] + + fig1, ax = plt.subplots() + ax.set_title('Estudiantes 2018 según área de estudio') + ax.axis('equal') + ax.pie(est_mujeres, labels=etiquetas, autopct='%1.2f%%') + + display(plt) # Replace plt.show() if running locally + +.. Interactive Widgets +.. -------------------- + +.. Add interactivity to your plots using widgets. For example, dynamically change the degree of a polynomial: + +.. .. code-block:: python + +.. import numpy as np +.. import matplotlib.pyplot as plt +.. import ipywidgets as widgets +.. from IPython.display import display + +.. @widgets.interact(grado=(0, 9), N_puntos=(5, 35)) +.. def mi_plot(grado=3, N_puntos=5): +.. x = np.linspace(-10, 10, N_puntos) +.. y = x**grado +.. plt.figure(figsize=(12,8)) +.. plt.plot(x, y, 'ro-') +.. plt.grid(True) +.. display(plt) # Replace plt.show() if running locally + +Exercise: Create Your Own Visualization +--------------------------------------- + +**Task:** Create a bar chart that compares the average temperatures in Argentina across three different years: 1991, 2000, and 2020. + +**Hint:** You can use the data for 2000 as follows: + +.. code-block:: python + + temp_2000 = [21.2, 19.4, 17.0, 14.5, 10.1, 8.1, 5.6, 8.9, 10.8, 14.9, 16.3, 19.6] + +Follow the steps from the previous examples to create and display your chart. + +Interactive Editor +------------------ + +.. note:: + Use this editor to run the codes, practice, and do exercises to see the results. + +.. activecode:: ac_l66_5_1a + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + # You can start practicing here by copying and pasting the code examples from above, + # or by writing your own code to explore different visualizations. \ No newline at end of file diff --git a/_sources/lectures/TWP66/TWP66_6_en.rst b/_sources/lectures/TWP66/TWP66_6_en.rst new file mode 100644 index 0000000000..b3ff5bd2c8 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_6_en.rst @@ -0,0 +1,142 @@ +========================================== +Interactive Data Visualization with Python +========================================== + +In this lesson, we will explore the use of Python libraries for creating interactive data visualizations. You will learn how to generate various types of plots, including line plots, bar charts, and pie charts. We will also cover how to interact with these plots dynamically. By the end of this lesson, you'll have a solid understanding of how to create and manipulate visual data representations in Python. + +.. contents:: Table of Contents + :depth: 2 + :local: + +.. note:: + Ensure you have all the necessary Python libraries installed. This lesson assumes you are already familiar with NumPy and Matplotlib. + +Line Plots +---------- + +Let's start with a simple line plot to compare the average temperatures in Argentina between the years 1991 and 2020. + +.. code-block:: python + + import matplotlib.pyplot as plt + + temp_1991 = [20.5, 20.0, 18.9, 14.8, 11.9, 8.2, 7.3, 8.9, 12.4, 13.8, 17.3, 18.6] + temp_2020 = [21.5, 20.1, 20.0, 14.9, 11.0, 8.3, 6.4, 9.7, 12.5, 15.5, 19.0, 20.3] + + plt.plot(temp_1991, linewidth=3, label='1991') + plt.plot(temp_2020, linestyle='dashed', linewidth=3, label='2020') + + plt.ylabel('Temperaturas') + plt.title('Comparativa de 1991 y 2020') + plt.xlabel('Mes') + plt.legend() + plt.grid(True) + display(plt) # Replace plt.show() + +Now, let's label the months on the x-axis: + +.. code-block:: python + + meses = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', + 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'] + + plt.plot(meses, temp_1991, linewidth=3, label='1991') + plt.plot(meses, temp_2020, linestyle='dashed', linewidth=3, label='2020') + + plt.ylabel('Temperaturas') + plt.title('Comparativa de 1991 y 2020') + plt.xlabel('Mes') + plt.legend() + plt.grid(True) + display(plt) # Replace plt.show() + +Bar Charts +---------- + +Let's compare the temperatures using a bar chart: + +.. code-block:: python + + import numpy as np + + ancho = 0.35 + x = np.arange(len(temp_1991)) + fig, ax = plt.subplots() + rects1 = ax.bar(x - ancho/2, temp_1991, ancho, color='b', label='1991') + rects2 = ax.bar(x + ancho/2, temp_2020, ancho, color='g', label='2020') + + ax.set_ylabel('Temperaturas') + ax.set_title('Comparativa') + ax.set_xticks(x) + ax.set_xticklabels(meses) + ax.legend() + + display(plt) # Replace plt.show() + +Pie Charts +---------- + +Visualize the distribution of female students across different study areas in 2018 using a pie chart: + +.. code-block:: python + + est_mujeres = [10512, 4774, 16232, 22904, 36700] + etiquetas = ['Ciencias Aplicadas', 'Ciencias Básicas', + 'Ciencias de la Salud', 'Ciencias Humanas', + 'Ciencias Sociales'] + + fig1, ax = plt.subplots() + ax.set_title('Estudiantes 2018 según área de estudio') + ax.axis('equal') + ax.pie(est_mujeres, labels=etiquetas, autopct='%1.2f%%') + + display(plt) # Replace plt.show() + +Interactive Widgets +-------------------- + +Add interactivity to your plots using widgets. For example, dynamically change the degree of a polynomial: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + import ipywidgets as widgets + from IPython.display import display + + @widgets.interact(grado=(0, 9), N_puntos=(5, 35)) + def mi_plot(grado=3, N_puntos=5): + x = np.linspace(-10, 10, N_puntos) + y = x**grado + plt.figure(figsize=(12,8)) + plt.plot(x, y, 'ro-') + plt.grid(True) + display(plt) # Replace plt.show() + +Exercise: Create Your Own Visualization +--------------------------------------- + +**Task:** Create a bar chart that compares the average temperatures in Argentina across three different years: 1991, 2000, and 2020. + +**Hint:** You can use the data for 2000 as follows: + +.. code-block:: python + + temp_2000 = [21.2, 19.4, 17.0, 14.5, 10.1, 8.1, 5.6, 8.9, 10.8, 14.9, 16.3, 19.6] + +Follow the steps from the previous examples to create and display your chart. + +Interactive Editor +------------------ + +.. note:: + Use this editor to run the codes, practice, and do exercises to see the results. + +.. activecode:: ac_l66_5_1a + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + # You can start practicing here by copying and pasting the code examples from above, + # or by writing your own code to explore different visualizations. + diff --git a/_sources/lectures/TWP66/toctree.rst b/_sources/lectures/TWP66/toctree.rst index f10eda5a66..cac22efbe0 100644 --- a/_sources/lectures/TWP66/toctree.rst +++ b/_sources/lectures/TWP66/toctree.rst @@ -16,4 +16,4 @@ Manipulación de Datos TWP66_1.rst TWP66_2.rst - TWP66_3.rst + TWP66_3_en.rst diff --git a/_sources/lectures/TWP66/toctree_en.rst b/_sources/lectures/TWP66/toctree_en.rst index c96de1c11a..bdd28cb630 100644 --- a/_sources/lectures/TWP66/toctree_en.rst +++ b/_sources/lectures/TWP66/toctree_en.rst @@ -17,3 +17,6 @@ Data Manipulation TWP66_1_en.rst TWP66_2_en.rst TWP66_3_en.rst + TWP66_4_en.rst + TWP66_5_en.rst + TWP66_6_en.rst diff --git a/_sources/lectures/img/TWP66_001.png b/_sources/lectures/img/TWP66_001.png index a7aba120bc50e613e9b4db60ac3e9429107251ff..25600bfc24b45796159ebff2712c5a7a49b65368 100644 GIT binary patch literal 3090 zcmV+t4DIuYP)a@M{~}fv*Sc^%}RC7J8aBEsLkr{`97x1Ub53ZZp_!;^Z5GyqR->y>-e|E z>REu&$J6enx#fMD+uh{!%;fKpsNayt-`U{vhM?SGhSYSD*wg9q!{F_2x!3dd{C~jP z;P3XJ&*Q<)?Xtq?cfHx$?ewGbye&e-sEli0i6>r{NvX^Yk@WXg=C-gt2eWB>pQ zG)Y83RCt{2ooQpDIuwRMkboGed+pR}omQv4T5bRTkGnt?vLc{%^Soc?szAcSNzRhc z>o_0~2m}IwKp+qZ1OkCTAP@)y0)apv5C{YUHPln`)jjx4dioo;Ucb5%zeXv|sMU(2 zSFq7D=q0C_32gLqJ#m^q^mM&QG$~OS^$qo;(F7Z9u9tr%nmJMMOtodFNo@26h}Kea zlR~p9YTbNw2Y;NBR~ykN0_$v|QBqUL_li z|Gmh+zdl0rWYgj?_32u8DR`#%QK7l)#u3D$X5}o7__V`0^+_D#)1%E&dt8qPY8JKf{#SL(W9>qS|IbbZI`rTqgmd znY599l<3o){fuj`<}FIA9$EC>RipPsT$0ycxo29G)jTqst!Lfb$}1(UIKJjm$+Bx_ z6UEQw)H2QMZB`AXk~a&{C@Lv?B+o4qQKLOyolHcd`0tZ+P;x7uWFQLeo#{=P5u^B@ zOf#!9slGmWmV8+{Z(cLao;;Yvc{I|CND;~3?KT=;d%?bq#Mrh{zsuiR?Z8EzJ5Y&gCAmk{SLsCG zRNKrFs4L{@rbPFfvV#^HP2;GS^mLa`0awX0C%U#BVl9;DHp<0IC0EKbC5ndw(*d?3 zQkjhk=Ugq%lxV0A`f{4Byi%fuo6gIT+{xAR%ZpCE^@U< z+?IuM`_v*NWhm-p-^jNg0byFI3UNUqHkh9TOux94w2{ zB1Kv*v{DOy8c&4Cd_C2h3TZDc!P9qDAr#=@_}mRiJkijUD%xsKaZ3-@Z`DIBJWXTa zlX;TII{b6qh9sV@aTuD3nk#aZdAj~iJNff@W^VYrCMxqpd&^-eQCoepI#1VYt0#X2 zPooz;K{8J_9N7*Oi5k4nlKfkPryHt+;Zu0}L`b;jbGjvkr~hC-lo8dvP#Pi8sk9DH z6!hiaK7%Kk+-G|5LQWVB&)AT{)5T>ED6G`{N`LO=h(8|F5;!2vnY55id~PlxgJ*3N)l9g9=? zm|WTSs;@BWJds~KR?0Iaie;iprNUgFC&L;P^NY-r5I_P?`ZM7<%rD@7Oi>Y9rpG1^ zq42=G!>SU`QTlx7Y2w(QlkWm8^Qgnq4Q9p9BOX-v-j27V=byEC?)Q40)PSeE7wtX0 z)Iq+V;Gu*kAMatW03qD{l(wkG$u)VpxG?X6XG-*))()Nx*}R!&6yKS7BDd!;5IiTt z4S32zGf(-3%nrx=Q3`BDFE30$Z0({>IA!AL6(s_Zr|VIkH+qTL$TOw+q_)TGGj!G= zgMj)c@k9ak0#;?ozwj{o?4pC6=Y+*ed0CA%=wj}CXje;9oGLtpTG|Obqv)?jQ{dTg z+U(jsEfY2w@9F3HW;<%Tg}LI%U^|{OfMh;2@f={*e(r(U=;r3wBVSl+M3s5E9xu5x z=BaIb(s}ZDn)#$g_DSn)Q+^+`^VFBnk2=qUKTbB`u($NOVJVgV|pG^gxQKZon3inlbt^_}LGS4Ia=m;TZ zQ1s%5Iw*4~Je?wD%0ujm$1@DlRrH}B` z|7MW-o^mCgMV?gfWF5ooz|Y~?5q6F=+32A1lNV0w2TP8T=eBV1{zMG58PA1AGmcN^$$b*znass^CGb5RD;MWU zk>Ki^LiCeGo~#m^_eQi3J~c_o7vrNEJjpH(ou_jkTS73~zm)7kI&Go=r^%a3wt+C7 zWd8`~$u@WtJjoZinf2+O5#xIhiimwS+!bo#*%PC|BRuKWhB`dS(>L%;W_!^-Q;iNj z&Wb_qEIWLS%IwoqI!WuvsIGm|l+$aruinJd*_rkVn0WGyB9(bM36;4!+E1O{da(Xu z_&HH8Wc!?$54VauDC9SL;mgQ#YBo@nr?Bm&I?wMenny^x;%dmqQ%n-9Jf%%czlSIF z?qS0%p=O>_<0_rVQ`r*sYk1OWxa_@*Qmq4?$O%08?f?r3#uqOus&h}?#SwY3@}rSw$$mwJXWT0L6As@{Gzkb! zdkL{W$&zR3A}gfFOcmDSB%ankbop)dhc0*E6U;ML?;%9;L)myI^89%;Q}cWeGhyRj zs;H;!Jd}-muNi0^oXr^o#zjn4dimPwk}?S=g*{hVQD+mtMZIn%P;HnH`ZF6 zL96iu+q7wp8t?>~R;|O@JYP!wxH?EN(E9roL6Wv1@I0&Tjq4o-p4xkGAd@-)s>HMO z6$DVB9!5ubmcP&ek~BTwBRqj-J#DaW=Lxo1U!5I&MPK6yG@EI?&o>vTJb`9YC2h}F zc!F)7q<%W+MV>(ORIO3Sc*a2U3`%BfJq~D|Rq#LB1%W^y5C{YUfj}S-2m}IwKp+qZ g1OkCTAkY=-e>P|G8vrpSbN~PV07*qoM6N<$g5+00>;M1& literal 48250 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

yvHQx;dPj$oH9WSQ! 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 Date: Wed, 14 Aug 2024 21:27:10 +0530 Subject: [PATCH 3/6] fixes lesson structure + minor fixes --- _sources/lectures/TWP66/TWP66_1.rst | 82 +++++------ _sources/lectures/TWP66/TWP66_2.rst | 65 ++++---- _sources/lectures/TWP66/TWP66_2_en.rst | 2 +- _sources/lectures/TWP66/TWP66_3.rst | 73 +++++++++ _sources/lectures/TWP66/TWP66_3_en.rst | 4 +- _sources/lectures/TWP66/TWP66_4.rst | 89 +++++++++++ _sources/lectures/TWP66/TWP66_4_en.rst | 2 +- _sources/lectures/TWP66/TWP66_5.rst | 136 +++++++++++++++++ _sources/lectures/TWP66/TWP66_5_en.rst | 196 ++++++++++++------------- _sources/lectures/TWP66/TWP66_6.rst | 154 +++++++++++++++++++ _sources/lectures/TWP66/TWP66_6_en.rst | 58 +++++--- _sources/lectures/TWP66/toctree.rst | 5 +- requirements.txt | 2 +- 13 files changed, 661 insertions(+), 207 deletions(-) create mode 100644 _sources/lectures/TWP66/TWP66_3.rst create mode 100644 _sources/lectures/TWP66/TWP66_4.rst create mode 100644 _sources/lectures/TWP66/TWP66_5.rst create mode 100644 _sources/lectures/TWP66/TWP66_6.rst diff --git a/_sources/lectures/TWP66/TWP66_1.rst b/_sources/lectures/TWP66/TWP66_1.rst index 616288aae0..90b74e6e76 100644 --- a/_sources/lectures/TWP66/TWP66_1.rst +++ b/_sources/lectures/TWP66/TWP66_1.rst @@ -3,62 +3,60 @@ Introducción a NumPy ==================== .. image:: ../img/TWP66_001.png - :height: 9.258cm - :width: 14.925cm :align: center :alt: Introducción ------------ -Esta completa lección se centra en dominar NumPy, una de las bibliotecas más populares en Python para cálculos numéricos. Exploraremos diversas funcionalidades de NumPy, comprendiendo cómo crear y manipular matrices para realizar operaciones numéricas de manera efectiva. +Esta conferencia integral se centra en dominar NumPy, una de las bibliotecas más populares en Python para cálculos numéricos. Exploraremos varias funcionalidades de NumPy, entendiendo cómo crear y manipular arreglos para realizar operaciones numéricas de manera efectiva. -Parte 1: Entendiendo los Fundamentos de NumPy ---------------------------------------------- +Parte 1: Entendiendo los Conceptos Básicos de NumPy +--------------------------------------------------- .. contents:: :local: -Visión general +Visión General ~~~~~~~~~~~~~~ -NumPy es una potente biblioteca para cálculos numéricos en Python. Proporciona soporte para grandes matrices y matrices multidimensionales, junto con una colección de funciones matemáticas para operar en estas matrices. +NumPy es una poderosa biblioteca para cálculos numéricos en Python. Proporciona soporte para grandes arreglos y matrices multidimensionales, junto con una colección de funciones matemáticas para operar sobre estos arreglos. -Instalación de NumPy -~~~~~~~~~~~~~~~~~~~~ +Instalando NumPy +~~~~~~~~~~~~~~~~ Instala NumPy usando pip:: pip install numpy -Importar NumPy -~~~~~~~~~~~~~~ +Importando NumPy +~~~~~~~~~~~~~~~~ Importa NumPy en tu script de Python:: import numpy as np -Creación de Arrays -~~~~~~~~~~~~~~~~~~ -**Array 1D**:: +Creando Arreglos +~~~~~~~~~~~~~~~~ +**Arreglo 1D**:: import numpy as np - # Crear un array 1D + # Crear un arreglo 1D arr = np.array([1, 2, 3, 4, 5]) - print("Array 1D:", arr) + print("Arreglo 1D:", arr) -**Array 2D**:: +**Arreglo 2D**:: import numpy as np - # Crear un array 2D + # Crear un arreglo 2D arr_2d = np.array([[1, 2, 3], [4, 5, 6]]) - print("Array 2D:", arr_2d) + print("Arreglo 2D:", arr_2d) -Operaciones con Arrays -~~~~~~~~~~~~~~~~~~~~~~ +Operaciones con Arreglos +~~~~~~~~~~~~~~~~~~~~~~~~ **Operaciones Básicas**:: import numpy as np - # Crear un array + # Crear un arreglo arr = np.array([1, 2, 3, 4, 5]) # Realizar operaciones básicas @@ -69,47 +67,41 @@ Operaciones con Arrays import numpy as np - # Crear arrays + # Crear arreglos arr1 = np.array([1, 2, 3]) arr2 = np.array([4, 5, 6]) - # Adición elemento a elemento - print("Adición Elemento a Elemento:", arr1 + arr2) + # Suma elemento a elemento + print("Suma Elemento a Elemento:", arr1 + arr2) # Multiplicación elemento a elemento print("Multiplicación Elemento a Elemento:", arr1 * arr2) -Manipulación de Forma -~~~~~~~~~~~~~~~~~~~~~ -**Reformatear Arrays**:: +Manipulación de la Forma +~~~~~~~~~~~~~~~~~~~~~~~~ +**Cambio de Forma de Arreglos**:: import numpy as np - # Crear un array 1D + # Crear un arreglo 1D arr = np.array([1, 2, 3, 4, 5, 6]) - # Reformatear el array a 2x3 - arr_reformateado = np.reshape(arr, (2, 3)) - print("Array Reformateado:", arr_reformateado) + # Cambiar la forma del arreglo a 2x3 + arr_reshaped = np.reshape(arr, (2, 3)) + print("Arreglo con Forma Cambiada:", arr_reshaped) -**Aplanamiento de Arrays**:: +**Aplanamiento de Arreglos**:: import numpy as np - # Crear un array 2D + # Crear un arreglo 2D arr_2d = np.array([[1, 2, 3], [4, 5, 6]]) - # Aplanar el array - arr_aplanado = arr_2d.flatten() - print("Array Aplanado:", arr_aplanado) - -Conclusión ----------- -NumPy es fundamental para cálculos numéricos en Python. Comprender los fundamentos de la creación y manipulación de arrays es crucial para la ciencia de datos y el aprendizaje automático. + # Aplanar el arreglo + arr_flat = arr_2d.flatten() + print("Arreglo Aplanado:", arr_flat) -Asegúrate de explorar la documentación de NumPy para conocer características y funcionalidades más avanzadas. - -Quiz ----- +Cuestionario +------------ .. raw:: html :file: ../_static/TWP66/TWP66_1.html diff --git a/_sources/lectures/TWP66/TWP66_2.rst b/_sources/lectures/TWP66/TWP66_2.rst index e27ab36bfb..2a5ed02b2a 100644 --- a/_sources/lectures/TWP66/TWP66_2.rst +++ b/_sources/lectures/TWP66/TWP66_2.rst @@ -2,22 +2,27 @@ Introducción a Pandas ===================== -Introduction +.. image:: ../img/TWP66_002.png + :align: center + :alt: + + +Introducción ------------ -Esta conferencia se centra en Pandas, una poderosa biblioteca de Python para manipulación y análisis de datos. Exploraremos sus capacidades en el manejo efectivo de datos estructurados. +Esta lección se centra en Pandas, una poderosa biblioteca de Python para la manipulación y el análisis de datos. Exploraremos sus capacidades para manejar datos estructurados de manera efectiva. -Understanding Pandas Basics ---------------------------- -Pandas proporciona estructuras de datos como Series y DataFrame. Está construido sobre NumPy, lo que facilita trabajar con datos estructurados. +Entendiendo los Conceptos Básicos de Pandas +------------------------------------------- +Pandas proporciona estructuras de datos como Series y DataFrame. Está construido sobre NumPy, lo que facilita el trabajo con datos estructurados. .. code-block:: python - :caption: Importando Pandas y Cargando Datos Ficticios + :caption: Importando Pandas y Cargando Datos de Ejemplo import pandas as pd - # Datos ficticios + # Datos de ejemplo data = { - 'Nombre': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Nombre': ['Juan', 'Ana', 'Pedro', 'Linda', 'Jacobo'], 'Edad': [28, 23, 25, 24, 30], 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] } @@ -30,10 +35,10 @@ Pandas proporciona estructuras de datos como Series y DataFrame. Está construid Análisis Exploratorio de Datos (EDA) con Pandas ----------------------------------------------- -Verifica las dimensiones de los datos y examina su estructura: +Revisa las dimensiones de los datos y examina su estructura: .. code-block:: python - :caption: Verificando Dimensiones de los Datos e Información + :caption: Verificando las Dimensiones y la Información de los Datos # Forma del DataFrame print(df.shape) @@ -43,17 +48,14 @@ Verifica las dimensiones de los datos y examina su estructura: Limpieza y Transformación de Datos ---------------------------------- -Renombra columnas, maneja datos faltantes y convierte tipos de datos: +Renombra columnas: .. code-block:: python - :caption: Limpieza y Transformación de Datos + :caption: Limpiando y Transformando Datos - # Renombrando columnas + # Renombrar columnas df.rename(columns={'Nombre': 'Nombre Completo', 'Ciudad': 'Ubicación'}, inplace=True) - # Manejo de datos faltantes (no aplicable para estos datos ficticios) - - # Conversión de tipos de datos (no necesario para estos datos ficticios) Manipulación y Agregación de Datos ---------------------------------- @@ -70,8 +72,8 @@ Selecciona, filtra, agrupa y agrega datos: print(datos_filtrados) # Agrupando y agregando datos - estadisticas_grupo_edad = df.groupby('Edad').size() - print(estadisticas_grupo_edad) + estadisticas_edad = df.groupby('Edad').size() + print(estadisticas_edad) Visualización de Datos con Pandas y Matplotlib ---------------------------------------------- @@ -89,17 +91,15 @@ Utiliza Matplotlib para visualizaciones: plt.ylabel('Frecuencia') display(plt) -.. note:: - use `plt.show()` en lugar de `display(plt)` si lo recrea en su máquina local. - +.. note:: + Estamos usando PyScript para ejecutar NumPy y Matplotlib en el navegador. + Utiliza `plt.show()` en lugar de `display(plt)` para mostrar los gráficos si estás ejecutando el código localmente. Ejemplo Interactivo -------------------- -Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame por edad y visualizar los resultados: - -.. note:: +-------------------- +Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame según la edad y visualizar los resultados: -.. activecode:: ac_l66_2_1es +.. activecode:: ac_l66_2_1 :nocodelens: :language: python3 :python3_interpreter: pyscript @@ -107,9 +107,9 @@ Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame por edad y import pandas as pd import matplotlib.pyplot as plt - # Datos ficticios + # Datos de ejemplo data = { - 'Nombre': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Nombre': ['Juan', 'Ana', 'Pedro', 'Linda', 'Jacobo'], 'Edad': [28, 23, 25, 24, 30], 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] } @@ -120,13 +120,16 @@ Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame por edad y # Filtrar DataFrame por edad df_filtrado = df[df['Edad'] > 25] - # Graficar datos filtrados + # Graficando los datos filtrados df_filtrado.plot(kind='bar', x='Nombre', y='Edad', color='skyblue') - plt.title('Distribución de Edades para Individuos Mayores de 25 Años') + plt.title('Distribución de Edad para Individuos Mayores de 25 Años') plt.xlabel('Nombre') plt.ylabel('Edad') display(plt) +.. note:: + Asegúrate de ejecutar todos los bloques de código proporcionados para ver los resultados completos y comprender las funcionalidades demostradas. + Ejercicio --------- -Escribe código para calcular la edad promedio de las personas en el DataFrame. +Escribe un código para calcular la edad promedio de los individuos en el DataFrame. diff --git a/_sources/lectures/TWP66/TWP66_2_en.rst b/_sources/lectures/TWP66/TWP66_2_en.rst index b271992cf6..6e75da36c9 100644 --- a/_sources/lectures/TWP66/TWP66_2_en.rst +++ b/_sources/lectures/TWP66/TWP66_2_en.rst @@ -99,7 +99,7 @@ Interactive Example -------------------- Here's an interactive example where you can filter the DataFrame based on age and visualize the results: -.. activecode:: ac_l66_2_1 +.. activecode:: ac_l66_2_en_1 :nocodelens: :language: python3 :python3_interpreter: pyscript diff --git a/_sources/lectures/TWP66/TWP66_3.rst b/_sources/lectures/TWP66/TWP66_3.rst new file mode 100644 index 0000000000..76c8be0f62 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_3.rst @@ -0,0 +1,73 @@ +============================== +Operaciones Avanzadas de NumPy +============================== + +Introducción +------------ +En este ejercicio, utilizaremos Python para explorar el uso de las bibliotecas NumPy y Matplotlib. + +Ejemplo de Código +----------------- +Usaremos la biblioteca NumPy para definir el dominio y el rango de una función, y Matplotlib para graficar los resultados. + +**Definir el Dominio y Rango** + +.. code-block:: python + + import numpy as np + + # Definir el DOMINIO de una FUNCIÓN + N = 55 + X = np.linspace(-5, 5, N) # -5 límite inferior, 5 límite superior, N número de puntos a generar + # Mostrar los valores + print(X) + + # Calcular el RANGO de una FUNCIÓN + Y = np.sin(X) + # Mostrar los valores calculados + print(Y) + +**Graficar los Valores** + +.. code-block:: python + + from matplotlib import pyplot as plt + + # Graficar los valores de X e Y con círculos rojos + plt.plot(X, Y, 'ro') + plt.grid(True) + + # Graficar los valores de X e Y con líneas azules + plt.plot(X, Y, 'b-') + plt.grid(True) + + # Mostrar la gráfica + diplay(plt) + +.. note:: + utiliza `plt.show()` en lugar de `display(plt)` si estás recreando esto en una máquina local. + +**Editor de Código Interactivo** + +Para experimentar con el código de forma interactiva, utiliza los bloques de código interactivos proporcionados a continuación. Ejecuta todos los bloques de código para ver los resultados y explorar diferentes funcionalidades. + +.. activecode:: ac_l66_3_1 + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + import numpy as np + import matplotlib.pyplot as plt + + # Definir el dominio + N = 55 + X = np.linspace(-5, 5, N) + Y = np.sin(X) + + # Graficando los valores + plt.plot(X, Y, 'b-') + plt.grid(True) + display(plt) + +.. note:: + Asegúrate de ejecutar todos los bloques de código proporcionados para ver los resultados completos y comprender las funcionalidades demostradas. diff --git a/_sources/lectures/TWP66/TWP66_3_en.rst b/_sources/lectures/TWP66/TWP66_3_en.rst index 5f59b4c73c..760f0d44cd 100644 --- a/_sources/lectures/TWP66/TWP66_3_en.rst +++ b/_sources/lectures/TWP66/TWP66_3_en.rst @@ -46,12 +46,12 @@ We will use the NumPy library to define the domain and range of a function, and .. note:: use `plt.show()` instead of `display(plt)` if recreating on local machine. - + **Interactive Code Editor** To experiment with the code interactively, use the provided interactive code blocks below. Run all the code blocks to see the results and explore different functionalities. -.. activecode:: ac_l66_1a +.. activecode:: ac_l66_3_en_1 :nocodelens: :language: python3 :python3_interpreter: pyscript diff --git a/_sources/lectures/TWP66/TWP66_4.rst b/_sources/lectures/TWP66/TWP66_4.rst new file mode 100644 index 0000000000..d2e6c364a8 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_4.rst @@ -0,0 +1,89 @@ +================================================ +Explorando Más a Fondo las Bibliotecas de Python +================================================ + +Introducción +------------ +En esta sección, profundizaremos en el uso de las bibliotecas de Python, centrándonos específicamente en operaciones avanzadas con NumPy y visualizaciones utilizando Matplotlib. + +**Trabajando con Funciones** + +Comenzaremos definiendo el dominio de una función y calculando su rango correspondiente, seguido de la representación gráfica de estos valores. + +.. code-block:: python + + import numpy as np + + # Definir el DOMINIO de una FUNCIÓN + N = 35 + X = np.linspace(-5, 5, N) # -5 límite inferior, 5 límite superior, N número de puntos a generar + # Mostrar los valores + print(X) + + # Calcular el CO-DOMINIO de una FUNCIÓN + Y = np.sin(X) / X + # Mostrar los valores calculados + print(Y) + +**Graficando Funciones Complejas** + +Vamos a graficar los valores calculados y explorar técnicas de graficado más avanzadas. + +.. code-block:: python + + from matplotlib import pyplot as plt + + # Graficar los valores de X e Y con círculos rojos + plt.plot(X, Y, 'ro') + plt.grid(True) + + # Graficar los valores de X e Y con círculos cian + plt.plot(X, Y, 'co') + plt.grid(True) + + # Graficar los valores de X e Y con líneas azules + plt.plot(X, Y, 'b-') + plt.grid(True) + display(plt) + +**Explorando y Componiendo Funciones** + +También podemos explorar y componer funciones utilizando NumPy y Matplotlib. + +.. code-block:: python + + Z = (np.sin(X)) ** 2 + plt.plot(X, Z, '.-') + plt.grid(True) + display(plt) + +**Editor de Código Interactivo** + +Para experimentar con el código de forma interactiva, utiliza los bloques de código interactivos proporcionados a continuación. Ejecuta todos los bloques de código para ver los resultados y explorar diferentes funcionalidades. + +.. activecode:: ac_l66_4_1 + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + import numpy as np + import matplotlib.pyplot as plt + + # Definir el dominio + N = 35 + X = np.linspace(-5, 5, N) + Y = np.sin(X) / X + + # Graficando los valores + plt.plot(X, Y, 'b-') + plt.grid(True) + display(plt) + + # Explorando la composición de funciones + Z = (np.sin(X)) ** 2 + plt.plot(X, Z, '.-') + plt.grid(True) + display(plt) + +.. note:: + utiliza `plt.show()` en lugar de `display(plt)` si estás recreando esto en una máquina local. diff --git a/_sources/lectures/TWP66/TWP66_4_en.rst b/_sources/lectures/TWP66/TWP66_4_en.rst index 86e9ae98cc..e2862f75a7 100644 --- a/_sources/lectures/TWP66/TWP66_4_en.rst +++ b/_sources/lectures/TWP66/TWP66_4_en.rst @@ -61,7 +61,7 @@ We can also explore and compose functions using NumPy and Matplotlib. To experiment with the code interactively, use the provided interactive code blocks below. Run all the code blocks to see the results and explore different functionalities. -.. activecode:: ac_l66_2b +.. activecode:: ac_l66_4_en_1 :nocodelens: :language: python3 :python3_interpreter: pyscript diff --git a/_sources/lectures/TWP66/TWP66_5.rst b/_sources/lectures/TWP66/TWP66_5.rst new file mode 100644 index 0000000000..51f4756299 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_5.rst @@ -0,0 +1,136 @@ +================== +SymPy con Gráficas +================== + +Introducción +------------ +En este ejercicio, utilizaremos la biblioteca SymPy de Python para crear y visualizar expresiones matemáticas utilizando gráficos en 2D y 3D. + +Ejemplo de Código: Gráficas 2D +------------------------------ +Usaremos la biblioteca SymPy para definir expresiones simbólicas y visualizarlas utilizando gráficos en 2D. + +**Definir la Variable Simbólica** + +.. code-block:: python + + from sympy import Symbol + from sympy.plotting import plot + + # Definir la variable simbólica + x = Symbol('x') + + # Mostrar la variable simbólica + print(x) + +**Graficar las Expresiones** + +.. code-block:: python + + # Graficar la función cuadrática x^2 con un color personalizado + plot(x**2, line_color='fucsia') + + # Graficar la función cuadrática x^2 con un código de color diferente + plot(x**2, line_color='#e30052') + + # Graficar la función cuadrática x^2 con el color predeterminado + plot(x**2) + + # Graficar las funciones seno y coseno en un intervalo específico + plot(sin(x), cos(x), (x, -pi, pi)) + + # Graficar múltiples funciones con diferentes intervalos y un título personalizado + plot((sin(x), (x, -2*pi, 2*pi)), (cos(x), (x, -pi, pi)), + line_color='verde', title='Ejemplo de Gráfica con SymPy') + +.. note:: + Usa estas gráficas para explorar el comportamiento de las funciones dentro de intervalos específicos. + +Ejemplo de Código: Gráficas 3D +------------------------------ +También podemos crear gráficos de superficies 3D utilizando SymPy. + +**Gráfico de Superficie 3D** + +.. code-block:: python + + from sympy.plotting import plot3d + from sympy import Symbol + + # Definir variables simbólicas para gráficos 3D + x = Symbol('x') + y = Symbol('y') + + # Mostrar las variables simbólicas + print(x, y) + + # Graficar una superficie 3D para la expresión x * y + plot3d(x * y, (x, -10, 10), (y, -10, 10)) + + # Graficar múltiples superficies 3D + plot3d(x * y, x / y, (x, -5, 5), (y, -5, 5)) + + # Graficar superficies con expresiones más complejas + plot3d((x**2 + y**2, (x, -5, 5), (y, -5, 5)), + (x * y, (x, -3, 3), (y, -3, 3))) + +**Gráficas Paramétricas 3D** + +.. code-block:: python + + from sympy.plotting import plot3d_parametric_line + from sympy import cos, sin + + # Graficar una línea paramétrica 3D + plot3d_parametric_line(cos(x), sin(x), x, (x, -5, 5)) + + # Graficar una superficie paramétrica 3D + from sympy.plotting import plot3d_parametric_surface + u, v = symbols('u v') + plot3d_parametric_surface(cos(u + v), sin(u - v), u - v, + (u, -5, 5), (v, -5, 5)) + +**Gráficas Implícitas** + +.. code-block:: python + + from sympy import plot_implicit, Eq, And + from sympy import symbols + + # Definir las variables simbólicas + x, y = symbols('x y') + + # Graficar una ecuación implícita + p1 = plot_implicit(Eq(x**2 + y**2, 5), + (x, -5, 5), (y, -2, 2), + adaptive=False, points=400) + + # Graficar una región definida por una desigualdad + p2 = plot_implicit(y > x**2) + + # Graficar utilizando conjunciones booleanas + p3 = plot_implicit(And(y > x, y > -x)) + +.. note:: + Experimenta con estas gráficas para entender cómo SymPy maneja las matemáticas simbólicas y la visualización. + +Editor de Código Interactivo +---------------------------- +Para experimentar con el código de forma interactiva, utiliza los bloques de código interactivos proporcionados a continuación. Ejecuta todos los bloques de código para ver los resultados y explorar diferentes funcionalidades. + +.. activecode:: ac_l66_5_1 + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + from sympy import Symbol, sin, cos, pi + from sympy.plotting import plot + + # Definir la variable simbólica + x = Symbol('x') + + # Graficar las funciones seno y coseno + plot(sin(x), cos(x), (x, -pi, pi)) + +.. note:: + Asegúrate de ejecutar todos los bloques de código proporcionados para ver los resultados completos y comprender las funcionalidades demostradas. diff --git a/_sources/lectures/TWP66/TWP66_5_en.rst b/_sources/lectures/TWP66/TWP66_5_en.rst index e90abb3b86..ce38e1ec6c 100644 --- a/_sources/lectures/TWP66/TWP66_5_en.rst +++ b/_sources/lectures/TWP66/TWP66_5_en.rst @@ -1,144 +1,136 @@ -========================================== -Interactive Data Visualization with Python -========================================== +================= +SymPy with Graphs +================= -In this lesson, we will explore the use of Python libraries for creating interactive data visualizations. You will learn how to generate various types of plots, including line plots, bar charts, and pie charts. We will also cover how to interact with these plots dynamically. By the end of this lesson, you'll have a solid understanding of how to create and manipulate visual data representations in Python. +Introduction +------------ +In this exercise, we will use Python's SymPy library to create and visualize mathematical expressions using both 2D and 3D plots. -.. contents:: Table of Contents - :depth: 2 - :local: +Code Example: 2D Plots +----------------------- +We will use the SymPy library to define symbolic expressions and visualize them using 2D plots. -.. note:: - Ensure you have all the necessary Python libraries installed. This lesson assumes you are already familiar with NumPy and Matplotlib. - -Line Plots ----------- - -Let's start with a simple line plot to compare the average temperatures in Argentina between the years 1991 and 2020. +**Define the Symbolic Variable** .. code-block:: python - import matplotlib.pyplot as plt + from sympy import Symbol + from sympy.plotting import plot + + # Define the symbolic variable + x = Symbol('x') + + # Display the symbolic variable + print(x) - temp_1991 = [20.5, 20.0, 18.9, 14.8, 11.9, 8.2, 7.3, 8.9, 12.4, 13.8, 17.3, 18.6] - temp_2020 = [21.5, 20.1, 20.0, 14.9, 11.0, 8.3, 6.4, 9.7, 12.5, 15.5, 19.0, 20.3] +**Plot the Expressions** - plt.plot(temp_1991, linewidth=3, label='1991') - plt.plot(temp_2020, linestyle='dashed', linewidth=3, label='2020') - - plt.ylabel('Temperaturas') - plt.title('Comparativa de 1991 y 2020') - plt.xlabel('Mes') - plt.legend() - plt.grid(True) - display(plt) # Replace plt.show() if running locally +.. code-block:: python -.. note:: - Replace `display(plt)` with `plt.show()` if running the code locally. + # Plot the quadratic function x^2 with a custom color + plot(x**2, line_color='fuchsia') -Now, let's label the months on the x-axis: + # Plot the quadratic function x^2 with a different color code + plot(x**2, line_color='#e30052') -.. code-block:: python + # Plot the quadratic function x^2 with the default color + plot(x**2) - meses = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', - 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'] + # Plot the sine and cosine functions over a specific interval + plot(sin(x), cos(x), (x, -pi, pi)) - plt.plot(meses, temp_1991, linewidth=3, label='1991') - plt.plot(meses, temp_2020, linestyle='dashed', linewidth=3, label='2020') + # Plot multiple functions with different intervals and a custom title + plot((sin(x), (x, -2*pi, 2*pi)), (cos(x), (x, -pi, pi)), + line_color='green', title='Graph Example with SymPy') - plt.ylabel('Temperaturas') - plt.title('Comparativa de 1991 y 2020') - plt.xlabel('Mes') - plt.legend() - plt.grid(True) - display(plt) # Replace plt.show() if running locally +.. note:: + Use these plots to explore the behavior of functions within specified intervals. -Bar Charts ----------- +Code Example: 3D Plots +----------------------- +We can also create 3D surface plots using SymPy. -Let's compare the temperatures using a bar chart: +**3D Surface Plot** .. code-block:: python - import numpy as np + from sympy.plotting import plot3d + from sympy import Symbol - ancho = 0.35 - x = np.arange(len(temp_1991)) - fig, ax = plt.subplots() - rects1 = ax.bar(x - ancho/2, temp_1991, ancho, color='b', label='1991') - rects2 = ax.bar(x + ancho/2, temp_2020, ancho, color='g', label='2020') + # Define symbolic variables for 3D plotting + x = Symbol('x') + y = Symbol('y') - ax.set_ylabel('Temperaturas') - ax.set_title('Comparativa') - ax.set_xticks(x) - ax.set_xticklabels(meses) - ax.legend() + # Display the symbolic variables + print(x, y) - display(plt) # Replace plt.show() if running locally + # Plot a 3D surface for the expression x * y + plot3d(x * y, (x, -10, 10), (y, -10, 10)) -Pie Charts ----------- + # Plot multiple 3D surfaces + plot3d(x * y, x / y, (x, -5, 5), (y, -5, 5)) -Visualize the distribution of female students across different study areas in 2018 using a pie chart: + # Plot surfaces with more complex expressions + plot3d((x**2 + y**2, (x, -5, 5), (y, -5, 5)), + (x * y, (x, -3, 3), (y, -3, 3))) -.. code-block:: python +**3D Parametric Plots** - est_mujeres = [10512, 4774, 16232, 22904, 36700] - etiquetas = ['Ciencias Aplicadas', 'Ciencias Básicas', - 'Ciencias de la Salud', 'Ciencias Humanas', - 'Ciencias Sociales'] +.. code-block:: python - fig1, ax = plt.subplots() - ax.set_title('Estudiantes 2018 según área de estudio') - ax.axis('equal') - ax.pie(est_mujeres, labels=etiquetas, autopct='%1.2f%%') + from sympy.plotting import plot3d_parametric_line + from sympy import cos, sin - display(plt) # Replace plt.show() if running locally + # Plot a 3D parametric line + plot3d_parametric_line(cos(x), sin(x), x, (x, -5, 5)) -.. Interactive Widgets -.. -------------------- + # Plot a 3D parametric surface + from sympy.plotting import plot3d_parametric_surface + u, v = symbols('u v') + plot3d_parametric_surface(cos(u + v), sin(u - v), u - v, + (u, -5, 5), (v, -5, 5)) -.. Add interactivity to your plots using widgets. For example, dynamically change the degree of a polynomial: +**Implicit Plots** -.. .. code-block:: python +.. code-block:: python -.. import numpy as np -.. import matplotlib.pyplot as plt -.. import ipywidgets as widgets -.. from IPython.display import display + from sympy import plot_implicit, Eq, And + from sympy import symbols + + # Define the symbolic variables + x, y = symbols('x y') + + # Plot an implicit equation + p1 = plot_implicit(Eq(x**2 + y**2, 5), + (x, -5, 5), (y, -2, 2), + adaptive=False, points=400) -.. @widgets.interact(grado=(0, 9), N_puntos=(5, 35)) -.. def mi_plot(grado=3, N_puntos=5): -.. x = np.linspace(-10, 10, N_puntos) -.. y = x**grado -.. plt.figure(figsize=(12,8)) -.. plt.plot(x, y, 'ro-') -.. plt.grid(True) -.. display(plt) # Replace plt.show() if running locally + # Plot a region defined by an inequality + p2 = plot_implicit(y > x**2) -Exercise: Create Your Own Visualization ---------------------------------------- + # Plot using boolean conjunctions + p3 = plot_implicit(And(y > x, y > -x)) -**Task:** Create a bar chart that compares the average temperatures in Argentina across three different years: 1991, 2000, and 2020. +.. note:: + Experiment with these plots to understand how SymPy handles symbolic math and visualization. -**Hint:** You can use the data for 2000 as follows: +Interactive Code Editor +----------------------- +To experiment with the code interactively, use the provided interactive code blocks below. Run all the code blocks to see the results and explore different functionalities. -.. code-block:: python +.. activecode:: ac_l66_5_en_1 + :nocodelens: + :language: python3 + :python3_interpreter: pyscript - temp_2000 = [21.2, 19.4, 17.0, 14.5, 10.1, 8.1, 5.6, 8.9, 10.8, 14.9, 16.3, 19.6] + from sympy import Symbol, sin, cos, pi + from sympy.plotting import plot -Follow the steps from the previous examples to create and display your chart. + # Define the symbolic variable + x = Symbol('x') -Interactive Editor ------------------- + # Plotting the sine and cosine functions + plot(sin(x), cos(x), (x, -pi, pi)) .. note:: - Use this editor to run the codes, practice, and do exercises to see the results. - -.. activecode:: ac_l66_5_1a - :nocodelens: - :language: python3 - :python3_interpreter: pyscript - - # You can start practicing here by copying and pasting the code examples from above, - # or by writing your own code to explore different visualizations. \ No newline at end of file + Ensure you run all the code blocks provided to see the complete results and understand the functionalities demonstrated. diff --git a/_sources/lectures/TWP66/TWP66_6.rst b/_sources/lectures/TWP66/TWP66_6.rst new file mode 100644 index 0000000000..4f816b66d4 --- /dev/null +++ b/_sources/lectures/TWP66/TWP66_6.rst @@ -0,0 +1,154 @@ +============================================= +Visualización Interactiva de Datos con Python +============================================= + +En esta lección, exploraremos el uso de bibliotecas de Python para crear visualizaciones de datos interactivas. Aprenderás a generar varios tipos de gráficos, incluyendo gráficos de líneas, gráficos de barras y gráficos de pastel. También cubriremos cómo interactuar dinámicamente con estos gráficos. Al final de esta lección, tendrás un conocimiento sólido de cómo crear y manipular representaciones visuales de datos en Python. + +.. contents:: Tabla de Contenidos + :depth: 2 + :local: + +.. note:: + Asegúrate de tener instaladas todas las bibliotecas necesarias de Python. Esta lección asume que ya estás familiarizado con NumPy y Matplotlib. + +Gráficos de Líneas +------------------ + +Comencemos con un gráfico de líneas simple para comparar las temperaturas promedio en Argentina entre los años 1991 y 2020. + +.. code-block:: python + + import matplotlib.pyplot as plt + + temp_1991 = [20.5, 20.0, 18.9, 14.8, 11.9, 8.2, 7.3, 8.9, 12.4, 13.8, 17.3, 18.6] + temp_2020 = [21.5, 20.1, 20.0, 14.9, 11.0, 8.3, 6.4, 9.7, 12.5, 15.5, 19.0, 20.3] + + plt.plot(temp_1991, linewidth=3, label='1991') + plt.plot(temp_2020, linestyle='dashed', linewidth=3, label='2020') + + plt.ylabel('Temperaturas') + plt.title('Comparativa de 1991 y 2020') + plt.xlabel('Mes') + plt.legend() + plt.grid(True) + display(plt) # Reemplaza plt.show() si ejecutas el código localmente + +.. note:: + Reemplaza `display(plt)` con `plt.show()` si ejecutas el código localmente. + +Ahora, etiquetemos los meses en el eje x: + +.. code-block:: python + + meses = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', + 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'] + + plt.plot(meses, temp_1991, linewidth=3, label='1991') + plt.plot(meses, temp_2020, linestyle='dashed', linewidth=3, label='2020') + + plt.ylabel('Temperaturas') + plt.title('Comparativa de 1991 y 2020') + plt.xlabel('Mes') + plt.legend() + plt.grid(True) + display(plt) # Reemplaza plt.show() si ejecutas el código localmente + +Gráficos de Barras +------------------ + +Comparemos las temperaturas utilizando un gráfico de barras: + +.. code-block:: python + + import numpy as np + + ancho = 0.35 + x = np.arange(len(temp_1991)) + fig, ax = plt.subplots() + rects1 = ax.bar(x - ancho/2, temp_1991, ancho, color='b', label='1991') + rects2 = ax.bar(x + ancho/2, temp_2020, ancho, color='g', label='2020') + + ax.set_ylabel('Temperaturas') + ax.set_title('Comparativa') + ax.set_xticks(x) + ax.set_xticklabels(meses) + ax.legend() + + display(plt) # Reemplaza plt.show() si ejecutas el código localmente + +Gráficos de Pastel +------------------ + +Visualiza la distribución de estudiantes femeninas en diferentes áreas de estudio en 2018 utilizando un gráfico de pastel: + +.. code-block:: python + + est_mujeres = [10512, 4774, 16232, 22904, 36700] + etiquetas = ['Ciencias Aplicadas', 'Ciencias Básicas', + 'Ciencias de la Salud', 'Ciencias Humanas', + 'Ciencias Sociales'] + + fig1, ax = plt.subplots() + ax.set_title('Estudiantes 2018 según área de estudio') + ax.axis('equal') + ax.pie(est_mujeres, labels=etiquetas, autopct='%1.2f%%') + + display(plt) # Reemplaza plt.show() si ejecutas el código localmente + +Interacción con Widgets +----------------------- + +Intenta cambiar el grado de un polinomio: + +.. code-block:: python + + import numpy as np + import matplotlib.pyplot as plt + + def plot_function(degree=3, num_points=5): + # Generar valores de x + x = np.linspace(-10, 10, num_points) + # Calcular valores de y en función del grado del polinomio + y = x**degree + + # Crear una nueva figura con tamaño especificado + plt.figure(figsize=(12, 8)) + # Graficar los valores de x e y con círculos rojos y una línea + plt.plot(x, y, 'ro-') + # Agregar líneas de cuadrícula al gráfico + plt.grid(True) + # Mostrar el gráfico + display(plt) # Reemplaza plt.show() si ejecutas el código localmente + + # Ejemplo de uso + degree = 3 # Establecer el grado del polinomio + num_points = 5 # Establecer el número de puntos a graficar + plot_function(degree, num_points) + + +Ejercicio: Crea Tu Propia Visualización +--------------------------------------- + +**Tarea:** Crea un gráfico de barras que compare las temperaturas promedio en Argentina en tres años diferentes: 1991, 2000 y 2020. + +**Pista:** Puedes usar los datos para el año 2000 de la siguiente manera: + +.. code-block:: python + + temp_2000 = [21.2, 19.4, 17.0, 14.5, 10.1, 8.1, 5.6, 8.9, 10.8, 14.9, 16.3, 19.6] + +Sigue los pasos de los ejemplos anteriores para crear y mostrar tu gráfico. + +Editor Interactivo +------------------ + +.. note:: + Usa este editor para ejecutar los códigos, practicar y hacer los ejercicios para ver los resultados. + +.. activecode:: ac_l66_6_1 + :nocodelens: + :language: python3 + :python3_interpreter: pyscript + + # Puedes comenzar a practicar aquí copiando y pegando los ejemplos de código de arriba, + # o escribiendo tu propio código para explorar diferentes visualizaciones. diff --git a/_sources/lectures/TWP66/TWP66_6_en.rst b/_sources/lectures/TWP66/TWP66_6_en.rst index b3ff5bd2c8..d3fefa36a2 100644 --- a/_sources/lectures/TWP66/TWP66_6_en.rst +++ b/_sources/lectures/TWP66/TWP66_6_en.rst @@ -31,7 +31,10 @@ Let's start with a simple line plot to compare the average temperatures in Argen plt.xlabel('Mes') plt.legend() plt.grid(True) - display(plt) # Replace plt.show() + display(plt) # Replace plt.show() if running locally + +.. note:: + Replace `display(plt)` with `plt.show()` if running the code locally. Now, let's label the months on the x-axis: @@ -48,7 +51,7 @@ Now, let's label the months on the x-axis: plt.xlabel('Mes') plt.legend() plt.grid(True) - display(plt) # Replace plt.show() + display(plt) # Replace plt.show() if running locally Bar Charts ---------- @@ -71,7 +74,7 @@ Let's compare the temperatures using a bar chart: ax.set_xticklabels(meses) ax.legend() - display(plt) # Replace plt.show() + display(plt) # Replace plt.show() if running locally Pie Charts ---------- @@ -90,28 +93,38 @@ Visualize the distribution of female students across different study areas in 20 ax.axis('equal') ax.pie(est_mujeres, labels=etiquetas, autopct='%1.2f%%') - display(plt) # Replace plt.show() + display(plt) # Replace plt.show() if running locally -Interactive Widgets --------------------- +Interact with your Widgets +-------------------------- -Add interactivity to your plots using widgets. For example, dynamically change the degree of a polynomial: +Try changing the degree of a polynomial: .. code-block:: python - import numpy as np - import matplotlib.pyplot as plt - import ipywidgets as widgets - from IPython.display import display - - @widgets.interact(grado=(0, 9), N_puntos=(5, 35)) - def mi_plot(grado=3, N_puntos=5): - x = np.linspace(-10, 10, N_puntos) - y = x**grado - plt.figure(figsize=(12,8)) - plt.plot(x, y, 'ro-') - plt.grid(True) - display(plt) # Replace plt.show() + import numpy as np + import matplotlib.pyplot as plt + + def plot_function(degree=3, num_points=5): + # Generate x values + x = np.linspace(-10, 10, num_points) + # Compute y values based on the polynomial degree + y = x**degree + + # Create a new figure with specified size + plt.figure(figsize=(12, 8)) + # Plot the x and y values with red circles and a line + plt.plot(x, y, 'ro-') + # Add grid lines to the plot + plt.grid(True) + # Show the plot + display(plt) # Replace plt.show() if running locally + + # Example usage + degree = 3 # Set the degree of the polynomial + num_points = 5 # Set the number of points to plot + plot_function(degree, num_points) + Exercise: Create Your Own Visualization --------------------------------------- @@ -132,11 +145,10 @@ Interactive Editor .. note:: Use this editor to run the codes, practice, and do exercises to see the results. -.. activecode:: ac_l66_5_1a +.. activecode:: ac_l66_6_en_1 :nocodelens: :language: python3 :python3_interpreter: pyscript # You can start practicing here by copying and pasting the code examples from above, - # or by writing your own code to explore different visualizations. - + # or by writing your own code to explore different visualizations. \ No newline at end of file diff --git a/_sources/lectures/TWP66/toctree.rst b/_sources/lectures/TWP66/toctree.rst index cac22efbe0..dca7a478a8 100644 --- a/_sources/lectures/TWP66/toctree.rst +++ b/_sources/lectures/TWP66/toctree.rst @@ -16,4 +16,7 @@ Manipulación de Datos TWP66_1.rst TWP66_2.rst - TWP66_3_en.rst + TWP66_3.rst + TWP66_4.rst + TWP66_5.rst + TWP66_6.rst diff --git a/requirements.txt b/requirements.txt index 9b9937c296..c391e193e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -git+https://github.com/PyAr/RunestoneComponents.git@master#runestone +git+https://github.com/abadoni5/RunestoneComponents.git@sympy#runestone pytest==6.2.4 playwright==1.18.0 pytest-playwright==0.1.1 From 8f7df55e384d4982b31522fcdb07bc133acdd03d Mon Sep 17 00:00:00 2001 From: Aayush Badoni Date: Thu, 15 Aug 2024 16:09:19 +0530 Subject: [PATCH 4/6] adds sympy image conversion logic --- _sources/lectures/TWP66/TWP66_5.rst | 60 ++++++++++++++++++-------- _sources/lectures/TWP66/TWP66_5_en.rst | 38 +++++++++++++--- 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/_sources/lectures/TWP66/TWP66_5.rst b/_sources/lectures/TWP66/TWP66_5.rst index 51f4756299..3a5b20c640 100644 --- a/_sources/lectures/TWP66/TWP66_5.rst +++ b/_sources/lectures/TWP66/TWP66_5.rst @@ -4,7 +4,7 @@ SymPy con Gráficas Introducción ------------ -En este ejercicio, utilizaremos la biblioteca SymPy de Python para crear y visualizar expresiones matemáticas utilizando gráficos en 2D y 3D. +En este ejercicio, utilizaremos la biblioteca SymPy de Python para crear y visualizar expresiones matemáticas utilizando gráficos tanto en 2D como en 3D. Ejemplo de Código: Gráficas 2D ------------------------------ @@ -28,7 +28,7 @@ Usaremos la biblioteca SymPy para definir expresiones simbólicas y visualizarla .. code-block:: python # Graficar la función cuadrática x^2 con un color personalizado - plot(x**2, line_color='fucsia') + plot(x**2, line_color='fuchsia') # Graficar la función cuadrática x^2 con un código de color diferente plot(x**2, line_color='#e30052') @@ -36,28 +36,39 @@ Usaremos la biblioteca SymPy para definir expresiones simbólicas y visualizarla # Graficar la función cuadrática x^2 con el color predeterminado plot(x**2) - # Graficar las funciones seno y coseno en un intervalo específico + # Graficar las funciones seno y coseno sobre un intervalo específico plot(sin(x), cos(x), (x, -pi, pi)) # Graficar múltiples funciones con diferentes intervalos y un título personalizado plot((sin(x), (x, -2*pi, 2*pi)), (cos(x), (x, -pi, pi)), - line_color='verde', title='Ejemplo de Gráfica con SymPy') + line_color='green', title='Ejemplo de Gráfica con SymPy') .. note:: - Usa estas gráficas para explorar el comportamiento de las funciones dentro de intervalos específicos. + Utiliza estas gráficas para explorar el comportamiento de las funciones dentro de intervalos especificados. + +**Explicación: Convirtiendo Gráficas a PNG** + +En algunos casos, especialmente cuando se trabaja en un entorno web como este editor de código interactivo, necesitamos convertir las gráficas en imágenes (como PNG) para que se puedan mostrar. Esto se debe a que el editor puede no soportar la representación directa de las gráficas de SymPy en su formato nativo. Al convertir las gráficas en imágenes y codificarlas en base64, podemos incrustarlas en HTML para su visualización dentro del cuaderno o de una página web. + +Alternativamente, si estás trabajando localmente en tu propia máquina, puedes mostrar las gráficas directamente sin convertirlas en imágenes utilizando el método `show()` proporcionado por el módulo de gráficos de SymPy. Este método renderizará la gráfica en una nueva ventana o dentro de tu Jupyter Notebook si estás utilizando uno. + +.. code-block:: python + + # Graficar directamente la expresión sin conversión cuando se trabaja localmente + plot(sin(x), cos(x), (x, -pi, pi), show=True) Ejemplo de Código: Gráficas 3D ------------------------------ -También podemos crear gráficos de superficies 3D utilizando SymPy. +También podemos crear gráficos de superficies en 3D utilizando SymPy. -**Gráfico de Superficie 3D** +**Gráfica de Superficie 3D** .. code-block:: python from sympy.plotting import plot3d from sympy import Symbol - # Definir variables simbólicas para gráficos 3D + # Definir variables simbólicas para graficar en 3D x = Symbol('x') y = Symbol('y') @@ -115,22 +126,37 @@ También podemos crear gráficos de superficies 3D utilizando SymPy. Experimenta con estas gráficas para entender cómo SymPy maneja las matemáticas simbólicas y la visualización. Editor de Código Interactivo ----------------------------- -Para experimentar con el código de forma interactiva, utiliza los bloques de código interactivos proporcionados a continuación. Ejecuta todos los bloques de código para ver los resultados y explorar diferentes funcionalidades. +----------------------------- +Para experimentar con el código de forma interactiva, utiliza los bloques de código interactivo proporcionados a continuación. Ejecuta todos los bloques de código para ver los resultados y explorar diferentes funcionalidades. .. activecode:: ac_l66_5_1 :nocodelens: :language: python3 :python3_interpreter: pyscript - from sympy import Symbol, sin, cos, pi - from sympy.plotting import plot + from sympy import Symbol, sin, cos, pi + from sympy.plotting import plot + from io import BytesIO + import base64 + + x = Symbol('x') + p = plot(sin(x), cos(x), (x, -pi, pi), show=False) + + # Convertir la gráfica a PNG + buffer = BytesIO() + p.save(buffer) + buffer.seek(0) + img = buffer.getvalue() - # Definir la variable simbólica - x = Symbol('x') + # Codificar en base64 + img_base64 = base64.b64encode(img).decode('utf-8') - # Graficar las funciones seno y coseno - plot(sin(x), cos(x), (x, -pi, pi)) + # Crear la etiqueta HTML img + img_tag = f'' + # Mostrar utilizando la clase HTML de PyScript + from pyscript import HTML + display(HTML(img_tag)) + .. note:: - Asegúrate de ejecutar todos los bloques de código proporcionados para ver los resultados completos y comprender las funcionalidades demostradas. + Asegúrate de ejecutar todos los bloques de código proporcionados para ver los resultados completos y entender las funcionalidades demostradas. diff --git a/_sources/lectures/TWP66/TWP66_5_en.rst b/_sources/lectures/TWP66/TWP66_5_en.rst index ce38e1ec6c..4c195e9b19 100644 --- a/_sources/lectures/TWP66/TWP66_5_en.rst +++ b/_sources/lectures/TWP66/TWP66_5_en.rst @@ -46,6 +46,17 @@ We will use the SymPy library to define symbolic expressions and visualize them .. note:: Use these plots to explore the behavior of functions within specified intervals. +**Converting Plots to PNG** + +In some cases, especially when working in a web environment like this interactive code editor, we need to convert plots into images (such as PNG) for them to be displayed. This is because the editor may not support direct rendering of SymPy plots in their native format. By converting the plots into images and encoding them as base64, we can embed them into HTML for visualization within the notebook or a web page. + +Alternatively, if you're working locally on your own machine, you can directly display plots without converting them to images by using the `show()` method provided by SymPy's plotting module. This method will render the plot in a new window or within your Jupyter Notebook if you're using one. + +.. code-block:: python + + # Directly plot the expression without conversion when working locally + plot(sin(x), cos(x), (x, -pi, pi), show=True) + Code Example: 3D Plots ----------------------- We can also create 3D surface plots using SymPy. @@ -123,14 +134,29 @@ To experiment with the code interactively, use the provided interactive code blo :language: python3 :python3_interpreter: pyscript - from sympy import Symbol, sin, cos, pi - from sympy.plotting import plot + from sympy import Symbol, sin, cos, pi + from sympy.plotting import plot + from io import BytesIO + import base64 + + x = Symbol('x') + p = plot(sin(x), cos(x), (x, -pi, pi), show=False) + + # Convert plot to PNG + buffer = BytesIO() + p.save(buffer) + buffer.seek(0) + img = buffer.getvalue() + + # Encode to base64 + img_base64 = base64.b64encode(img).decode('utf-8') - # Define the symbolic variable - x = Symbol('x') + # Create HTML img tag + img_tag = f'' - # Plotting the sine and cosine functions - plot(sin(x), cos(x), (x, -pi, pi)) + # Display using PyScript's HTML class + from pyscript import HTML + display(HTML(img_tag)) .. note:: Ensure you run all the code blocks provided to see the complete results and understand the functionalities demonstrated. From 19da491d022d4d930698e285b890e47042239983 Mon Sep 17 00:00:00 2001 From: Aayush Badoni Date: Thu, 15 Aug 2024 19:03:33 +0530 Subject: [PATCH 5/6] adds sympy lessons --- _sources/lectures/TWP66/TWP66_2.rst | 55 ++++++++--------- _sources/lectures/TWP66/TWP66_2_en.rst | 7 ++- _sources/lectures/TWP66/TWP66_3.rst | 23 ++++---- _sources/lectures/TWP66/TWP66_3_en.rst | 7 ++- _sources/lectures/TWP66/TWP66_4.rst | 28 ++++----- _sources/lectures/TWP66/TWP66_4_en.rst | 9 +-- _sources/lectures/TWP66/TWP66_5.rst | 81 +++++++++++++------------- _sources/lectures/TWP66/TWP66_5_en.rst | 49 ++++++++-------- _sources/lectures/TWP66/TWP66_6.rst | 52 ++++++++--------- _sources/lectures/TWP66/TWP66_6_en.rst | 10 ++-- 10 files changed, 166 insertions(+), 155 deletions(-) diff --git a/_sources/lectures/TWP66/TWP66_2.rst b/_sources/lectures/TWP66/TWP66_2.rst index 2a5ed02b2a..00a505edfd 100644 --- a/_sources/lectures/TWP66/TWP66_2.rst +++ b/_sources/lectures/TWP66/TWP66_2.rst @@ -11,20 +11,20 @@ Introducción ------------ Esta lección se centra en Pandas, una poderosa biblioteca de Python para la manipulación y el análisis de datos. Exploraremos sus capacidades para manejar datos estructurados de manera efectiva. -Entendiendo los Conceptos Básicos de Pandas -------------------------------------------- +Comprendiendo los conceptos básicos de Pandas +--------------------------------------------- Pandas proporciona estructuras de datos como Series y DataFrame. Está construido sobre NumPy, lo que facilita el trabajo con datos estructurados. .. code-block:: python - :caption: Importando Pandas y Cargando Datos de Ejemplo + :caption: Importando Pandas y Cargando Datos Simulados import pandas as pd - # Datos de ejemplo + # Datos simulados data = { - 'Nombre': ['Juan', 'Ana', 'Pedro', 'Linda', 'Jacobo'], - 'Edad': [28, 23, 25, 24, 30], - 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] + 'Name': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Age': [28, 23, 25, 24, 30], + 'City': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] } # Creando un DataFrame @@ -35,10 +35,10 @@ Pandas proporciona estructuras de datos como Series y DataFrame. Está construid Análisis Exploratorio de Datos (EDA) con Pandas ----------------------------------------------- -Revisa las dimensiones de los datos y examina su estructura: +Verifica las dimensiones de los datos y examina su estructura: .. code-block:: python - :caption: Verificando las Dimensiones y la Información de los Datos + :caption: Verificando Dimensiones e Información de los Datos # Forma del DataFrame print(df.shape) @@ -48,13 +48,13 @@ Revisa las dimensiones de los datos y examina su estructura: Limpieza y Transformación de Datos ---------------------------------- -Renombra columnas: +Renombrar columnas: .. code-block:: python :caption: Limpiando y Transformando Datos # Renombrar columnas - df.rename(columns={'Nombre': 'Nombre Completo', 'Ciudad': 'Ubicación'}, inplace=True) + df.rename(columns={'Name': 'Nombre Completo', 'City': 'Ubicación'}, inplace=True) Manipulación y Agregación de Datos @@ -72,12 +72,12 @@ Selecciona, filtra, agrupa y agrega datos: print(datos_filtrados) # Agrupando y agregando datos - estadisticas_edad = df.groupby('Edad').size() - print(estadisticas_edad) + estadisticas_por_edad = df.groupby('Edad').size() + print(estadisticas_por_edad) Visualización de Datos con Pandas y Matplotlib ---------------------------------------------- -Utiliza Matplotlib para visualizaciones: +Utiliza Matplotlib para las visualizaciones: .. code-block:: python :caption: Visualización de Datos @@ -86,18 +86,18 @@ Utiliza Matplotlib para visualizaciones: # Ejemplo de gráfico df['Edad'].plot(kind='hist', bins=5) - plt.title('Distribución de Edades') + plt.title('Distribución de Edad') plt.xlabel('Edad') plt.ylabel('Frecuencia') - display(plt) + display(plt, "plot_area") # Reemplazar con plt.show() si se ejecuta localmente .. note:: - Estamos usando PyScript para ejecutar NumPy y Matplotlib en el navegador. - Utiliza `plt.show()` en lugar de `display(plt)` para mostrar los gráficos si estás ejecutando el código localmente. + Estamos utilizando PyScript para ejecutar NumPy y Matplotlib en el navegador. + Usa `plt.show()` en lugar de `display(plt, "plot_area")` para mostrar los gráficos si ejecutas el código localmente. Ejemplo Interactivo -------------------- -Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame según la edad y visualizar los resultados: +Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame en función de la edad y visualizar los resultados: .. activecode:: ac_l66_2_1 :nocodelens: @@ -107,11 +107,11 @@ Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame según la import pandas as pd import matplotlib.pyplot as plt - # Datos de ejemplo + # Datos simulados data = { - 'Nombre': ['Juan', 'Ana', 'Pedro', 'Linda', 'Jacobo'], - 'Edad': [28, 23, 25, 24, 30], - 'Ciudad': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] + 'Name': ['John', 'Anna', 'Peter', 'Linda', 'Jack'], + 'Age': [28, 23, 25, 24, 30], + 'City': ['Nueva York', 'París', 'Berlín', 'Londres', 'Tokio'] } # Crear DataFrame @@ -120,16 +120,17 @@ Aquí tienes un ejemplo interactivo donde puedes filtrar el DataFrame según la # Filtrar DataFrame por edad df_filtrado = df[df['Edad'] > 25] - # Graficando los datos filtrados + # Graficando datos filtrados df_filtrado.plot(kind='bar', x='Nombre', y='Edad', color='skyblue') - plt.title('Distribución de Edad para Individuos Mayores de 25 Años') + plt.title('Distribución de Edad para Personas Mayores de 25 Años') plt.xlabel('Nombre') plt.ylabel('Edad') - display(plt) + print("El gráfico se muestra abajo en el campo:") + display(plt, "plot_area") # Reemplazar con plt.show() si se ejecuta localmente .. note:: Asegúrate de ejecutar todos los bloques de código proporcionados para ver los resultados completos y comprender las funcionalidades demostradas. Ejercicio --------- -Escribe un código para calcular la edad promedio de los individuos en el DataFrame. +Escribe un código para calcular la edad promedio de las personas en el DataFrame. diff --git a/_sources/lectures/TWP66/TWP66_2_en.rst b/_sources/lectures/TWP66/TWP66_2_en.rst index 6e75da36c9..a0d67532fd 100644 --- a/_sources/lectures/TWP66/TWP66_2_en.rst +++ b/_sources/lectures/TWP66/TWP66_2_en.rst @@ -89,11 +89,11 @@ Utilize Matplotlib for visualizations: plt.title('Age Distribution') plt.xlabel('Age') plt.ylabel('Frequency') - display(plt) + display(plt, "plot_area") # Replace with plt.show() if running locally .. note:: We are using PyScript to run NumPy and Matplotlib in the browser. - Use `plt.show()` instead of `display(plt)` to show the plots if you are running code locally. + Use `plt.show()` instead of `display(plt, "plot_area")` to show the plots if you are running code locally. Interactive Example -------------------- @@ -125,7 +125,8 @@ Here's an interactive example where you can filter the DataFrame based on age an plt.title('Age Distribution for Individuals Older than 25') plt.xlabel('Name') plt.ylabel('Age') - display(plt) + print("The plot is displayed below in the field:") + display(plt, "plot_area") # Replace with plt.show() if running locally .. note:: Ensure you run all the code blocks provided to see the complete results and understand the functionalities demonstrated. diff --git a/_sources/lectures/TWP66/TWP66_3.rst b/_sources/lectures/TWP66/TWP66_3.rst index 76c8be0f62..a7a33831c6 100644 --- a/_sources/lectures/TWP66/TWP66_3.rst +++ b/_sources/lectures/TWP66/TWP66_3.rst @@ -1,6 +1,6 @@ -============================== -Operaciones Avanzadas de NumPy -============================== +=============================== +Operaciones Avanzadas con NumPy +=============================== Introducción ------------ @@ -10,7 +10,7 @@ Ejemplo de Código ----------------- Usaremos la biblioteca NumPy para definir el dominio y el rango de una función, y Matplotlib para graficar los resultados. -**Definir el Dominio y Rango** +**Definir el Dominio y el Rango** .. code-block:: python @@ -33,19 +33,19 @@ Usaremos la biblioteca NumPy para definir el dominio y el rango de una función, from matplotlib import pyplot as plt - # Graficar los valores de X e Y con círculos rojos + # Graficar los valores de X y Y con círculos rojos plt.plot(X, Y, 'ro') plt.grid(True) - # Graficar los valores de X e Y con líneas azules + # Graficar los valores de X y Y con líneas azules plt.plot(X, Y, 'b-') plt.grid(True) - # Mostrar la gráfica - diplay(plt) + # Mostrar el gráfico + display(plt, "plot_area") # Reemplazar con plt.show() si se ejecuta localmente .. note:: - utiliza `plt.show()` en lugar de `display(plt)` si estás recreando esto en una máquina local. + Usa `plt.show()` en lugar de `display(plt, "plot_area")` si lo recreas en una máquina local. **Editor de Código Interactivo** @@ -64,10 +64,11 @@ Para experimentar con el código de forma interactiva, utiliza los bloques de c X = np.linspace(-5, 5, N) Y = np.sin(X) - # Graficando los valores + # Graficar los valores plt.plot(X, Y, 'b-') plt.grid(True) - display(plt) + print("El gráfico se muestra abajo en el campo:") + display(plt, "plot_area") # Reemplazar con plt.show() si se ejecuta localmente .. note:: Asegúrate de ejecutar todos los bloques de código proporcionados para ver los resultados completos y comprender las funcionalidades demostradas. diff --git a/_sources/lectures/TWP66/TWP66_3_en.rst b/_sources/lectures/TWP66/TWP66_3_en.rst index 760f0d44cd..d3a3acd802 100644 --- a/_sources/lectures/TWP66/TWP66_3_en.rst +++ b/_sources/lectures/TWP66/TWP66_3_en.rst @@ -42,10 +42,10 @@ We will use the NumPy library to define the domain and range of a function, and plt.grid(True) # Display the plot - diplay(plt) + diplay(plt, "plot_area") # Replace with plt.show() if running locally .. note:: - use `plt.show()` instead of `display(plt)` if recreating on local machine. + use `plt.show()` instead of `display(plt, "plot_area")` if recreating on local machine. **Interactive Code Editor** @@ -67,7 +67,8 @@ To experiment with the code interactively, use the provided interactive code blo # Plotting the values plt.plot(X, Y, 'b-') plt.grid(True) - display(plt) + print("The plot is displayed below in the field:") + display(plt, "plot_area") # Replace with plt.show() if running locally .. note:: Ensure you run all the code blocks provided to see the complete results and understand the functionalities demonstrated. \ No newline at end of file diff --git a/_sources/lectures/TWP66/TWP66_4.rst b/_sources/lectures/TWP66/TWP66_4.rst index d2e6c364a8..535454a42e 100644 --- a/_sources/lectures/TWP66/TWP66_4.rst +++ b/_sources/lectures/TWP66/TWP66_4.rst @@ -1,10 +1,10 @@ -================================================ -Explorando Más a Fondo las Bibliotecas de Python -================================================ +==================================== +Explorando Más Bibliotecas de Python +==================================== Introducción ------------ -En esta sección, profundizaremos en el uso de las bibliotecas de Python, centrándonos específicamente en operaciones avanzadas con NumPy y visualizaciones utilizando Matplotlib. +En esta sección, profundizaremos en el uso de bibliotecas de Python, enfocándonos específicamente en operaciones avanzadas con NumPy y visualizaciones utilizando Matplotlib. **Trabajando con Funciones** @@ -27,24 +27,24 @@ Comenzaremos definiendo el dominio de una función y calculando su rango corresp **Graficando Funciones Complejas** -Vamos a graficar los valores calculados y explorar técnicas de graficado más avanzadas. +Vamos a graficar los valores calculados y explorar técnicas de representación gráfica más avanzadas. .. code-block:: python from matplotlib import pyplot as plt - # Graficar los valores de X e Y con círculos rojos + # Graficar los valores de X y Y con círculos rojos plt.plot(X, Y, 'ro') plt.grid(True) - # Graficar los valores de X e Y con círculos cian + # Graficar los valores de X y Y con círculos cian plt.plot(X, Y, 'co') plt.grid(True) - # Graficar los valores de X e Y con líneas azules + # Graficar los valores de X y Y con líneas azules plt.plot(X, Y, 'b-') plt.grid(True) - display(plt) + display(plt, "plot_area") # Reemplazar con plt.show() si se ejecuta localmente **Explorando y Componiendo Funciones** @@ -55,7 +55,7 @@ También podemos explorar y componer funciones utilizando NumPy y Matplotlib. Z = (np.sin(X)) ** 2 plt.plot(X, Z, '.-') plt.grid(True) - display(plt) + display(plt, "plot_area") # Reemplazar con plt.show() si se ejecuta localmente **Editor de Código Interactivo** @@ -74,7 +74,7 @@ Para experimentar con el código de forma interactiva, utiliza los bloques de c X = np.linspace(-5, 5, N) Y = np.sin(X) / X - # Graficando los valores + # Graficar los valores plt.plot(X, Y, 'b-') plt.grid(True) display(plt) @@ -83,7 +83,9 @@ Para experimentar con el código de forma interactiva, utiliza los bloques de c Z = (np.sin(X)) ** 2 plt.plot(X, Z, '.-') plt.grid(True) - display(plt) + print("El gráfico se muestra abajo en el campo:") + display(plt, "plot_area") # Reemplazar con plt.show() si se ejecuta localmente + .. note:: - utiliza `plt.show()` en lugar de `display(plt)` si estás recreando esto en una máquina local. + Usa `plt.show()` en lugar de `display(plt, "plot_area")` si lo recreas en una máquina local. diff --git a/_sources/lectures/TWP66/TWP66_4_en.rst b/_sources/lectures/TWP66/TWP66_4_en.rst index e2862f75a7..1b3469844a 100644 --- a/_sources/lectures/TWP66/TWP66_4_en.rst +++ b/_sources/lectures/TWP66/TWP66_4_en.rst @@ -44,7 +44,7 @@ Let's plot the calculated values and explore more advanced plotting techniques. # Plot the values of X and Y with blue lines plt.plot(X, Y, 'b-') plt.grid(True) - display(plt) + display(plt, "plot_area") # Replace with plt.show() if running locally **Exploring and Composing Functions** @@ -55,7 +55,7 @@ We can also explore and compose functions using NumPy and Matplotlib. Z = (np.sin(X)) ** 2 plt.plot(X, Z, '.-') plt.grid(True) - display(plt) + display(plt, "plot_area") # Replace with plt.show() if running locally **Interactive Code Editor** @@ -83,7 +83,8 @@ To experiment with the code interactively, use the provided interactive code blo Z = (np.sin(X)) ** 2 plt.plot(X, Z, '.-') plt.grid(True) - display(plt) + print("The plot is displayed below in the field:") + display(plt, "plot_area") # Replace with plt.show() if running locally .. note:: - use `plt.show()` instead of `display(plt)` if recreating on local machine. \ No newline at end of file + use `plt.show()` instead of `display(plt, "plot_area")` if recreating on local machine. \ No newline at end of file diff --git a/_sources/lectures/TWP66/TWP66_5.rst b/_sources/lectures/TWP66/TWP66_5.rst index 3a5b20c640..725fd3fcd9 100644 --- a/_sources/lectures/TWP66/TWP66_5.rst +++ b/_sources/lectures/TWP66/TWP66_5.rst @@ -4,11 +4,11 @@ SymPy con Gráficas Introducción ------------ -En este ejercicio, utilizaremos la biblioteca SymPy de Python para crear y visualizar expresiones matemáticas utilizando gráficos tanto en 2D como en 3D. +En este ejercicio, utilizaremos la biblioteca SymPy de Python para crear y visualizar expresiones matemáticas usando gráficos tanto en 2D como en 3D. -Ejemplo de Código: Gráficas 2D ------------------------------- -Usaremos la biblioteca SymPy para definir expresiones simbólicas y visualizarlas utilizando gráficos en 2D. +Ejemplo de Código: Gráficas en 2D +---------------------------------- +Usaremos la biblioteca SymPy para definir expresiones simbólicas y visualizarlas mediante gráficos en 2D. **Definir la Variable Simbólica** @@ -36,39 +36,39 @@ Usaremos la biblioteca SymPy para definir expresiones simbólicas y visualizarla # Graficar la función cuadrática x^2 con el color predeterminado plot(x**2) - # Graficar las funciones seno y coseno sobre un intervalo específico + # Graficar las funciones seno y coseno en un intervalo específico plot(sin(x), cos(x), (x, -pi, pi)) # Graficar múltiples funciones con diferentes intervalos y un título personalizado plot((sin(x), (x, -2*pi, 2*pi)), (cos(x), (x, -pi, pi)), - line_color='green', title='Ejemplo de Gráfica con SymPy') + line_color='green', title='Ejemplo de Gráfico con SymPy') .. note:: - Utiliza estas gráficas para explorar el comportamiento de las funciones dentro de intervalos especificados. + Utiliza estos gráficos para explorar el comportamiento de las funciones dentro de los intervalos especificados. -**Explicación: Convirtiendo Gráficas a PNG** +**Convertir Gráficas a PNG** -En algunos casos, especialmente cuando se trabaja en un entorno web como este editor de código interactivo, necesitamos convertir las gráficas en imágenes (como PNG) para que se puedan mostrar. Esto se debe a que el editor puede no soportar la representación directa de las gráficas de SymPy en su formato nativo. Al convertir las gráficas en imágenes y codificarlas en base64, podemos incrustarlas en HTML para su visualización dentro del cuaderno o de una página web. +En algunos casos, especialmente cuando se trabaja en un entorno web como este editor de código interactivo, necesitamos convertir los gráficos en imágenes (como PNG) para que se puedan mostrar. Esto se debe a que el editor puede no soportar la representación directa de gráficos SymPy en su formato nativo. Al convertir los gráficos en imágenes y codificarlos como base64, podemos incrustarlos en HTML para visualizarlos dentro del cuaderno o en una página web. -Alternativamente, si estás trabajando localmente en tu propia máquina, puedes mostrar las gráficas directamente sin convertirlas en imágenes utilizando el método `show()` proporcionado por el módulo de gráficos de SymPy. Este método renderizará la gráfica en una nueva ventana o dentro de tu Jupyter Notebook si estás utilizando uno. +Alternativamente, si estás trabajando localmente en tu propia máquina, puedes mostrar los gráficos directamente sin convertirlos en imágenes utilizando el método `show()` proporcionado por el módulo de gráficos de SymPy. Este método renderizará el gráfico en una nueva ventana o dentro de tu Jupyter Notebook si estás utilizando uno. .. code-block:: python - # Graficar directamente la expresión sin conversión cuando se trabaja localmente + # Graficar la expresión directamente sin conversión cuando se trabaja localmente plot(sin(x), cos(x), (x, -pi, pi), show=True) -Ejemplo de Código: Gráficas 3D ------------------------------- -También podemos crear gráficos de superficies en 3D utilizando SymPy. +Ejemplo de Código: Gráficas en 3D +---------------------------------- +También podemos crear gráficos de superficie en 3D utilizando SymPy. -**Gráfica de Superficie 3D** +**Gráfico de Superficie en 3D** .. code-block:: python from sympy.plotting import plot3d from sympy import Symbol - # Definir variables simbólicas para graficar en 3D + # Definir variables simbólicas para la representación 3D x = Symbol('x') y = Symbol('y') @@ -85,7 +85,7 @@ También podemos crear gráficos de superficies en 3D utilizando SymPy. plot3d((x**2 + y**2, (x, -5, 5), (y, -5, 5)), (x * y, (x, -3, 3), (y, -3, 3))) -**Gráficas Paramétricas 3D** +**Gráficas Paramétricas en 3D** .. code-block:: python @@ -119,44 +119,47 @@ También podemos crear gráficos de superficies en 3D utilizando SymPy. # Graficar una región definida por una desigualdad p2 = plot_implicit(y > x**2) - # Graficar utilizando conjunciones booleanas + # Graficar usando conjunciones booleanas p3 = plot_implicit(And(y > x, y > -x)) .. note:: - Experimenta con estas gráficas para entender cómo SymPy maneja las matemáticas simbólicas y la visualización. + Experimenta con estos gráficos para entender cómo SymPy maneja la matemática simbólica y la visualización. Editor de Código Interactivo ----------------------------- -Para experimentar con el código de forma interactiva, utiliza los bloques de código interactivo proporcionados a continuación. Ejecuta todos los bloques de código para ver los resultados y explorar diferentes funcionalidades. +Para experimentar con el código de forma interactiva, utiliza los bloques de código interactivos proporcionados a continuación. Ejecuta todos los bloques de código para ver los resultados y explorar diferentes funcionalidades. .. activecode:: ac_l66_5_1 :nocodelens: :language: python3 :python3_interpreter: pyscript - from sympy import Symbol, sin, cos, pi - from sympy.plotting import plot - from io import BytesIO - import base64 + from sympy import Symbol, sin, cos, pi + from sympy.plotting import plot + from io import BytesIO + import base64 - x = Symbol('x') - p = plot(sin(x), cos(x), (x, -pi, pi), show=False) + x = Symbol('x') + p = plot(sin(x), cos(x), (x, -pi, pi), show=False) - # Convertir la gráfica a PNG - buffer = BytesIO() - p.save(buffer) - buffer.seek(0) - img = buffer.getvalue() + # Puedes mostrar directamente el gráfico usando plot() cuando trabajas localmente - # Codificar en base64 - img_base64 = base64.b64encode(img).decode('utf-8') + # Convertir gráfico a PNG + buffer = BytesIO() + p.save(buffer) + buffer.seek(0) + img = buffer.getvalue() + + # Codificar a base64 + img_base64 = base64.b64encode(img).decode('utf-8') - # Crear la etiqueta HTML img - img_tag = f'' + # Crear etiqueta HTML de imagen + img_tag = f'' + + # Mostrar usando la clase HTML de PyScript + from pyscript import HTML + print("El gráfico se muestra abajo en el campo:") + display(plt, "plot_area") # Reemplazar con plt.show() si se ejecuta localmente - # Mostrar utilizando la clase HTML de PyScript - from pyscript import HTML - display(HTML(img_tag)) - .. note:: Asegúrate de ejecutar todos los bloques de código proporcionados para ver los resultados completos y entender las funcionalidades demostradas. diff --git a/_sources/lectures/TWP66/TWP66_5_en.rst b/_sources/lectures/TWP66/TWP66_5_en.rst index 4c195e9b19..98750747c9 100644 --- a/_sources/lectures/TWP66/TWP66_5_en.rst +++ b/_sources/lectures/TWP66/TWP66_5_en.rst @@ -134,29 +134,32 @@ To experiment with the code interactively, use the provided interactive code blo :language: python3 :python3_interpreter: pyscript - from sympy import Symbol, sin, cos, pi - from sympy.plotting import plot - from io import BytesIO - import base64 - - x = Symbol('x') - p = plot(sin(x), cos(x), (x, -pi, pi), show=False) - - # Convert plot to PNG - buffer = BytesIO() - p.save(buffer) - buffer.seek(0) - img = buffer.getvalue() - - # Encode to base64 - img_base64 = base64.b64encode(img).decode('utf-8') - - # Create HTML img tag - img_tag = f'' - - # Display using PyScript's HTML class - from pyscript import HTML - display(HTML(img_tag)) + from sympy import Symbol, sin, cos, pi + from sympy.plotting import plot + from io import BytesIO + import base64 + + x = Symbol('x') + p = plot(sin(x), cos(x), (x, -pi, pi), show=False) + + # You can directly display the plot using plot() when working locally + + # Convert plot to PNG + buffer = BytesIO() + p.save(buffer) + buffer.seek(0) + img = buffer.getvalue() + + # Encode to base64 + img_base64 = base64.b64encode(img).decode('utf-8') + + # Create HTML img tag + img_tag = f'' + + # Display using PyScript's HTML class + from pyscript import HTML + print("The plot is displayed below in the field:") + display(plt, "plot_area") # Replace with plt.show() if running locally .. note:: Ensure you run all the code blocks provided to see the complete results and understand the functionalities demonstrated. diff --git a/_sources/lectures/TWP66/TWP66_6.rst b/_sources/lectures/TWP66/TWP66_6.rst index 4f816b66d4..b774bace3b 100644 --- a/_sources/lectures/TWP66/TWP66_6.rst +++ b/_sources/lectures/TWP66/TWP66_6.rst @@ -1,20 +1,20 @@ ============================================= -Visualización Interactiva de Datos con Python +Visualización de Datos Interactiva con Python ============================================= -En esta lección, exploraremos el uso de bibliotecas de Python para crear visualizaciones de datos interactivas. Aprenderás a generar varios tipos de gráficos, incluyendo gráficos de líneas, gráficos de barras y gráficos de pastel. También cubriremos cómo interactuar dinámicamente con estos gráficos. Al final de esta lección, tendrás un conocimiento sólido de cómo crear y manipular representaciones visuales de datos en Python. +En esta lección, exploraremos el uso de bibliotecas de Python para crear visualizaciones de datos interactivas. Aprenderás a generar varios tipos de gráficos, incluidos gráficos de líneas, gráficos de barras y gráficos circulares. También cubriremos cómo interactuar con estos gráficos de manera dinámica. Al final de esta lección, tendrás una comprensión sólida de cómo crear y manipular representaciones visuales de datos en Python. .. contents:: Tabla de Contenidos :depth: 2 :local: .. note:: - Asegúrate de tener instaladas todas las bibliotecas necesarias de Python. Esta lección asume que ya estás familiarizado con NumPy y Matplotlib. + Asegúrate de tener instaladas todas las bibliotecas de Python necesarias. Esta lección asume que ya estás familiarizado con NumPy y Matplotlib. Gráficos de Líneas ------------------ -Comencemos con un gráfico de líneas simple para comparar las temperaturas promedio en Argentina entre los años 1991 y 2020. +Comencemos con un gráfico de líneas simple para comparar las temperaturas medias en Argentina entre los años 1991 y 2020. .. code-block:: python @@ -31,7 +31,7 @@ Comencemos con un gráfico de líneas simple para comparar las temperaturas prom plt.xlabel('Mes') plt.legend() plt.grid(True) - display(plt) # Reemplaza plt.show() si ejecutas el código localmente + display(plt, "plot_area") # Reemplaza con plt.show() si ejecutas localmente .. note:: Reemplaza `display(plt)` con `plt.show()` si ejecutas el código localmente. @@ -51,12 +51,12 @@ Ahora, etiquetemos los meses en el eje x: plt.xlabel('Mes') plt.legend() plt.grid(True) - display(plt) # Reemplaza plt.show() si ejecutas el código localmente + display(plt, "plot_area") # Reemplaza con plt.show() si ejecutas localmente Gráficos de Barras ------------------ -Comparemos las temperaturas utilizando un gráfico de barras: +Compararemos las temperaturas usando un gráfico de barras: .. code-block:: python @@ -74,12 +74,12 @@ Comparemos las temperaturas utilizando un gráfico de barras: ax.set_xticklabels(meses) ax.legend() - display(plt) # Reemplaza plt.show() si ejecutas el código localmente + display(plt, "plot_area") # Reemplaza con plt.show() si ejecutas localmente -Gráficos de Pastel ------------------- +Gráficos Circulares +------------------- -Visualiza la distribución de estudiantes femeninas en diferentes áreas de estudio en 2018 utilizando un gráfico de pastel: +Visualiza la distribución de estudiantes mujeres en diferentes áreas de estudio en 2018 usando un gráfico circular: .. code-block:: python @@ -93,12 +93,12 @@ Visualiza la distribución de estudiantes femeninas en diferentes áreas de estu ax.axis('equal') ax.pie(est_mujeres, labels=etiquetas, autopct='%1.2f%%') - display(plt) # Reemplaza plt.show() si ejecutas el código localmente + display(plt, "plot_area") # Reemplaza con plt.show() si ejecutas localmente -Interacción con Widgets ------------------------ +Interactúa con tus Widgets +--------------------------- -Intenta cambiar el grado de un polinomio: +Prueba cambiar el grado de un polinomio: .. code-block:: python @@ -108,7 +108,7 @@ Intenta cambiar el grado de un polinomio: def plot_function(degree=3, num_points=5): # Generar valores de x x = np.linspace(-10, 10, num_points) - # Calcular valores de y en función del grado del polinomio + # Calcular valores de y basados en el grado del polinomio y = x**degree # Crear una nueva figura con tamaño especificado @@ -118,18 +118,17 @@ Intenta cambiar el grado de un polinomio: # Agregar líneas de cuadrícula al gráfico plt.grid(True) # Mostrar el gráfico - display(plt) # Reemplaza plt.show() si ejecutas el código localmente + display(plt, "plot_area") # Reemplaza con plt.show() si ejecutas localmente - # Ejemplo de uso - degree = 3 # Establecer el grado del polinomio - num_points = 5 # Establecer el número de puntos a graficar + # Uso de ejemplo + degree = 3 # Establece el grado del polinomio + num_points = 5 # Establece el número de puntos a graficar plot_function(degree, num_points) - -Ejercicio: Crea Tu Propia Visualización +Ejercicio: Crea tu propia Visualización --------------------------------------- -**Tarea:** Crea un gráfico de barras que compare las temperaturas promedio en Argentina en tres años diferentes: 1991, 2000 y 2020. +**Tarea:** Crea un gráfico de barras que compare las temperaturas medias en Argentina a lo largo de tres años diferentes: 1991, 2000 y 2020. **Pista:** Puedes usar los datos para el año 2000 de la siguiente manera: @@ -143,12 +142,11 @@ Editor Interactivo ------------------ .. note:: - Usa este editor para ejecutar los códigos, practicar y hacer los ejercicios para ver los resultados. + Usa este editor para ejecutar los códigos, practicar y hacer ejercicios para ver los resultados. .. activecode:: ac_l66_6_1 - :nocodelens: :language: python3 :python3_interpreter: pyscript - # Puedes comenzar a practicar aquí copiando y pegando los ejemplos de código de arriba, - # o escribiendo tu propio código para explorar diferentes visualizaciones. + # Puedes comenzar a practicar aquí copiando y pegando los ejemplos de código anteriores, + # o escribiendo tu propio código para explorar diferentes visualizaciones. \ No newline at end of file diff --git a/_sources/lectures/TWP66/TWP66_6_en.rst b/_sources/lectures/TWP66/TWP66_6_en.rst index d3fefa36a2..1b1f303c93 100644 --- a/_sources/lectures/TWP66/TWP66_6_en.rst +++ b/_sources/lectures/TWP66/TWP66_6_en.rst @@ -31,7 +31,7 @@ Let's start with a simple line plot to compare the average temperatures in Argen plt.xlabel('Mes') plt.legend() plt.grid(True) - display(plt) # Replace plt.show() if running locally + display(plt, "plot_area") # Replace plt.show() if running locally .. note:: Replace `display(plt)` with `plt.show()` if running the code locally. @@ -51,7 +51,7 @@ Now, let's label the months on the x-axis: plt.xlabel('Mes') plt.legend() plt.grid(True) - display(plt) # Replace plt.show() if running locally + display(plt, "plot_area") # Replace plt.show() if running locally Bar Charts ---------- @@ -74,7 +74,7 @@ Let's compare the temperatures using a bar chart: ax.set_xticklabels(meses) ax.legend() - display(plt) # Replace plt.show() if running locally + display(plt, "plot_area") # Replace plt.show() if running locally Pie Charts ---------- @@ -93,7 +93,7 @@ Visualize the distribution of female students across different study areas in 20 ax.axis('equal') ax.pie(est_mujeres, labels=etiquetas, autopct='%1.2f%%') - display(plt) # Replace plt.show() if running locally + display(plt, "plot_area") # Replace plt.show() if running locally Interact with your Widgets -------------------------- @@ -118,7 +118,7 @@ Try changing the degree of a polynomial: # Add grid lines to the plot plt.grid(True) # Show the plot - display(plt) # Replace plt.show() if running locally + display(plt, "plot_area") # Replace plt.show() if running locally # Example usage degree = 3 # Set the degree of the polynomial From 180dc7daac7ee81f700feff037bde044d764819f Mon Sep 17 00:00:00 2001 From: Aayush Badoni Date: Thu, 15 Aug 2024 19:10:22 +0530 Subject: [PATCH 6/6] removes unwanted local file --- build_info | 1 - 1 file changed, 1 deletion(-) delete mode 100644 build_info diff --git a/build_info b/build_info deleted file mode 100644 index 1d0fe84223..0000000000 --- a/build_info +++ /dev/null @@ -1 +0,0 @@ -unknown-0-0