miércoles, 29 de agosto de 2018

VBA: Modificar Citas de Outlook desde Excel

Hoy veremos una variante de unos artículos publicados sobre Outlook y Excel (aquí y sobre todo aquí) que servirá para contestar la duda de un lector, que planteaba cuál sería la forma de modificar una cita de un calendario de Outlook desde Excel.

La idea del asunto es poder localizar una Cita concreta, en el ejemplo siguiente la buscaremos por dos criterios frecuentes:
1. por fechas
2. por el asunto
Para luego modificar alguna de sus propiedades... aprovechando la doble característica de lectura-escritura.


Así pues, insertaremos el siguiente procedimiento en un módulo estándar:

Sub ModificacionCitasdeOutlook()
'petición lector:
'solo necesitaria saber como puedo hacer para que sobre escriba si una cita es duplicada o modificada.

Dim olApp As Object, olNS As Object, olCalendario As Object
Dim Cita As Object
Dim fila As Long

'El rango de fecha de la Cita buscada... (si es que va a ser este el criterio!!).
Dim FechaIni As Date, FechaFin As Date
FechaIni = DateSerial(2018, 7, 10) + TimeSerial(10, 0, 0)  
FechaFin = DateSerial(2018, 7, 10) + TimeSerial(10, 30, 0) 

'Trabajamos sobre Outlook
Set olApp = CreateObject("Outlook.Application")
Set olNS = olApp.GetNamespace("MAPI")
'declaramos el objeto de la carpeta de los Calendarios
'(9 equivale a la carpeta del Calendario)
Set olCalendario = olNS.GetDefaultFolder(9)

'Ordenamos las Citas por Fecha de Inicio
Set misCitas = olCalendario.Items
misCitas.Sort "[Start]", False

'recorremos todas las citas del calendario
For Each Cita In misCitas
    'para cambiar/modificar por fecha o por Asunto
    'If Cita.Start >= FechaIni And Cita.Start <= FechaFin Then
    'si el asunto es...
     If Cita.Subject = "Borrar-Excelforo" Then
        'vemos en la ventana de inmediato el Asunto antes de la modificación
        Debug.Print Cita.Subject
        Cita.Subject = "Cambiado"   'realizamos el cambio por este nuevo asunto
        Cita.Save       'guardamos la cita
        'y volvemos a verificar en la ventana de inmediato como ha quedado
        Debug.Print Cita.Subject
    End If
Next Cita

MsgBox "Cita modificada..."

'liberamos memoria
Set Cita = Nothing
Set olCalendario = Nothing
Set olNS = Nothing
Set olApp = Nothing

End Sub

Listo. Puedes comprobar que si existe esa cita, el cambio se ha realizado correctamente....

jueves, 23 de agosto de 2018

VBA: Mover o Duplicar Autoformas

Trataremos hoy una manera de mover y/o duplicar autoformas desde una macro.

Para ello emplearemos las propiedades de las Autoformas:
.Top - controla la posición vertical de la forma, desde la parte superior de la hoja
.Left - controla la posición horizontal de la forma , desde el margen izquierdo de la hoja
.Rotation - el ángulo de giro
y
.Height - la altura del objeto
.Width - el ancho...

Y por otra parte el método .Duplicate si lo que queremos es copiar la autoforma de origen.

Lo primero que debemos hacer es añadir una autoforma a nuestra hoja.. por ejemplo, una estrella de siete puntas...
Tras ejecutar la macro de más abajo obtendremos:

VBA: Mover o Duplicar Autoformas



Insertaremos los siguientes procedimientos en un módulo estándar:

Sub MoverDuplicarForma()
Dim tamaño As Long
tamaño = 1
'controlamos, según la posición de la forma
'inicio y fin del bucle...
Dim a As Integer, b As Integer
If ActiveSheet.Shapes(1).Left <= 10 Then
    a = 1
    b = 360
    paso = 1
Else
    a = 360
    b = 1
    paso = -1
End If

