domingo, enero 27, 2008

Operaciones con colores en Excel

En la nota Usando funciones XLM (Excel 4) en hojas de cálculo, mostraba cómo se podía obtener el número de color del fondo de una celda. Esto implicaba el uso de "macrofunciones" (funciones del lenguaje de macro XLM que existió hasta la versión 4) dentro de nombres. Esta técnica nos permitía realizar operaciones como sumar o contar, basándonos en los colores del fondo de un rango de celdas.
No tenía intenciones de volver sobre el tema, hasta que hace unos días un compañero de trabajo me manda un cuaderno Excel con una lista de cerca de 4.000 clientes de la empresa. La tabla estaba ordenada alfabéticamente y cada nombre de cliente tenía un color distinto de acuerdo a las condiciones de crédito (al contado: azul; 30 días: verde; 60 días: amarillo; etc.). Su tarea era sumar los saldos de los clientes por condiciones de crédito y calcular el promedio, para lo cual había que contar el número de clientes en cada grupo.
Después de señalarle que esa hoja era uno de los mejores ejemplos de lo que no se debe hacer en Excel (preferir la estética a la utilidad) intenté explicarle la técnica a usar con las macrofunciones. Como podrán imaginar mi compañero no estaba del mejor ánimo para explicaciones, después de haber invertido horas en poner fondos de color por tipo de crédito para descubrir al final que no puede hacer nada con la lista.
Decidí que lo mejor sería escribir unas UDF (funciones definidas por el usuario) que hagan la tarea.
Empezamos por una función que de cómo resultado el color del fondo de la celda:

Function extraer_color(miCelda As Range)
extraer_color = miCelda.Interior.ColorIndex
End Function


Aplicamos la fórmula a algunas celdas con fondo de color




La celda A6 no tiene ningún fondo y de ahí el resultado. Podemos cambiar el código de esta manera para que en caso de no haber fondo el resultado sea 0


Function extraer_color(miCelda As Range)
Select Case miCelda.Interior.ColorIndex
Case xlNone
extraer_color = 0
Case Else
extraer_color = miCelda.Interior.ColorIndex
End Select
End Function



Nuestra próxima función nos permitirá contar por color:


Function contar_por_color(RangoColor As Range, CeldaColor As Range)
Dim rngCelda As Range

For Each rngCelda In RangoColor
If rngCelda.Interior.ColorIndex = CeldaColor.Interior.ColorIndex Then
contar_por_color = contar_por_color + 1
End If
Next
End Function




La función tiene dos variables: RangoColor, que es el rango dónde queremos contar por color y CeldaColor, que es la celda que contiene el color del criterio.

Finalmente, una función para contar por color:

Function sumar_por_color(RangoColor As Range, CeldaColor As Range, RangoSumar As Range)
Dim rngCelda As Range
Dim colOffset As Long

colOffset = RangoSumar.Column - RangoColor.Column

For Each rngCelda In RangoColor
If rngCelda.Interior.ColorIndex = CeldaColor.Interior.ColorIndex Then
sumar_por_color = sumar_por_color + rngCelda.Offset(0, colOffset).Value
End If
Next
End Function



En esta función usamos un tercer argumento para el rango que contiene los valores a sumar. Los rangos RangoColor y RangoSumar deben tener la filas en común.
La variable colOffset calcula la distancia, en número de columnas, entre el rango con los valores y el rango con los fondos de color. Naturalmente, este número puede ser positivo, si los números están a la derecha de los colores, o negativo si lo están a la izquierda.

El cuaderno con las funciones puede descargarse aquí

Technorati Tags:

Programación de eventos en Excel – Segunda Nota