'realizamos proceso...
'Selection.ShapeRange.Duplicate.Select
For i = a To b Step paso
    'si solo queremos moverla...
    'With ActiveSheet.Shapes(1)
    'o bien si queremos duplicarla y obtener el efecto...
    With ActiveSheet.Shapes(1).Duplicate
        'damos ángulo de rotación/giro
        .Rotation = i
        'damos situación a la forma alto e izquierda
        'desde la esquina superior izquierda punto (0,0)
        .Top = 50
        .Left = i
        'definimos su altura y ancho
        .Height = i
        .Width = i
        'damos color RGB a la forma si el ángulo es par
        If i Mod 2 = 0 Then
            rojo = Int((255 - 0 + 1) * Rnd + 0)
            verde = Int((255 - 0 + 1) * Rnd + 0)
            azul = Int((255 - 0 + 1) * Rnd + 0)
            .Fill.ForeColor.RGB = RGB(rojo, verde, azul)
        End If
    End With
    
    'damos un tiempo de ejecución
    'para que se haga visible el cambio
    TimeOut 0.01
Next i
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''
Sub TimeOut(duracion As Double)
Ini = Timer
Do
    DoEvents
Loop Until (Timer - Ini) >= duracion
End Sub



Otro punto interesante de este proceso es que al incorporarle la llamada al otro procedimiento 'TimeOut', que fuerza la ejecución de eventos, veremos como se realiza el copiado/duplicado de las autoformas...

Finalmente para eliminar los 360 objetos o autoformas podemos lanzar este otro procedimiento

''''''''''''''''''''''''''''''''''''''''''''''''''
Sub Borrar_Hoja()
Dim forma As Shape
'Para cada autoforma
For Each forma In ActiveSheet.Shapes
    ' Eliminamos forma
    forma.Delete
Next forma
End Sub



O bien manualmente selecciona una de las autoformas y presiona:
CTRL+MAYÚSCULA+BARRA ESPACIADORA
lo que provocará la selección de todas los objetos de la hoja... después simplemente presiona suprimir.

martes, 21 de agosto de 2018

Análisis de Regresión Lineal Múltiple-Excel

Estudiaremos hoy un herramienta interesante específica del Análisis de datos en Excel, y pensada para la estimación de resultados...

Supongamos tenemos una serie de datos histórica que refleja el 'Coste de mano de obra' de una empresa durante los últimos once meses, con datos del 'número de empleados' por mes, así como de 'horas reales trabajadas':

Análisis de Regresión Lineal Múltiple-Excel



El objetivo es estimar el dato Coste de mano de obra de diciembre-2018 sabiendo que tendremos 11 empleados contratados que trabajarán un número de 350 horas... y encontrar la ecuación de regresión lineal múltiple.

Coste mano de obra = constante + parámetro1*Num_empleados + parámetro2*Horas_Trabajadas


Para tal fin emplearemos una herramienta contenida en el 'pack' de Análisis de datos (ficha Datos > Análisis)
OJO!, requiere tener el complemento instalado!!.

Dentro de las herramientas de análisis buscaremos la Regresión

Análisis de Regresión Lineal Múltiple-Excel



Al abrir la herramienta nos pedirá completar algunos parámetros:
Sección Entrada
1-Rango Y de entrada: E2:E13 que corresponde al rango de celdas con el histórico de Coste de mano obra
2-Rango X de entrada: C2:D13 que corresponde con nuestras dos variables: empleados y horas trabajadas
3-Rótulos: marcado ya que en los rangos anteriores incluimos los encabezados
4-Nivel de confianza: sin marcar por que nos vale el nivel al 95% (o el alfa=0,05)
5-Constante igual a cero: sin marcar por que nos interesa una constante en nuestra futura ecuación

Sección Salida
1-Rango de salida: G1 será la celda superior izquierda del rango destino

No marcaremos ninguna otra opción para no recargar el análisis...

Análisis de Regresión Lineal Múltiple-Excel



Tras aceptar vemos los siguientes resultados...



De especial relevancia para el análisis e interpretación de nuestra regresión lineal múltiple son los datos marcados en las Estadísticas de la regresión, que paso a resumir:

Coeficiente de correlación múltiple:= 0,95804402
Coeficiente de determinación R^2:= 0,917848345
R^2 ajustado:= 0,897310431
Error típico:= 765,9173652

El cálculo mostrado para el coef de correlación múltiple (R) será la raíz cuadrada del Coeficiente de determinación R^2, y este último viene del cociente entre la 'suma de los cuadrados de la regresión' entre 'la suma de los cuadrados del total'...
Aunque para los casos de regresión lineal múltiple es conveniente fijarse en el R^2 ajustado, ya que este es la medida que define el porcentaje explicado por la varianza de la regresión en relación con la varianza de la variable explicada, esto es, lo mismo que el R^2, pero con una diferencia, y es que el R^2 ajustado tiene en cuenta el tamaño muestral y la inclusión de variables.

Este R^2 ajustado y el R^2 'normal' debe ser un valor entre 0 y 1.. cuanto más próximo a 1 mejor reflejaría una correlación.

Por otra parte es importante que el error típico sea lo más bajo posible.


Otras variables relevantes son dentro de la sección de ANOVA (Análisis de varianza):
F:= 44,69043718
Valor crítico de F:= 4,55476E-05

Este valor nos aporta la significación (si es o no relevante el análisis obtenido); siempre que el valor crítico sea inferior al alfa del estudio (en nuestro caso alfa=0,05 = 1-0,95)

En nuestro caso es netamente inferior a 0,05, con un valor crítico de casi cero; con lo que concluimos que a nivel global es significativo.


De la última sección del análisis nos quedaremos con los coeficientes de la ecuación de regresión:
Intercepción:= -2528,239987 -el valor de la constante de la ecuación buscada
Núm Empleados:= 1513,960316 -el parámetro para la primera variable
Horas Trabajadas:= 0,63819145 -el parámetro para la segunda variable

con esto construimos nuestra ecuación buscada:
Coste mano de obra = -2528,24 + 1513,96*Num_Empleados + 0,64*Horas_trabajadas

ecuación con la que podríamos estimar datos futuros...


Pero para certificar que nuestra ecuación es válida tenemos que fijarnos, al menos, en otro parámetro que nos aportará información sobre la significación local
Estadístico t
Intercepción:= -1,206087721
Núm Empleados:= 3,187709856
Horas Trabajadas:= 0,052624141

y de manera más relevante
Probabilidad
Intercepción:= 0,262239309
Núm Empleados:= 0,01284757 - valores inferiores a alfa (alfa=0,05) serán significativos (Significativa)
Horas Trabajadas:= 0,959321713 - valores inferiores a alfa (alfa=0,05) serán significativos (NO significativa)

En nuestro ejemplo solo la variable 'Num empleados' es significativa!!, así pues, esta lectura nos lleva a la conclusión que podríamos prescindir de ella en el análisis de nuestros datos...


Lanzaremos entonces de nuevo el proceso solo para la variable independiente 'Num empleados' obteniendo los siguientes resultados:

Análisis de Regresión Lineal Múltiple-Excel



Al hacer el mismo análisis sobre los datos relevantes obtenidos leemos que:

Datos marcados en las Estadísticas de la regresión, que paso a resumir:
Coeficiente de correlación múltiple:= 0,958029179
Coeficiente de determinación R^2:= 0,917819907
R^2 ajustado:= 0,908688786
Error típico:= 722,2387906

Dentro de la sección de ANOVA (Análisis de varianza):
F:= 100,5155735
Valor crítico de F:= 3,50246E-06

que indica la significación a nivel global del estudio.

Finalmente recuperamos los coeficientes de la ecuación de regresión:
Intercepción:= -2559,704918
Núm Empleados:= 1537,442623

con lo que nuestra ecuación buscada será:
Coste mano de obra = -2559.70 + 1537,44*Num_Empleados

y los valores que determinan la significación local:
Estadístico t
Intercepción:= -1,351072511
Núm Empleados:= 10,02574553


y de manera más relevante
Probabilidad
Intercepción:= 0,209655471
Núm Empleados:= 3,50246E-06 - valores inferiores a alfa (alfa=0,05) serán significativos

Que nos indica que en este caso, la variable 'Num empleados' sí es significativa.


En definitiva, tras analizar ambos análisis determinamos que el mejor es el segundo donde correlacionamos únicamente el coste de mano de obra con el número de empleados a través de la ecuación:
Coste mano de obra = -2559.70 + 1537,44*Num_Empleados

sabiendo que si es significativo a nivel global y local, que tiene un R^2 ajustado muy alto y un error típico muy bajo...


Podemos entonces estimar cuál será el coste de mano de obra en diciembre suponiendo empleemos a 11 trabajadores al 95%, en la celda E14:
=-2559,7+1537,44*C14

Análisis de Regresión Lineal Múltiple-Excel

jueves, 16 de agosto de 2018

VBA: Derivada de una función lineal de una variable en Excel

Veremos una manera de obtener la ecuación derivada a partir de una función linea de una sola variable...
Obviamente las restricciones son altas, y por ese motivo nos limitaremos a una sola variable.

El ejemplo se basa en el concepto de Newton de función derivada (leer más aquí)

En nuestro desarrollo veremos el ejemplo sobre la función:
f(x) = 2x2-1x

(que para los principiantes, su función derivada deberá ser f'(x)= 4x-1



Comenzaremos generando con programación nuestras funciones personalizadas.

Una de ellas ya se explicó en este blog (leer aquí).

La UDF 'FuncionesLineales' permite tratar una ecuación escrita como texto en una celda como una ecuación 'de verdad'... y es la base del cálculo diferencial que veremos a continuación.


La segunda de las UDF programadas (llamada 'Derivada') replica el límite o cociente de Newton:

límite cuando h tiende a cero de (f(a+h)-f(a))/ h


Insertaremos las siguientes funciones en un módulo estándar:

Function Derivada(ecuacion As String, punto As Double)
Dim h As Double
Dim fa As Double, fah As Double
h = 0.000000000001

'reoplicaremos el cálculo del límiete cuadno se tiende a cero
'nos aprovecharemos de nuestra UDF qeu convierte en funciones operables
'ecuaciones escritas en una celda
fa = FuncionesLineales(ecuacion, punto)
fah = FuncionesLineales(ecuacion, punto + h)

'y ua vea calculado los valores en los puntos 'a+h' y en 'a'
'devolvemos el dato a la función
Derivada = (fah - fa) / h

End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function FuncionesLineales(fx As String, valor_x As Double) As Double
'http://excelforo.blogspot.com/2018/05/vba-una-funcion-para-gobernarlas-todas.html

'aplicamos dos reemplazamientos
'1- para cambiar la variable por el valor concreto asignado
'2- tenemos en cuenta el cambio de configuración de los separadores decimales
'(recuerda que en el entorno del editor de VB el separador decimal es el punto, y no la coma!!)

func = Replace(Replace(fx, "x1", valor_x), ",", ".")

'retornamos el valor a la función creada
FuncionesLineales = Application.Evaluate(func)

End Function



Trabajemos con nuestras funciones.
En A12:A32 añadimos valores desde -5 a 5 en intervalos de 0,5.
En B12:B32 añadimos el valor de f(x), es decir, insertamos nuestra función:
=FuncionesLineales($B$9;$A12)

Y en C12:C32 el valor en cada punto de la derivada f'(x) insertando nuestra función UDF:
=Derivada($B$9;A12)

recuerda que en B9 tenemos escrita nuestra función f(x)=(2*x1^2)-1*x1


Con los valores de la función derivada para cada punto conseguidos y conocidos esos puntos (la x de nuestra equciación), podemos sabe y componer nuestra ecuación derivada, lo que haremos aplicando la función ESTIMACION.LINEAL

Así pues seleccionamos las celdas E13:F13 y escribimos:
=REDONDEAR(ESTIMACION.LINEAL(C12:C32;A12:A32;VERDADERO);2)

es decir, indicamos como argumento de 'conocidas_y' el rango con los valores de la derivada (C12:C32)
y como 'conocido_x' al de las equis (A12:A32)

Redondearemos el resultado para no arrastrar decimales innecesarios a la ecuación derivada..

Validamos matricialmente!!! (presionamos Ctrñ+Mayusc+Enter).

VBA: Derivada de una función lineal de una variable en Excel



Con ese resultado ya sabemos la pendiente y constante de nuestra recta derivada (f'(x) = m x + b)
Siendo 4 la pendiente y -1 la constante, y por tanto nuestra ecuación derivada buscada será:

f'(x)=4x-1

Lo que buscábamos...

Componiéndola con fórmulas en la celda F15 será:
=CONCATENAR(TEXTO(E13;"0,00");"x";SI(F13>0;"+"&TEXTO(F13;"0,00");SI(F13<0;TEXTO(F13;"0,00");"")))


Recuerda que este proceso no es extrapolable a todo tipo de funciones!!

martes, 14 de agosto de 2018

Ábaco Soroban en Excel

Construiremos hoy un ábaco japonés (llamado también Soroban). muy similar en funcionamiento al ábaco romano, siendo acaso este último algo más completo, puesto que incluía partes fraccionadas...

¿Qué necesitamos?
1- funciones sencillas del tipo condicional SI y una función SUMAPRODUCTO para verificar el correcto funcionamiento.
2- un formato condicional
3- controles de formulario (NO ActiveX), sin programación...

Ábaco Soroban en Excel



El primer paso es incorporar los controles de formulario de tipo 'control de número' en grupos de cinco en las celdas: B5:F5 y B9:F9

Estos controles los asociaremos a cada una de las celdas sobre las que se sitúa, esto es, el control en la celda B5 se vincula a B5:

Ábaco Soroban en Excel



Y así sucesivamente para los 10 controles.

Los controles de la fila superior B5:F5 deberán tener como propiedades:
Valor mínimo: 0
Valor máximo: 1


Mientras que los controles de las celdas B9:F9 deben ser:
Valor mínimo: 0
Valor máximo: 4


Los controles superiores representarán la parte de arriba del ábaco japones, que mostrarán los incrementos/decrementos de los múltiplos de 5 (5, 50, 500, 5000, 50000, etc)
Y los controles inferiores, la parte de abajo del ábaco, que muestra los aumentos/disminuciones de unidades, decenas, centenas, millares, etc...


Vamos a por la parte de funciones, así pues en el rango superior B6:F7 insertamos la fórmula:
=SI(B$5+1<=2-FILAS(B$6:B6);0;SI(B$5>2-FILAS(B$6:B6);B$4;""))

Con esta fórmula conseguimos que cuando pulsemos el control hacia arriba el valor de la cuenta correspondiente baje.
En este caso he optado por añadir formulación para que si no está pulsado la 'cuenta' aparezca como cero y solo si está pulsada la cuenta baje con el valor asignado.
Fíjate en el ejemplo siguiente donde se representa el número 5.050 y donde la cuenta de 5.000 y la de 50 están bajadas

Ábaco Soroban en Excel



De forma similar formulamos la parte inferior del ábaco en el rango B10:F14 incluyendo la fórmula:
=SI(B$9+1=FILAS(B$10:B10);B$8;""))

Ajustándose a lo que necesitamos, es decir, que cuando subimos la 'cuenta' aparezca el valor de ésta, y cuando está bajada muestre un cero.
En el ejemplo representamos el número 1.234

Ábaco Soroban en Excel



Para verificar la corrección del uso aplicamos en la celda I6 la fórmula:
=SUMAPRODUCTO(B4:F4;B5:F5)+SUMAPRODUCTO(B8:F8;B9:F9)

donde simplemente multiplicamos el valor representativo de las cuentas (B4:F4 y B8:F8) por el número de cuentas subidos o seleccionados en cada caso...


Terminada la formulación aplicaremos un formato condicional con fórmula, para ello seleccionaremos el rango B6:F7 y B10:F14
Nos aseguraremos que la celda activa sea B6 y añadiremos la fórmula:
=Y(B6<>"";B6>0)

con el formato deseado...

Ábaco Soroban en Excel



Listos para calcular con nuestro ábaco soroban.

Por ejemplo para mostrar el 13.131 subiríamos/bajaríamos las cuentas...

Ábaco Soroban en Excel

jueves, 9 de agosto de 2018

VBA: Color RGB y el Círculo Cromático en Excel

Llevaba tiempo queriendo escribir sobre este tema de los colores RGB en Excel, y no he encontrado mejor forma que haciéndolo sobre el Círculo Cromático de 12 colores (ni el más simple ni el más completo).
Si no te suena qué es esto, puedes leer algo más en Wikipedia


En este caso lo más importante es conocer la combinación RGB de esos doce colores...



Nuestra gama de colores está dividida en tres colores primarios:
amarillo = RGB 255-255-000
rojo = RGB 255-000-000
azul = RGB 000-000-255

Tres colores secundarios:
Naranja = rojo + amarillo= RGB 255-166-000
Violeta = rojo + azul = RGB 128-000-128
Verde = azul + amarillo = RGB 000-255-000

y seis terciarios:
Naranja amarillento = naranja + amarillo = RGB 255-198-000
Rojo anaranjado = rojo + naranja = RGB 255-090-004
Violeta rojizo = violeta + rojo = RGB 206-000-099
Azul violáceo = azul + violeta = RGB 132-008-255
Verde azulado = verde + azul = RGB 000-160-140
Amarilloso verdoso = verde + amarillo = RGB 222-255-000


Nuestro objetivo es construir un gráfico con los colores del tipo seleccionados en las celdas K1:K3.

Para ello añadimos tres 'casillas de verificación' vinculadas cada una de ellas a la celda que tiene debajo (en K1:K3).
A modo de ejemplo veamos la primera..

VBA: Color RGB y el Círculo Cromático en Excel



A partir del resultado obtenido en las celda vinculadas K1:K3 se rellenarán las fórmulas del campo 'Selección' en la tabla 'TblCromatica'.
La fórmula será un sencillo condicional para marcar rápidamente las filas con las que trabajar.
Para las filas de colores primarios añadimos:
=SI($K$1;"x";"")

Para las filas de colores secundarios:
=SI($K$2;"x";"")

Y para las filas de terciarios:
=SI($K$3;"x";"")

VBA: Color RGB y el Círculo Cromático en Excel



Estas 'equis' nos servirán posteriormente en la macro para saber qué colores trasladar al gráfico.

En el paso siguiente generamos un rango K10:N21 al que hemos asignado un nombre definido:
rngColores =colores!$K$10:$N$21

además en el rango O10:O21 hemos añadido la siguiente fórmula:
=SI(K10<>"";1/CONTARA($K$10:$K$21);"")

que permite asignar una parte igual en función de los colores trasladados o seleccionados en K1:K3.

VBA: Color RGB y el Círculo Cromático en Excel



Por otra parte sobre el rango discontinuo: K9:K21 + O9:O21 construimos un gráfico Circular con la leyenda a la derecha y sin título de gráfico, y al que he llamado 'chCirculoCromatico'.

Este gráfico es necesario que exista para el correcto funcionamiento de la macro siguiente...


Tenemos todo lo necesario:
1- controles del tipo 'casilla de verificación' (tres, uno por tipo: primario, secundario y terciario)
2- una tabla con la información de los colores y sus valores de color RGB (tabla 'TblCromatica')
3- un rango K9:O21 donde volcar datos desde la 'TblCromatica' y que
4- alimentará el gráfico circular llamado 'chCirculoCromatico'


Insertaremos el siguiente procedimiento en un módulo estándar, para luego asociar la macro a un botón:

Sub CirculoCromatico()
'limpiamos datos anteriores
Range("rngColores").ClearContents

Dim rng_R As Range, rng_G As Range, rng_B As Range
Set rng_R = Range("TblCromatica[Red]")
Set rng_G = Range("TblCromatica[Green]")
Set rng_B = Range("TblCromatica[Blue]")

Dim rng_Color As Range
Set rng_Color = Range("TblCromatica[Color]")

'TRasladamos nueva selección
Dim color As String
x = 0: y = 0
For Each celda In Range("TblCromatica[Selección]")
    y = y + 1
    'recuperamos valores de la TblCromática
    color = rng_Color.Item(y).Value
    rojo = rng_R.Item(y).Value
    verde = rng_G.Item(y).Value
    azul = rng_B.Item(y).Value
    'si el color está seleccionado
    If celda.Value = "x" Then
        'llevamos datos al área del gráfico
        '1.descripción del color
        Range("K10").Offset(0 + x, 0).Value = color
        '2. valor de rojo
        Range("K10").Offset(0 + x, 1).Value = rojo
        '3. valor de verde
        Range("K10").Offset(0 + x, 2).Value = verde
        '4. valor de azul
        Range("K10").Offset(0 + x, 3).Value = azul
        
        x = x + 1
        'y trasladamos el color al punto de la serie del gráfico
        'ajustamos el color de cada partición del gráfico
        'que YA está creado y se llama 'chCirculoCromatico'
        Set ChtObj = ActiveSheet.ChartObjects("chCirculoCromatico")
        With ChtObj
            Set ser = .Chart.SeriesCollection(1)
            'punto.Format.Fill.ForeColor.RGB = RGB(255, 0, 0)
            'llevamos el color al punto de la serie
            With ser.Points(x).Format.Fill
                .Visible = msoTrue
                .ForeColor.RGB = RGB(rojo, verde, azul)
                .Transparency = 0
                .Solid
            End With
        End With
    End If
Next celda

'liberamos memoria
Set rng_R = Nothing
Set rng_G = Nothing
Set rng_B = Nothing
Set rng_Color = Nothing
Set ser = Nothing

End Sub



Hemos finalizado. Podemos seleccionar en los controles la categoría de color a mostrar en nuestro círculo cromático...

Por ejemplo, solo primarios..

VBA: Color RGB y el Círculo Cromático en Excel



O Primarios y Secundarios..

VBA: Color RGB y el Círculo Cromático en Excel



O cualquier otra combinación posible...

martes, 7 de agosto de 2018

Los Divisores y los Números Perfectos en Excel

Hablaremos hoy de un tema curioso, de los Números perfectos.
Si leemos algo más sobre estos números en Wikipedia (aquí), comprenderemos rápidamente en qué consiste.

Un número perfecto es un número natural que es igual a la suma de sus divisores propios positivos. Dicho de otra forma, un número perfecto es aquel que es amigo de sí mismo.


Así pues la clave del asunto, para obtener o conocer si un número es perfecto, es poder recuperar un listado de los divisores de cualquier número natural...

Generamos una serie de enteros desde 2 hasta 500 en las celdas B2:B500, e insertaremos la función personalizada en VB que veremos a continuación en el rango continuo C2:C500...

Los Divisores y los Números Perfectos en Excel



Insertaremos la siguiente función personalizada en un módulo estándar:

Function DivisoresFx(x As Integer)
Application.Volatile

Dim i As Integer, acum As Long

acum = 0
'recorremos en descendente todos los números inferiores al Valor buscado
'por eso empezamos en x-1
For i = (x - 1) To 1 Step -1
    'comprobamos es divisible
    'esto es, es un divisor...
    If x Mod i = 0 Then
        'en ese caso acumulamos/sumamos a los divisores previos...
        acum = acum + i
        txt = i & "+" & txt
    End If
Next i

'devolvemos valor a lal función en la hoja de cálculo
If acum = x Then
    'si cumple la condición de número perfecto
    ' es un número natural que es igual a la suma de sus divisores propios positivos.
    DivisoresFx = "Número Perfecto" & "-" & Left(txt, Len(txt) - 1)
ElseIf acum = 1 Then
    'si cumple la condicío de primo
    'se divisible solo por si mismo y por uno
    DivisoresFx = "Primo"
Else
    'resto de números...
    DivisoresFx = "-"
End If

End Function



Lo que logramos con esta función es determinar, a partir de un número, cuáles son sus divisores... evaluando si además, la suma de estos divisores coincide con el valor origen (condición para que sea Número Perfecto)...
Para su fácil evaluación hemos incluido el listado de los divisores que corresponden a estos 'Números perfectos'
Si comprobamos los tres incluidos en el rango de 2 a 500:
6 Número Perfecto=1+2+3
28 Número Perfecto=1+2+4+7+14
496 Número Perfecto=1+2+4+8+16+31+62+124+248

verás que coinciden con el listado descubierto por Euclides.. el siguiente Número perfecto es 8128.. por si te interesa comprobarlo ;-)


Además, y como curiosidad añadida, si el único divisor de un número es 1, sabremos que éste es un número primo ver esta otra entrada del blog).


Son bastantes peculiares estos números y aún parecen tener bastantes cosas por demostrar...

jueves, 2 de agosto de 2018

VBA: 6174 La Constante de Kaprekar

Existen muchas curiosidades matemáticas y hoy veremos uno de ellos: La constante de Kaprekar, el 6174.

Básicamente este matemático indio (Dattatreya Ramachandra Kaprekar) demostró que con algunas condiciones y un orden concreto en unas operaciones, a partir de un número de cuatro dígitos, siempre se llega al número 6174.

Puedes leer algo más en nuestra amiga Wikipedia (aquí).

En resumen la operación a realizar consiste en seguir los siguientes pasos:
1- Escoger cualquier número de cuatro dígitos (OOJO!!, existen algunas limitaciones).
2- Ordenar los cuatro dígitos en orden ascendente, para obtener el minuendo de una resta.
3- Ordenar los mismos cuatro dígitos en orden descendente, para obtener el sustraendo de la misma resta.
4- Calcular la diferencia, restando el sustraendo del minuendo.
Si el resto no es igual a 6174, repetir los cuatro pasos anteriores, añadiendo ceros a la derecha al minuendo y a la izquierda al sustraendo, siempre que sea necesario para completar los cuatro dígitos.


Por ejemplo, si elegimos el 2784, manualmente el proceso sería:
8742 2478 =6264 (8742-2478)
6642 2466 =4176 (6642-2466)
7641 1467 =6174 (7641 - 1467)

VBA: 6174 La Constante de Kaprekar



En nuestro caso aplicaremos el ya conocido algoritmo de burbuja para ordenar los dígitos de cada número (ver aquí)...
Y para el proceso iterativo aplicaremos el bucle DO...LOOP UNTIL


Insertaremos el siguiente procedimiento en un módulo estándar:

Sub Kaprekar()
Dim numero As Long
inicio:
numero = Application.InputBox("Introduce un númerode cuatro dígitos", "Kaprecar en Excel")
'controlamos se cumplen las condiciones básicas:
'número de cuatro dígitos
If Len(numero) <> 4 Then
    GoTo inicio
ElseIf Not IsNumeric(numero) Then
    GoTo inicio
End If

'limpiamos el rango
Range("A1").CurrentRegion.ClearContents

'1. Escoger cualquier número de cuatro dígitos.
'2. Ordenar los cuatro dígitos en orden ascendente, para obtener el minuendo de una resta.
'3. Ordenar los mismos cuatro dígitos en orden descendente, para obtener el sustraendo de la misma resta.
'4. Calcular el resto, restando el sustraendo del minuendo.
'5. Si el resto no es igual a 6174, repetir los cuatro pasos anteriores, añadiendo ceros a la derecha al minuendo y a la izquierda al sustraendo, siempre que sea necesario para completar los cuatro dígitos.

fila = 0
diferencia = numero

'para controlar la inserción de valores numéricos NO válidos
On Error GoTo control
Do
    'obtenemos el valor ordenado en descendente
    ordDESC = OrdNumero(diferencia, "DESC")
    With Range("A1").Offset(fila, 0)
        .Value = ordDESC
        .NumberFormat = "0000"
    End With
    
    'obtenemos el valor ordenado en ascendente
    ordASC = OrdNumero(diferencia, "ASC")
    With Range("A1").Offset(fila, 1)
        .Value = ordASC
        .NumberFormat = "0000"
    End With
    
    'y su diferncia para hacerlo recursivo en pasos siguientes
    diferencia = ordDESC - ordASC
    With Range("A1").Offset(fila, 2)
        .Value = diferencia
        .Font.Bold = True
        .NumberFormat = "0000"
    End With
    
    fila = fila + 1
Loop Until diferencia = 6174 'contante de Kaprekar

Exit Sub

control:
If Err.Number > 0 Then MsgBox "Número no válido"
Exit Sub
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function OrdNumero(ByVal numero As Long, tipo As String) As String
Dim i As Long, j As Long

'definimos una Array de elementos a ordenar
Dim v(1 To 4) As Integer
For i = 1 To 4
    v(i) = Mid(numero, i, 1)
Next i

'procesamos el algoritmo de burbuja
For i = 1 To UBound(v)
    For j = i To UBound(v)
        If UCase(tipo) = "ASC" Then         'para ordenar en Ascendente
            If Val(v(j)) < Val(v(i)) Then
                t = v(i)
                v(i) = v(j)
                v(j) = t
            End If
        ElseIf UCase(tipo) = "DESC" Then    'y en descendente
            If Val(v(j)) > Val(v(i)) Then
                t = v(i)
                v(i) = v(j)
                v(j) = t
            End If
        Else    'para fallos u otros casos en Ascendente
            If Val(v(j)) < Val(v(i)) Then
                t = v(i)
                v(i) = v(j)
                v(j) = t
            End If
        End If
    Next j
Next i

'recomponemos el número ordenado
For x = 1 To 4
    rdo = rdo & v(x)
Next x

'y lo devolvemos a la función
OrdNumero = Val(rdo)

End Function

Listos, puedes probar con cualquier número de cuatro dígitos, a excepción de los números de cuatro dígitos iguales y algunos números de cuatro dígitos con tres números repetidos (si no se añadieran ceros a la derecha al minuendo y a la izquierda al sustraendo para completar los cuatro dígitos)...