En la primera nota sobre programación de eventos en Excel vimos la importancia y el poder de esta herramienta. En esta nota daremos algunos ejemplos, poniendo el énfasis al aspecto práctico. Pero empecemos por señalar algunas características importantes de los eventos.
Existe una jerarquía de eventos:


  • Eventos de la aplicación (Application events)


  • Eventos del cuaderno (Workbook events)


  • Eventos de la hoja (Worksheets events)


  • En el tope de la jerarquía están los eventos de la aplicación, luego los del cuaderno y finalmente los de la hoja. Cada objeto contiene sus propios eventos y los de de los objetos que se encuentran por debajo de él en la jerarquía. Por ejemplo el cuaderno tiene un evento Worksheet_Change que responde a cada cambio en una celda de la hoja. El cuaderno, a su vez, tiene un evento Workbook_SheetChange que responde a un cambio en una celda de cualquiera de las hojas del cuaderno. Ante un cambio en una celda, los eventos de los tres niveles entran en acción.

    Ciertas acciones disparan más un evento, pero en cierto orden preestablecido. Por ejemplo, agregar una nueva hoja a un cuaderno (la acción) dispara una serie de eventos exactamente en este orden:

  • Workbook_SheetDeactivate

  • Workbook_SheetActivate

  • Workbook_NewSheet


  • Un tercer punto, y el más importante del punto de vista práctico, es cómo evitar generar "loops" infinitos al programar eventos. Por ejemplo, consideremos este código

    Private Sub Worksheet_Change(ByVal Target As Range)
    Target.Value = Target.Value + 1
    End Sub

    Ante un cambio en la hoja, el valor de la celda activa (Target) aumenta en 1. Esta acción en sí misma constituye un cambio, lo que produce un evento Change que vuelva a agregar 1 al valor de la celda. Y así sucesivamente hasta el infinito (o hasta que pulsemos Ctrl+Break).
    Si queremos ejecutar este código sin entrar en un "loop" infinito, debemos usar la propiedad EnableEvents de la Aplicación. En nuestro ejemplo:

    Private Sub Worksheet_Change(ByVal Target As Range)
    Application.EnableEvents = False
    Target.Value = Target.Value + 1
    Application.EnableEvents = True
    End Sub

    Primero llevamos el valor de la propiedad a False, ejecutamos la (o las) línea y volvemos a poner el valor de EnableEvents a True. Esto es importante, ya que el valor de la propiedad no vuelve al valor de defecto (True) una vez concluido el código.

    Ya hemos visto algunos ejemplos de eventos en la nota anterior y también en la nota sobre el numerador automático de facturas.

    Ejemplos de eventos de cuaderno (Workbook events):

    Seleccionar la celda A1 al activar una hoja

    Private Sub Workbook_SheetActivate(ByVal Sh As Object)
       [A1].Select
    End Sub

    Dado que usamos un evento a nivel de cuaderno, al seleccionar cualquier hoja, la celda A1 será la celda activa (excepto que seleccionemos una hoja de gráfico, en cuyo caso ocurrirá un error).

    Al agregar una nueva hoja al cuaderno, le fecha y hora aparecen en la celda A1

    Private Sub Workbook_NewSheet(ByVal Sh As Object)

    If TypeName(Sh) = "Worksheet" Then
       [A1] = "La hoja fue agregada el " & Now
    End If

    End Sub

    Ejemplos de eventos de hoja

    En la nota anterior mostramos un ejemplo de Worksheet_Change. Otro ejemplo interesante de este evento es el siguiente que pone un fondo de color a la fila y la columna de la celda activa

    Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Cells.Interior.ColorIndex = xlNone
     With Target
       .EntireRow.Interior.ColorIndex = 35
       .EntireColumn.Interior.ColorIndex = 35
     End With
    End Sub

    Otros ejemplos pueden encontrarse en notas anteriores en este blog, como Limitar el área de trabajo en Excel o en cómo crear un menú en Excel.



    Technorati Tags:

    sábado, enero 26, 2008

    Programación de Eventos en Excel - Primera Nota

    En mi nota sobre cómo crear un numerador automático para factura en Excel mostraba el uso de eventos en esta tarea. Ya en notas anteriores había mostrado o mencionado el uso de esta herramienta y también prometido que escribiría una nota sobre el tema. Aquí está la nota.

    Debemos distinguir entre eventos y programación de eventos. Evento es, como su nombre lo indica, algo que ocurre en Excel. Programar un evento significa que hemos escrito una rutina que será ejecutada cuando ocurra el evento.

    Excel monitorea constantemente lo que ocurre en la aplicación. Cuando existe un código asociado a un evento, este es disparado al darse las condiciones del evento.

    Por ejemplo, en la nota mencionada más arriba, hacíamos uso del evento BeforePrint. A este evento le habíamos asociado una macro que colocaba un número consecutivo cuando el usuario decidía imprimir la factura.
    En ese ejemplo el evento es iniciado por el usuario. Eventos pueden ser iniciados también por macros.

    Existen eventos para casi todos los objetos de Excel. Podemos clasificar los eventos de la siguiente manera:

    • Eventos del cuaderno (Workbook events): responden a acciones en un cuaderno en particular. Por ejemplo Workbook_Open, que ocurre cuando abrimos un cuaderno.


    • Eventos de las hojas (Worksheet events): responden a acciones en una hoja en particular. Por ejemplo Worksheet_Calculate, que ocurre cuando la hoja es recalculada.


    • Eventos de gráficos (Charts events): responden a acciones en un gráfico en particular.


    • Eventos de la aplicación (Application events): responden a acciones a nivel de la aplicación (es decir, Excel). Un ejemplo es WorkbookBeforeClose, que ocurre cuando iniciamos el proceso de cerrar un cuaderno.


    • Eventos de formularios/controles (Userform events): por ejemplo, el botón de la barra de formulario tiene un evento Button_Click.



    Existen distintas formas de investigar qué eventos existen para cada objeto. Por ejemplo, al poner un botón de la barra de formularios en una hoja de Excel se abre el diálogo Asignar macro




    Si apretamos Aceptar, Excel abrirá el editor de Vb con una rutina Botón2_AlHacerClic() sin líneas.



    Si escribimos esta macro



    cada vez que apretemos el botón ("al hacer clic"), el valor de la celda C1 se incrementa en 1.

    En este caso la macro está ubicada en un módulo corriente. Más adelante veremos que no siempre es así.

    Hay varias formas de investigar qué eventos existen para cada objeto. Por ejemplo, podemos usar el Examinador de Objetos (en el editor de Vb, apretar F2). En la ventana Clases elegimos el objeto que queremos investigar (Worksheet en nuestro caso) y en la ventana Miembros de Worksheet nos deslizamos hasta que vemos nombres con un rayo amarillo a la izquierda



    Esto nos permite ver los eventos disponibles para la hoja.

    Otra forma es seleccionar el objeto en la ventana Explorador de proyectos con un doble clic. Si hacemos esto con la Hoja1, se abre un módulo especial asociado con esta hoja. Abrimos la lista de la ventanilla donde aparece General



    y elegimos Worksheet. Excel pone automáticamente una Sub Worksheet_SelectionChange(ByVal Target As Range) sin líneas. Ahora podemos abrir la lista de la ventanilla de los eventos y elegir alguno de ellos



    Señalemos que los nombres y los parámetros de los eventos están predeterminados y no deben ser cambiados.

    Veamos ahora algunas técnicas útiles. Queremos que cada vez que el usuario abre un determinado cuaderno aparezca un mensaje que le recuerde realizar cierta tarea. Obviamente, este evento pertenece al libro (Workbook). En el editor de Vb, apretamos el icono ThisWorkbook y elegimos el evento Open. Escribimos una rutina como ésta



    Guardamos el cuaderno. Al abrirlo, veremos el mensaje



    Varios de los eventos de la hoja tienen una variable llamada Target. De acuerdo al evento, esta variable está definida como Rango, como en el evento Change


    Sub Worksheet_Change(ByVal Target As Range)

    o como enlace (Hyperlink)

    Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)

    e inclusive como tabla dinámica

    Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable).

    En el caso de rangos, Target se refiere a cualquier celda de la hoja. Por eso, cuando trabajamos con alguno de estos eventos, surge la necesidad de definir cuál es el rango relevante.
    Supongamos que en una hoja tenemos un rango llamado Ventas, B2:B13. Queremos que cada vez que el usuario ingrese las ventas de un mes, aparezca un mensaje que le muestre el total acumulado. Esto significa que el evento debe reaccionar cuando cambian los datos en el rango.
    En este caso usamos el evento Change, al que le asociamos este código

    Private Sub Worksheet_Change(ByVal Target As Range)
      Dim rngVentas As Range, vntTotal As Double

      Set rngVentas = Range("Ventas")
      vntTotal = WorksheetFunction.Sum("Ventas")

        If Union(Target, rngVentas).Address = rngVentas.Address Then
          MsgBox "Tottal acumulado de ventas " & vntTotal
        End If

    End Sub

    Cada vez que ingresamos un dato en el rango B2:B13, recibiremos un mensaje como este



    La clave en esta rutina es el uso de la función Union. Esta función evalúa si la dirección de Target (la celda activa donde introducimos el dato) coincide con alguna de las direcciones del rango Ventas. En caso afirmativo, se dispara el evento que calcula el total y muestra el mensaje.
    En la línea Set rngVentas = Range("B2:B13") es más conveniente usar la sintaxis Set rngVentas = Range("ventas"), usando el nombre definido "Ventas".

    En la próxima nota tocaremos otros aspectos de los eventos, como jerarquía de eventos, cómo evitar "loops" y agregaremos algunos ejemplos más.


    Technorati Tags:

    sábado, enero 19, 2008

    Distribuir datos en hojas Excel con macros.

    En la nota anterior sobre cómo distribuir datos de una hoja a otras hojas de un cuaderno Excel, vimos como hacerlo con fórmulas.

    En esa nota señalaba que el método con fórmulas es útil sólo si nuestro cuaderno contiene pocos datos. Uno de mis lectores intentó usar la solución con fórmulas pero, en sus porpias palabras "no he podido concluir mi base de datos porque la cantidad de data es mucha y con el peso de las formulas todas las maquinas se cuelgan".

    Este mismo lector me pedía que le enseñara la forma de hacerlo con macros. En esta nota mostraré una solución posible con macros al mismo caso que mostrábamos en la nota anterior.
    Debo aclarar que esta solución no es óptima desde el punto de vista de programación, sino que está orientada al usuario promedio cuyo objetivo es crear herramientas para el trabajo diario y no desarrollo de implementaciones en Excel.

    El ejemplo se basa en el mismo archivo de la nota anterior. El archivo con las macros puede descargarse ">distribuir_a_hojas_macroaquí.

    Empezamos por agregar el encabezamiento "Transferido".





    Esta columna nos servirá para chequear si la línea de la hoja Datos ha sido transferida o no.

    En esta solución usaremos dos macros. Una de tipo evento y otra que hará el trabajo de copiar los datos a la hoja correspondiente.
    La idea es que, una vez agregados los datos en la hoja "Datos", haciendo doble-clic en la celda correspondiente de la columna E, los datos sean transferidos a la hoja adecuada. Además queremos evitar que por error los datos sean transferidos más de una vez. Para eso usaremos el mecanismo de poner, automáticamente, la palabra "SI" en la columna Transferido, después de haber copiado los datos. Una vez que aparece la palabra SI en la columna E de la línea, la macro no permitirá volver a copiarlos.

    Para disparar la macro que copie los datos, usaremos el evento BeforeDoubleClick de la hoja "Datos". Empezamos por abrir el editor de Vba y haciendo doble-clic en el icono de la hoja Datos, abrimos el módulo de Vb para el evento



    En el módulo del evento ponemos este código


    Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

    Dim rngAnotar As Range, Resp, Fila

    Set rngAnotar = [E:E]

    If IsEmpty(Target) = False Then
    MsgBox "La línea ya fue transferida"
    Exit Sub
    End If

    If Union(Target, rngAnotar).Address = rngAnotar.Address Then
    Resp = MsgBox(prompt:="Transferir datos?", Buttons:=vbYesNo, _
    Title:="Transferir Datos")
    If Resp = vbNo Then
    Cancel = True
    Exit Sub
    End If
    Fila = Target.Row
    Call dist_hojas
    Target.Value = "SI"
    End If
    End Sub


    Después de declara las variables y definir el rango E, empezamos por comprobar si la línea a sido transferida en el pasado. Si la palabra SI aparece en la celda correspondiente de la línea que queremos copiar, aparece un mensaje informándonos que ya hemos transferido los datos y la macro se interrumpe.
    El resto del código produce un mensaje preguntándonos si queremos copiar los datos. Sólo si apretamos NO, la macro se interrumpe y no habrá ningún cambio en el cuaderno.



    Si aceptamos, los datos serán copiados y en la celda de la columna E aparecerá la palabra SI



    Si intentamos volver a copiar los datos de la línea, aparece este mensaje



    El trabajo de copiar a la hoja correspondiente lo hace esta macro, que ponemos en un módulo corriente (Módulo1)


    Sub dist_hojas()
    Dim LastRow As Long, Hoja As String
    Dim rngCopiar As Range

    Hoja = "Ruta " & ActiveCell.Offset(0, -1).Value 'definir nombre de hoja

    Set rngCopiar = Range(Cells(ActiveCell.Row, 1), Cells(ActiveCell.Row, 3))

    Application.ScreenUpdating = False

    With Sheets(Hoja)
    .Activate
    LastRow = WorksheetFunction.CountA([A:A]) + 1
    End With

    rngCopiar.Copy Sheets(Hoja).Cells(LastRow, 1)
    Sheets("Datos").Select

    Application.ScreenUpdating = True

    End Sub


    Después de definir las variable, la primer línea del código "arma" el nombre de la hoja uniendo a la palabra "Ruta" el número que aparece en la columna D, con el operador "&".
    La línea siguiente determina cuál es el rango a copiar en "Datos".
    El paso siguiente es determinar cuál es la primer fila libre en la hoja en la que vamos a pegar los datos.
    Una vez hecho esto, volvemos a "Datos", copiamos el rango adecuado y lo pegamos en la hoja correspondiente.

    En este modelo no hemos puesto ningún método automático para borrar lpineas que han sido copiadas y cancelar la señal SI en la hoja Datos. Esto se deberá hacer manualmente.




    Technorati Tags:

    jueves, enero 17, 2008

    Numerador automático para facturas o recibos en Excel

    Con Excel es fácil crear plantillas para facturas o recibos. Más aún, se pueden descargar gratuitamente de varios sitios. La plantilla del ejemplo que usaré en esta nota fue descargada del sitio de Microsoft.



    Actualización 25/08/2014: nuevo modelo mejorado

    Una de las consultas que recibo frecuentemente, es cómo crear un numerador automático para facturas o recibos en hojas de Excel. Si observan la plantilla de la factura, verán que la celda C5 contiene el número de factura.


    numerador de facturas

    Lo que queremos hacer es que este número se actualice cada vez que emitimos una factura, de manera que la siguiente tenga el número consecutivo (el archivo con el ejemplo se puede descargar aquí aunque recomiendo el nuevo modelo que incluye base de datos de las facturas producidas).

    Esto se puede hacer de varias maneras, pero todas implican usar macros.

    Una solución sencilla es agregar un botón al que le asociamos una macro. El botón lo creamos copiándolo de la barra de formularios.

    numerador de facturas

    Pulsamos el botón Nuevo, lo que abre un módulo de Vba con el evento Sub Botón3_AlHacerClic(). Aquí escribimos este código

    [C5] = [C5] + 1

    numerador de facturas

    Ahora, cuando apretamos el botón el valor en la celda C5 se incrementará en 1.

    Esta técnica es muy sencilla, pero no ofrece ninguna ventaja frente al sencillo método de cambiar el valor en la celda manualmente. Además, si nos olvidamos de presionar el botón, la próxima factura saldrá con el mismo número.

    Una forma de lograr algún tipo de control es ligar el botón a la acción de sumar los importes de la factura. Es decir, hasta que no apretemos el botón no aparecerá la suma total de la factura en la celda correspondiente (la celda C35 en nuestra plantilla).

    Empezamos por eliminar la fórmula en la celda C35. Teniendo en cuenta que el rango de los montos de las líneas de la factura es C18:C34, modificamos nuestro código, para que sume los valores de las celdas del rango y luego cambie el número de factura

    Sub Botón3_AlHacerClic()
    [C35] = WorksheetFunction.Sum(Range("C18:C34"))
    [C5] = [C5] + 1
    End Sub

    numerador de facturas

    Otra alternativa es que el número de factura cambie automáticamente en las circunstancias debidas, por ejemplo antes de imprimirla.

    Para esto debemos usar un tipo de macro especiales llamadas "eventos".
    Eventos son macros que actúan cuando, como su nombre lo sugiere, algo sucede en la hoja, o el objeto, al cual están ligadas. Los eventos serán tema de una futura nota, como vengo prometiendo. En esta nota nos limitaremos a un ejemplo práctico.

    Para saber qué eventos existen ligados al objeto, en nuestro caso el cuaderno que contiene la hoja con la factura, pasamos al editor de Vba y hacemos doble clic al icono ThisWorkbook,

    numerador de facturas

    Abrimos la lista desplegable de la ventanilla donde aparece General y elegimos Workbook

    numerador de facturas

    Abrimos la ventanilla contigua para ver qué eventos están a nuestra disposición

    numerador de facturas

    Como podemos ver, existe un evento BeforePrint, es decir "antes de imprimir". Ponemos el código anterior en este evento

    Private Sub Workbook_BeforePrint(Cancel As Boolean)

    [C35] = WorksheetFunction.Sum(Range("C18:C34"))

    [C5] = [C5] + 1

    End Sub

    Ahora, cuando queramos imprimir la factura, ya sea con el icono de impresión o con el menú Archivo-Imprimir, se disparará el evento, el número de la factura aumentara en 1 y el total será recalculado.
    Para mejorar nuestro evento, podemos incluir la posibilidad de cancelar la impresión. Lo que haremos es agregar algunas líneas de código


    Private Sub Workbook_BeforePrint(Cancel As Boolean)
        Dim Mensaje, Resp
        Dim dlgPrint As Boolean
        
        Mensaje = "El total es " & [C35] 'Total
        Mensaje = Mensaje & " Imprimir?"
        Resp = MsgBox(Mensaje, vbQuestion + vbYesNo)

        On Error GoTo errNoPrint

        If Resp = vbYes Then
        Application.EnableEvents = False
        [C5] = [C5] + 1
         dlgPrint = Application.Dialogs(xlDialogPrint).Show
            If dlgPrint = False Then
                [C5] = [C5] - 1
                Cancel = True
                Application.EnableEvents = True
                Exit Sub
            End If
        Else
            Cancel = True
            Application.EnableEvents = True
        End If

        Application.EnableEvents = True

        
        Exit Sub

    errNoPrint:
    [C5] = [C5] - 1
    Cancel = True
    Application.EnableEvents = True
    End Sub



    Primero calculamos el total; luego producimos un mensaje donde exponemos el total y damos la opción de cancelar la impresión

    numerador de facturas

    Si el usuario aprieta No, el proceso de impresión se detiene y el número de la factura no cambia.

    Como se puede ver, con algunas líneas de código puestas en el lugar correspondiente, podemos lograr una aplicación bastante práctica. El cuaderno con la factura puede descargarse aquí

    Si usamos el evento BeforePrint, el botón es innecesario y puede ser eliminado.



    Technorati Tags:

    jueves, enero 10, 2008

    Distribuir datos en hojas Excel sin macros.

    Supongamos esta situación: una empresa de transporte lleva el registro de los viajes un cuaderno Excel con varias hojas. En la primera se anotan los datos (fecha, destino, conductor y ruta). Por cada ruta hay una hoja. Nuestro objetivo es que al anotar los viajes en la primer hoja, éstos aparezcan automáticamente en la hoja correspondiente por ruta.

    Esta es la tabla que aparece en la primer hoja (que llamaremos "Datos")




    Queremos que cada línea aparezca en otra hoja. Los viajes de la ruta 1 en una hoja que se llamará "Ruta 1", los de la ruta 2 en "Ruta 2", etc.

    Hay dos formas más o menos inmediatas de resolver el problema: macros y tablas dinámicas. Con tablas dinámicas no estaríamos distribuyendo los datos, pero podríamos generar con facilidad listas por ruta.

    Pero el desafío es hacerlo con fórmulas. No es que esté aburrido y no tenga lo que hacer. Pero curiosamente he recibido varias veces esta consulta en las últimas semanas. A veces se trata de transporte por rutas, como en el ejemplo, a veces una escuela de fútbol que lleva un registro de alumnos por edad, a veces una tienda que quiere manejar el inventario por tipo de producto.

    Finalmente decidí aceptar el desafío, a pesar que la solución que propondré más adelante no es eficiente como el uso de tablas dinámicas o macros.

    El primer paso es crear tres hojas, una para cada ruta, donde pondremos las fórmulas que reflejaran los datos correspondientes de la hoja Datos. En estas hoja ponemos los mismos encabezamientos como en Datos, pero agregamos una columna, "Orden"



    En la celda A2 ponemos esta fórmula: =SI(Datos!$D2=1,Datos!A2,"")
    Esta fórmula trae el contenido de la celda A2 de Datos, si el valor de la columna D de Datos es 1, es decir, la ruta 1. En la Hoja Ruta 2 copiamos la misma fórmula, pero cambiamos el argumento Datos!$D2=1 por Datos!$D2=2.

    Copiamos la fórmula en las celdas B2 y C2 (prestar atención a los símbolos $ en las direcciones de la celda) y luego al rango A3:C11.
    Como se puede ver, los valores que aparecen en el rango son los de la ruta 1. Sino, aparece una celda en blanco.



    En la celda D2 ponemos esta fórmula, que ya explicamos en la nota sobre ordenar texto en Excel con fórmulas,

    =CONTAR.SI($A$2:$A$11,"<="&A2) y la copiamos al rango D3:D11.



    Como se puede apreciar, esta fórmula hace las veces de la función JERARQUIA para textos. Si bien las fechas son números, y por lo tanto podríamos usar JERARQUIA, el problema surge con las celdas en blanco. Por ese motivo usamos la fórmula señalada.


    Ahora creamos una segunda tablas en el rango F1:H11. En la primer fila copiamos los encabezamientos. En la celda F2 ponemos esta fórmula

    =INDICE($A$2:$E$11,COINCIDIR(FILA()-1,$D$2:$D$11,0),COINCIDIR(F$1,$A$1:$C$1,0))

    que copiamos al rango F2:H11



    En la nueva tabla, las líneas que pertenecen a la ruta aparecen ordenadas por fecha, y las que pertenecen a otras rutas aparecen como #N/A. Para mejorar la apariencia de la lista podemos aplicar Formato Condicional



    dándole color blanco a la fuente de la celda que cumple la condición, para hacer "desaparecer" el resulta #N/A. También hemos ocultado las columnas A:E.

    ¿Cómo funciona la fórmula con al función INDICE? Esta función da como resultado el valor de una matriz que se encuentra en la celda determinada por el valor del segundo argumento (fila) y del tercer argumento (columna). La matriz es el rango A2:E11, que contiene también la columna Orden.
    La fila es determinada por la función COINCIDIR(FILA()-1,$D$2:$D$11,0), que encuentra en que lugar del rango D2:D11 se encuentra la fila con el número de orden 1, 2 etc. El número de orden es determinado por el número de fila de la celda que contiene la fórmula, menos 1. Así, en la fila 2 aparecerán los datos que tienen el número de orden 1, en la fila tres los que tienen el número de orden 2, y así sucesivamente.
    La segunda función COINCIDIR, hace que los datos en la celda correspondan a la columna indicada.

    Como verán, hemos encontrado una solución con fórmulas al problema. Pero esta solución tienen dos problemas importantes, si queremos trabajar con gran cantidad de datos:
    - la función FILA(), es volátil y causa que cada cambio en la hoja provoque un recálculo de toda lo hoja;
    - INDICE y COINCIDIR tienden a ser lentas cuando trabajamos con gran cantidad de datos.

    El archivo se puede descargar distribuir a hojasaquí




    Technorati Tags:

    domingo, enero 06, 2008

    Cálculos con pies (feet) y pulgadas (inches) en Excel.

    Hace unos días me consultaba un lector sobre cómo hacer cálculos en pies (feet) y pulgadas (inches) con Excel.
    Debo confesar que nunca me había planteado esta pregunta. Dado que despertó mi curiosidad, en definitiva en los Estados Unidos siguen usando estas medidas, empecé por informarme un poco sobre el tema.
    Como casi siempre en estos casos, empezamos por Wikipedia. Así nos enteramos que 1 pie (foot) equivale a 12 pulgadas (inches), la que se suele escribir: 1' = 12". Las fracciones de pulgada más comunes son: 1/2", 1/4", 1/8", 1/16", 1/32" y 1/64". Ciertas fracciones comunes son expresadas en su forma reducida, por ejemplo 6/32" es presentada como 3/16".
    Según la nota de Wikipedia, las equivalencias también se presentan en forma decimal. 1/2" = .5, 1/4"=.25, 1/8"=.125, 1/16"=.0625, 1/32"=.03125 y 1/64"=.015625; de ahí, el resto de las fracciones, por ejemplo: 3/8"=.375 ó 63/64"=.984375.

    Volviendo a la consulta de mi lector, se trataba de sumar 3'-4 1/2"+ 2'-2 5/8. La primera dificultad para los que crecimos y vivimos en un mundo métrico, es entender la notación. El primer número en la suma es, en letras, tres pies y cuatro y media pulgadas; el segundo es dos pies con dos cinco y ochoavos pulgadas.

    Tras una breve búsqueda en la Internet, llegué al sitio de John Lacher quien ofrece descargar una función UDF para convertir pies y pulgadas a medidas métricas.

    Otra alternativa es usar funciones nativas de Excel y columnas auxiliares, como mostraremos en esta nota.

    Para resolver el problema empezaremos por reducir todo a pulgadas, el mínimo común denominador. En el primer número 3 pies equivalen a 36 pulgadas; así que todo el número expresado en pulgadas es 40.5. El segundo equivales a 26.65 pulgadas (2*12 + 2 + 5/8 = 24+2+0.625).

    Como vemos, la conversión no es problemática. El problema es cómo indicarle a que Excel cuál es la parte del número expresado en pies y cuál en pulgadas.

    Para esta tarea tendremos que recurrir a funciones texto. Empezamos por construir una plantilla




    En la celda B2 ponemos esta fórmula =IZQUIERDA(A2;ENCONTRAR("'";A2)-1) y la copiamos en la celda B3. El resultado es un texto. Para poder aplicar más adelante operaciones matemáticas los convertimos en número usado la función VALOR



    Para extraer la parte de pulgadas usamos la función EXTRAE combinada con la función LARGO:

    =VALOR(EXTRAE(A2;ENCONTRAR("-";A2)+1;LARGO(A2)-ENCONTRAR("-";A2)-1))



    Finalmente, para calcular el total de pulgadas usamos en D2 la fórmula =B2*12+C2 y la copiamos a D3. Calculamos los totales para cada columna



    Todo lo que nos queda es reducir el resultado 67,125 pulgadas a su expresión en pies y pulgadas. Para esto usamos las funciones ENTERO y RESIDUO y TEXTO. En la celda D5 ponemos la fórmula

    =ENTERO(D4/12)&" - "&TEXTO(RESIDUO(D4;12);"# ??/??")

    Usamos la función texto, ya que tenemos que unir el resultado de la función ENTERO, que es numérico, con la parte fraccional que es texto.



    A quien tenga que hacer frecuentemente cálculos con pies y pulgadas, le convendrá sin dudas descargar alguna función de la Internet, como la que ofrece Lacher.

    Technorati Tags:

    miércoles, enero 02, 2008

    JLD en Castellano – Balance del segundo año

    Hace un año atrás, hacía el balance del primer año de este blog. Ahora ha llegado el momento de presentarles el balance del segundo año.
    Durante el 2007 he estado utilizando los servicios (gratuitos) de StatCounter. La ventaja de este servicio es que permite extraer datos históricos con facilidad. Sencillamente se introducen las fechas de inicio y fin del período y el sitio genera una tabla con las estadísticas diarias. El sitio también nos permite descargar la tabla a un archivo en formato Excel o csv.
    Esto que parece tan trivial, se convierte en un verdadero ejercicio de manipulación de datos, cuando nuestro sistema está instalado "en castellano". En una próxima nota estaré describiendo las técnicas que tuve que utilizar con los datos de StatCounter para poder generar la información y los gráficos que muestro aquí.

    Durante el 2007 han visitado mi este blog 222.328 lectores, de los cuales 171.176 lo hacían por primera vez (First Time Visitors - 77%) y 51.152 ya lo habían hecho en el pasado (Returning Visitors - 23%).

    Estos 222.328 visitantes leyeron 533.567 páginas, es decir un promedio de 2.4 páginas por visitante.

    Dicho en términos diarios: 609 visitantes por día, de los cuales 469 lo hacían por primera vez, y 1.462 páginas leídas por día.




    En forma gráfica:






    El 25 de octubre fue el día record de visitas, con 1.419 visitantes y 3.219 páginas.

    En el 2006, el primer año de este blog, hubo cerca de 58.000 visitante y 163.000 páginas leídas. Es decir un crecimiento del 383% en la cantidad de visitantes y del 327% en la de páginas leídas.

    A todo esto habría que sumar las suscripciones del feed del blog, que también han crecido a buen ritmo. Al final del 2006 contaba con 33 suscriptores. De acuerdo a las estadísticas de Feedburner, a fin del 2007 este blog tenía 257, es decir casi 8 veces más.

    En el resumen del 2006 declaraba cuáles eran mis planes para el 2007: reunificar el blog de gráficos y presentación de datos en este blog, crear un sitio independiente que de solución a la descarga de archivos con ejemplos, mejorar la interfaz del blog y empezar a publicar una serie de guías prácticas en castellano.

    Debo reconocer que de todos los planes sólo he cumplido el de mejorar, no dramáticamente debo reconocer, la interfaz del blog.
    Las guías y el sitio pasan a ser las buenas intenciones para el 2008. En cuanto al blog de gráficos, sigo dudando qué hacer con él. Por ahora seguirá siendo un blog independiente.

    En resumen, 2007 ha sido un año de buen crecimiento para el blog, por lo que le estoy agradecido a mis lectores. Ha sido un año en el que sentido la gratitud de muchos de ustedes, también en los momentos difíciles que me han tocado vivir en mi vida personal.

    A todos, muchas gracias y mis mejores deseos de un feliz y próspero 2008.



    Technorati Tags: