2014-06-30

Propiedades ColorIndex en VBA

En Excel empleamos el color de las celdas y de las fuentes para resaltar o facilitar la lectura de los datos. Excel posee dos propiedades diferentes para asignar programáticamente el color de relleno y el color de fuente: ColorIndex y Color.

ColorIndex genera hasta 57 colores:

Podemos generar el listado anterior con los colores de relleno y de fuente con el siguiente código:

Sub ColorIndex()
    Dim Cindex As Integer
    For Cindex = 0 To 56
        Cells(Cindex + 1, 1).Interior.ColorIndex = Cindex
        Cells(Cindex + 1, 1).Value = "Interior.ColorIndex = " & Cindex
        Cells(Cindex + 1, 2).Font.ColorIndex = Cindex
        Cells(Cindex + 1, 2).Value = "Font.ColorIndex = " & Cindex
        If Cells(Cindex + 1, 1).Interior.ColorIndex = 1 _
            Then Cells(Cindex + 1, 1).Font.ColorIndex = 48
    Next Cindex
        Columns(1).EntireColumn.AutoFit
        Columns(2).EntireColumn.AutoFit
End Sub
La propiedad Color es más extensa que ColorIndex ya que permite especificar colores con valores numéricos, hexadecimales, octales y RGB. Además, la paleta de Color es más extensa que la de ColorIndex. 57 colores en ColorIndex, 256 3 en RGB (16.777.216). Sin embargo, por su simplicidad, un índice del 0 al 56 en la paleta, podemos optar por ColorIndex en lugar de especificar 3 dígitos de 0 a 255 para un color en RGB.

Para ver el valor de las propiedades seleccionamos una celda y en la ventana de inmediato escribimos
?Selection.Interior.ColorIndex o ?Selection.Interior.Color y presionamos Entrar. En una celda que no tiene asignado un color de relleno el resultado de ColorIndex es -4142 (xlColorIndexNone) y el de Color es 16777215. Como ColorIndex solamente admite 56 colores, es posible que a dos colores diferentes les asigne el mismo valor. ColorIndex asignará el valor más cercano de la paleta del 0 al 56. Para conocer y asignar un color con precisión deberemos usar la propiedad Color.

Para mostrar en la barra de estado la propiedad ColorIndex del relleno de una celda y del color de fuente añadimos estos dos eventos en la hoja deseada:

' Muestra las propiedades
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Application.StatusBar = "Celda actual: Interior.ColorIndex = " & _
        ActiveCell.Interior.ColorIndex & "  /  Font.ColorIndex = " & _
        ActiveCell.Font.ColorIndex
End Sub
' Devuelve a Ms Excel el control de la barra de estado
Private Sub Worksheet_Deactivate()
Application.StatusBar = False
End Sub
Referencias:
Artículo de Microsoft Developer Network

2014-06-27

Valor más repetido aproximado en datos sin moda.

La moda es el valor que se repite con más frecuencia en una matriz o rango de datos. En Excel lo calculamos fácilmente con la fórmula MODA. Pero cuando todos los valores son diferentes y no hay moda, ¿cómo podemos calcular el valor aproximadamente más repetido?

En nuestro ejemplo tenemos una serie original de números, todos diferentes. Si queremos calcular el valor aproximado más repetido tenemos que recurrir a redondear (un decimal en nuestro ejemplo) o truncar el número decimal. Si truncamos, convertimos el número en entero sin redondearlo (14,5 se convierte en 14 no en 15). Podemos usar columnas auxiliares como la B o C, o directamente usar una fórmula.

Compara con:

=MODA(REDONDEAR(A2:A11;0))=15
=MODA(REDONDEAR.MENOS(A2:A11;0))=10, equivalente de truncar.

Porcentajes

En el caso de porcentajes no podemos usar la función truncar pues convertiría en ceros todos los números. Usamos la función redondear. Elegimos el número de decimales de acuerdo a la precisión deseada o necesidades.

¿Cuántas veces se repite?

Otro pregunta adicional es saber cuantas veces se repite dicho número. En condiciones normales o con columnas auxiliares con los números redondeados bastaría con la función CONTAR.SI. En este caso usamos la función SUMAR PRODUCTO.

Empleamos el doble operador negativo(double unary operator) para convertir los valores lógicos en numéricos positivos. Es la alternativa más rápida. Aunque es poco probable encontrar una situación en la que obtengamos una ganancia significativa por ello. Otras alternativas son:

=SUMAPRODUCTO(N((REDONDEAR(A2:A11;1)=A14)))
=SUMAPRODUCTO(0+(REDONDEAR(A2:A11;1)=A14))
=SUMAPRODUCTO(1*(REDONDEAR(A2:A11;1)=A14))
=SUMAPRODUCTO((REDONDEAR(A2:A11;1)=A14)^1)

Referencias:
Moda

2014-06-23

Exportar un rango de Excel al bloc de notas mediante VBA

Title Un aspecto importante al trabajar en una aplicación es la salida de datos o exportación de los mismos. Por ejemplo, para exportar datos en un formato de texto compatible con otras aplicaciones o sistemas. En otra entrada quizá trataremos las diferentes alternativas. En esta ocasión exportamos un rango como un fichero de texto (delimitado por tabulaciones) y lo abrimos con el bloc de notas.

Opción 1

La primera alternativa destaca por su brevedad. Abre el bloc de notas y pega el rango de CurrentRegion (región actual). El fichero de texto lo tendremos que guardar antes de cerrar. El problema es que usar SendKeys en VBA puede causar problemas imprevistos. En este caso desactiva la tecla Bloq Num.

Sub Rango_a_Bloc_de_notas1()
    Range("A1").CurrentRegion.Copy 'Celda de la región actual
    Shell "notepad.exe", vbNormalFocus
    SendKeys "^V"
    Close
End Sub

Opción 2

En esta segunda opción prescindimos de SendKeys. Creamos un libro nuevo de Excel, pegamos el contenido de CurrentRegion del libro inicial, guardamos el nuevo libro como fichero de texto con el nombre prueba.txt y abrimos el nuevo fichero de texto con el bloc de notas.

Sub Rango_a_Bloc_de_notas2()
    Application.ScreenUpdating = False
    Range("A1").CurrentRegion.Copy 'Celda de la región actual
    Dim ruta As String, wb As Object
    ruta = ThisWorkbook.Path & "\prueba.txt"
        Set wb = Workbooks.Add
        wb.Worksheets(1).Paste
        wb.SaveAs Filename:=ruta, FileFormat:=xlText
        Application.DisplayAlerts = False
        wb.Close
        Application.DisplayAlerts = True
    Shell "notepad.exe " & ruta, vbNormalFocus
End Sub

2014-06-20

Exportar gráficos de un libro de Excel con VBA

Hace unas semanas cree la siguiente subrutina que exporta todos los gráficos de un libro de Excel en la misma ruta del fichero desde donde se ejecuta.

Código

Option Explicit
Sub ExportarGraficos()
    Dim i As Integer, ext As String
    Dim ws As Object, chtobj As ChartObject
    Dim chtobjnum As Integer
    ext = InputBox(Prompt:="Escribe la extensión incluyendo el punto." _
            & vbCrLf & "Ej: .png, .gif, .jpeg, etc.", _
            Title:="Extensión de la imagen", Default:=".png")
        For Each ws In ThisWorkbook.Worksheets
        chtobjnum = chtobjnum + ws.ChartObjects.Count
            For Each chtobj In ws.ChartObjects
              chtobj.Activate
              ActiveChart.Export Filename:=ThisWorkbook.Path & "\" _
              & ActiveChart.Name & ext
            Next chtobj
        Next ws
    MsgBox "Gráficos exportados: " & chtobjnum & vbCrLf & _
     "Ruta: " & ThisWorkbook.Path, vbInformation, "Gráficos"
End Sub

Aclaraciones

Al ejecutarla muestra un cuadro de diálogo para escoger la extensión de la imagen deseada. Por defecto es .png.

Al finalizar la subrutina muestra un mensaje de texto con el número de gráficos exportados y la ruta donde se guardaron.

Gráficos exportados

2014-06-17

Ilusión óptica de la pared del café en R

Title La ilusión óptica de la pared del café es una ilusión óptica geométrica en la que las líneas paralelas que separan los azulejos alternando en dos colores parecen ser oblicuas. Fue redescubierta por Richard Gregory in 1973 cuando un compañero de su laboratorio observó dicho efecto en la fachada de un café de Bristol.

En una entrada anterior recreamos el efecto en Excel. Esta vez lo hacemos en R.

Datos

 # OPCION 1: Importamos txt exportado desde Excel
cafe <- read.delim("~/R/cafe.txt", dec = ",")
 # OPCION 2: Datos desde cero
fila.1 <- rep(c(0.5,1),5) # Fila inicial
fila.2a13  <- rep(1,10)   # Resto filas

  # a. Data.frame
  cafe.df <- t(data.frame(fila.1, replicate(12,fila.2a13))) # Transponemos
  rownames(cafe.df) <- NULL # Eliminamos nombres de las filas
  
  # b. Matriz
  cafe.m <- matrix(c(fila.1,replicate(12,fila.2a13)),ncol=10,byrow=T)

Gráficos

# Barra apilada en blanco y negro
# OPCION 1
barplot(as.matrix(cafe),           # En formato matriz
        col = c("white", "black"), 
        horiz = TRUE, space = 0.01, 
        xaxt = "n", 
        yaxt = "n", 
        border = "gray")

# OPCION 2
barplot(as.matrix(cafe.df,         # O cafe.m
        col = c("white", "black"), # "steelblue" en lugar de "black"
        horiz = TRUE, space = 0.01, 
        xaxt = "n", 
        yaxt = "n", 
        border = "gray")

Black

Steelblue

Notas

Son varias las leyes que gobiernan la ilusión óptica. Para crear los gráficos anteriores, merece la pena mencionar varios aspectos. Es necesario que los colores de los azulejos sean contrastados. Es clave el tamaño del espacio y el color de separación entre las series para que contraste tanto con los azulejos oscuros como con los claros. Para lograr la ilusión óptica tenemos que evitar que los azulejos sigan un patrón ajedrezado o que los colores sean paralelos. Para ello creamos la fila inicial de la matriz o data frame.

Entradas relacionadas:
Ilusión óptica de la pared del café en Excel

2014-06-13

Formato condicional que diferencia ceros y celdas vacías

Excel aplica el mismo formato condicional a ceros y celdas vacías cuando creamos nuestras reglas de formato. Como consecuencia los ceros y las celdas vacías son indistinguibles. Para resolver el problema vamos a ver un ejemplo sencillo:

Situación inicial


Soluciones

1. Aplicar escalas de colores

Es la solución más rápida y sencilla. Para cambiar los colores por defecto de la escala: Formato condicional > Escalas de Color > Más reglas...

2. Añadir una tercera condición para las celdas vacías

La condición de las celdas vacías la ponemos por delante de la condición de los ceros y seleccionamos la casilla Detener si es verdad

3. Excluir las celdas vacías del formato condicional para los ceros

Resultado final

2014-06-09

Evento al hacer doble clic sobre una celda

Title El doble clic sobre una celda es un evento que podemos emplear en muy diversas ocasiones.

1. Abrimos el editor de Visual Basic Alt+F11, o en la ficha Programador, en el grupo Controles, clic en Ver código

2. Doble clic en ThisWorkbook y copiamos el código:

Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, _
    ByVal Target As Range, Cancel As Boolean)
    'NUESTRO CÓDIGO
End Sub
Dos aplicaciones prácticas:

1. Ir a un rango que deseamos consultar frecuentemente desde cualquier hoja del libro.

Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, _
    ByVal Target As Range, Cancel As Boolean)
    Sheets("Hoja1").Activate
    Range("A1:A10").Select
End Sub
2. Añadir fecha y hora a cualquier celda del libro.

Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, _
    ByVal Target As Range, Cancel As Boolean)
    ActiveCell = Date & Chr(32) & Time
End Sub
Si queremos que muestre los segundos, presiona CTRL+1 para mostrar el cuadro de diálogo Formato de celdas y en Tipo, escribimos: dd/mm/aaaa h:mm:ss

2014-06-06

Agregar datos en R con el paquete reshape2

Title El paquete reshape2, creado por Hadley Wickham permite transformar y agregar datos con dos funciones: melt y cast. En esta entrada nos vamos a centrar en la agregación de datos para obtener resultados similares a los obtenidos con las tablas dinámicas en Excel. El objetivo de la agregación es ordenar, reducir y mostrar la información resumida de manera que nos facilite responder a preguntas planteadas sobre nuestros datos.

Partimos de la base de datos Northwind. Exportamos la consulta Análisis de ventas a Excel y creamos una tabla dinámica con la que iremos comparando los resultados que deseamos obtener en R. Desde Excel guardamos la hoja de datos como fichero CSV que importaremos en R.

Puedes descargar el fichero Análisis de ventas.csv y copiarlo en tu directorio de trabajo.

Importación y formato

1. Importamos el fichero CSV. Es importante observar el formato de la columna con valores. El símbolo de moneda si lo hubiera, los separadores decimal y de miles. Previamente instalamos los paquetes necesarios.

require(plyr)  # Para usar la función . de plyr
require(reshape2)
data <- read.csv("Análisis de ventas.csv", sep = ";") 
2. Formateamos los datos importados.

names(data) <- tolower(names(data))  # Nombres de columnas en minúsculas
data$ventas <- sub("([.])", "", data$ventas)  # Separador de miles la coma
data$ventas <- sub(",", ".", data$ventas)  # Separador decimal el punto
data$ventas <- as.numeric(data$ventas)  # Ventas tipo de variable numérica
data$fecha.de.pedido <- as.Date(data$fecha.de.pedido, "%d/%m/%Y") # Fechas

reshape2

3. Definimos identifiers (id.vars) y measured variables (measure.vars) con melt. Identificadores y valores, el equivalente en las tablas dinámicas de Excel a etiquetas o rótulos de filas y valores.

data.m <- melt(data, id.vars = c(1:19), measure.vars = 6)
data.m # Resultado: 
      cliente mesdetrimestre variable value
1 Compañía AA              1   ventas  1400
2 Compañía AA              1   ventas   105
3  Compañía D              1   ventas   300
4  Compañía D              1   ventas   530
5  Compañía D              1   ventas    35
6  Compañía L              1   ventas   270
A la derecha de la última id.vars (mesdetrimestre en este caso) crea dos columnas, con los nombres variable y value. Bajo variable sólo incluirá la variable ventas pues es la única definida como measured variable.

4. Comenzamos a agregar datos usando dcast.

a. Agrupando por empleado. Queremos el siguiente resultado.

data.c <- dcast(data.m, empleado ~ variable, sum, margins = "empleado")
data.c # Resultado:
               empleado   ventas
1      Francisco Chaves 19974.25
2      Humberto Acevedo  3786.50
3         Jesús Escolar  2617.50
4     Juan Carlos Rivas  6378.00
5          Luis Bonifaz   680.00
6        María González  6561.00
7    María Jesús Cuesta  6278.00
8 Pilar Pinilla Gallego  5787.50
9                 (all) 52062.75 

Argumentos de dcast:

data: molten data frame. El data frame obtenido con melt anteriormente.
formula: especificamos las variables que deseamos incluir, en este caso empleado. Hay un par de caracteres especiales: "..." representa todas las otras variables no usadas en la fórmula y "." representa a ninguna variable.
fun.aggregate: la función de agregación de la función, en ese caso sum.
margins: para añadir los subtotales, margins = TRUE devolverá todos los subtotales disponibles.
fill: valor que sustituirá a aquellos que faltan cuando fun.aggregate se aplica sobre un vector de longitud 0.

Más ejemplos:

# Total de ventas
data.c <- dcast(data.m, . ~ variable, sum) 
# Agrupar por otra variable, nombre de cliente
data.c <- dcast(data.m, nombre.del.cliente ~ variable, sum, margins = "nombre.del.cliente") 

Función . de plyr para filtrar

5. Agrupamos por nombre de cliente y filtramos por el empleado Francisco Chaves. Queremos el siguiente resultado.

data.c <- dcast(data.m, nombre.del.cliente ~ variable, sum, margins = "nombre.del.cliente", subset = .(empleado == "Francisco Chaves")) 
data.c
  nombre.del.cliente   ventas
1        Compañía AA  1505.00
2        Compañía BB 13800.00
3         Compañía D   184.00
4         Compañía Y   860.00
5         Compañía Z  3625.25
6              (all) 19974.25

Más consultas

Jugamos con los elementos anteriores, tomados de reshape2, plyr, y los operadores lógicos. Practicamos la sintaxis e interrogamos nuestros datos hasta que confiesen.1

6. Queremos saber las ventas de los empleados Francisco Chaves y Humberto Acevedo, agrupadas por categoría con su correspondiente subtotal por empleado. El resultado sería:

Añadimos dos identifiers (rótulos de fila), agrupamos por el total de categoría de cada empleado y filtramos por dos empleados, Francisco Chaves o Humberto Acevedo.

data.c <- dcast(data.m, empleado + categoría ~ variable, sum, margins = "categoría", subset = .(empleado == "Francisco Chaves" | empleado == "Humberto Acevedo")) 
                 empleado                   categoría   ventas
1       Francisco Chaves                      Aceite   533.75
2       Francisco Chaves                     Bebidas 15200.00
3       Francisco Chaves              Carne enlatada   552.00
4       Francisco Chaves                 Condimentos   660.00
5       Francisco Chaves                Frutos secos   105.00
6       Francisco Chaves     Mermeladas y confituras  2250.00
7       Francisco Chaves         Productos horneados   384.00
8       Francisco Chaves                       Sopas   289.50
9       Francisco Chaves                       (all) 19974.25
10      Humberto Acevedo                       Pasta  1950.00
11      Humberto Acevedo           Productos lácteos  1740.00
12      Humberto Acevedo                       Sopas    96.50
13      Humberto Acevedo                       (all)  3786.50
Más ejemplos:

# Por empleado y categoría, excluyendo la Compañía H de los clientes
data.c <- dcast(data.m, empleado + categoría ~ variable, sum, margins = c("categoría", "empleado"), subset = .(nombre.del.cliente != "Compañía H")) 

# Otras funciones de agregación: mínimo, media y máximo
# Ventas por nombre del cliente
data.c <- dcast(data.m, nombre.del.cliente ~ variable, min, fill = 0) 
data.c <- dcast(data.m, nombre.del.cliente ~ variable, mean, fill = 0)
data.c <- dcast(data.m, nombre.del.cliente ~ variable, max, fill = 0) 

Introducimos el argumento fill para evitar el mensaje de advertencia.

Fechas

7. La venta del empleado María Jesús Cuesta por producto entre dos fechas.

Opción 1

# Genera un error
data.c <- dcast(data.m, fecha.de.pedido + producto ~ variable, margins = c("fecha.de.pedido", "producto"), sum, subset = .(fecha.de.pedido > "2006-03-01" & fecha.de.pedido < "2006-05-01" & empleado == "María Jesús Cuesta")) 
str(data.c) # Estructura de un objeto
La inclusión de la fecha para los subtotales (margins) y del filtro por fecha genera un error. Y transforma fecha.de.pedido de Date a Factor. Se comprueba con la función str que muestra la estructura interna del objeto.

Warning messages:
1: In Ops.factor(fecha.de.pedido, "2006-03-01") :
  > not meaningful for factors
2: In Ops.factor(fecha.de.pedido, "2006-05-01") :
  < not meaningful for factors 

> str(data.c)
'data.frame': 1 obs. of  3 variables:
 $ fecha.de.pedido: Factor w/ 24 levels "2006-01-15","2006-01-20",..: NA
 $ producto       : Factor w/ 24 levels "Aceite de oliva Northwind Traders",..: NA
 $ NA             : num NA
Opción 2

# Subtotales incompletos
data.c <- dcast(data.m, as.Date(fecha.de.pedido) + producto ~ variable, sum, margins =c("fecha.de.pedido", "producto"), subset = .(fecha.de.pedido > "2006-03-01" & fecha.de.pedido < "2006-05-01" & empleado == "María Jesús Cuesta"))
data.c 
No genera un error pero presenta uno subtotales incompletos, solamente por producto.

  as.Date(fecha.de.pedido)                                 producto ventas
1       2006-03-24                       Té verde Northwind Traders    598
2       2006-03-24                                            (all)    598
3       2006-04-05 Galletas de chocolate surtidas Northwind Traders    230
4       2006-04-05                    Salsa curry Northwind Traders   1000
5       2006-04-05                                            (all)   1230
6       2006-04-25                        Almíbar Northwind Traders    500
7       2006-04-25                    Salsa curry Northwind Traders    120
8       2006-04-25                                            (all)    620
Opción 3

# Resultado correcto
fecha <- data.m$fecha.de.pedido
data.d <- data.m[fecha > "2006-03-01" & fecha < "2006-05-01", ]
data.c <- dcast(data.d, fecha.de.pedido + producto ~ variable, sum, margins = c("fecha.de.pedido", "producto"), subset = .(empleado == "María Jesús Cuesta"))
data.c
Filtramos previamente el molten data frame creado anteriormente con melt (punto 4).

  fecha.de.pedido                                         producto ventas
1      2006-03-24                       Té verde Northwind Traders    598
2      2006-03-24                                            (all)    598
3      2006-04-05 Galletas de chocolate surtidas Northwind Traders    230
4      2006-04-05                    Salsa curry Northwind Traders   1000
5      2006-04-05                                            (all)   1230
6      2006-04-25                        Almíbar Northwind Traders    500
7      2006-04-25                    Salsa curry Northwind Traders    120
8      2006-04-25                                            (all)    620
9           (all)                                            (all)   2448
Referencias:
Introducción y manual


1 Ronald Coase: "If you torture the data enough, nature will always confess."

2014-06-03

Ilusión óptica de la pared del café en Excel

Title La ilusión óptica de la pared del café es una ilusión óptica geométrica en la que las líneas paralelas que separan los azulejos alternando en dos colores parecen ser oblicuas. Fue redescubierta por Richard Gregory in 1973 cuando un compañero de su laboratorio observó dicho efecto en la fachada de un café de Bristol.

Notas

He reproducido la idea del fichero creado en 2010 por Hui. Se trata básicamente de un diagrama de barras apilado (100% apilado en el caso de Hui). He simplificado la formulación que desplaza los azulejos hacia la derecha y crea el efecto zigzag. He ampliado el desplazamiento para partir de una alineación vertical y terminar en un patrón ajedrezado. Finalmente, he añadido una barra de desplazamiento (control ActiveX) que actualiza constantemente los valores por lo que la respuesta sea continua. Hui utilizó una barra de desplazamiento (control de formulario) que actualiza los resultados después del clic. En lugar del blanco y negro, he optado por un color azul más vivo. El color no afecta la ilusión óptica. Sí lo hace en cambio la separación entre cada fila de azulejos (espesor de la junta).

Referencias

2014-06-01

Abrir ficheros mediante un archivo batch

Title Un archivo batch es un archivo de procesamiento por lotes. Se trata de archivos de texto sin formato, guardados con la extensión .BAT que contienen un conjunto de instrucciones MS-DOS. Cuando se ejecuta este archivo, —mediante CMD— las órdenes contenidas son ejecutadas en grupo, de forma secuencial, permitiendo automatizar diversas tareas.

En este caso simplemente vamos a abrir ficheros mediante archivos batch:

1. Abrimos el Wordpad
2. Escribimos entre comillas la ruta completa del fichero que deseamos abrir:

"C:\Tu ruta\Fichero 1.txt"
La ruta se escribe entre comillas por si hay un espacio al final de la ruta especificada.

3. Clic en Guardar como con el nombre deseado, y en tipo elegimos Documento de texto - formato MS-DOS (*.txt) el fichero

4. Cambiamos la extensión del archivo a *.bat o *.cmd
5. Al hacer doble clic sobre el fichero .bat o .cmd se abrirá el fichero 1.

Sintaxis para abrir programas


START "title" [/D path] [options] "command" [parameters]

REM Ejemplos:
START "" "%SystemRoot%\WORD.exe"
START "" "C:\Program Files\Adobe\Reader 11.0\Reader\AcroRd32.exe"
START "" "C:\Program Files\Microsoft Office 15\root\office15\EXCEL.EXE
Tras START añadimos las "" porque es necesario especificar un título, aunque sea vacío.

Un ejemplo

Podemos añadir cierto grado de interactividad con el comando CHOICE, para elegir entre varias opciones. He creado el siguiente ejemplo que permite elegir entre 5 opciones.

Usamos Wordpad en lugar del bloc de notas para poder guardar con formato MS-DOS. En caso contrario, si la ruta del fichero incluye caracteres especiales, el archivo batch no abrirá el mismo ni representará esos caracteres en la consola correctamente.

He incluido varios caracteres especiales para que se pueda apreciar la diferencia. Primero el fichero sin formato, cuando lo escribimos en el Wordpad. Luego el fichero guardado con formato MS-DOS.

Sin formato MS-DOS

@ECHO OFF

ECHO México: 1
ECHO Perú:   2
ECHO Canadá: 3
ECHO España: 4
ECHO Salir:  5

CHOICE /C 12345 /M "¿Qué fichero quieres abrir?"

IF ERRORLEVEL 5 GOTO 5
IF ERRORLEVEL 4 GOTO 4
IF ERRORLEVEL 3 GOTO 3
IF ERRORLEVEL 2 GOTO 2
IF ERRORLEVEL 1 GOTO 1

:5
ECHO Opción 5 seleccionada
GOTO End

:4
ECHO Opción 4 seleccionada
"C:\Tu ruta\España.txt"
GOTO End

:3
ECHO Opcion 3 seleccionada
"C:\Tu ruta\Canadá.txt"
GOTO End

:2
ECHO Opcion 2 seleccionada
"C:\Tu ruta\Perú.txt"
GOTO End

:1
ECHO Opcion 1 seleccionada
"C:\Tu ruta\México.txt"
GOTO End

:end

Guardado con formato MS-DOS

@ECHO OFF

ECHO M‚xico: 1
ECHO Per£:   2
ECHO Canad : 3
ECHO Espa¤a: 4
ECHO Salir:  5

CHOICE /C 12345 /M "¨Qu‚ fichero quieres abrir?"

IF ERRORLEVEL 5 GOTO 5
IF ERRORLEVEL 4 GOTO 4
IF ERRORLEVEL 3 GOTO 3
IF ERRORLEVEL 2 GOTO 2
IF ERRORLEVEL 1 GOTO 1

:5
ECHO Opci¢n 5 seleccionada
GOTO End

:4
ECHO Opci¢n 4 seleccionada
"C:\Tu ruta\Espa¤a.txt"
GOTO End

:3
ECHO Opcion 3 seleccionada
"C:\Tu ruta\Canad .txt"
GOTO End

:2
ECHO Opcion 2 seleccionada
"C:\Tu ruta\Per£.txt"
GOTO End

:1
ECHO Opcion 1 seleccionada
"C:\Tu ruta\M‚xico.txt"
GOTO End

:end

Resultado en la consola

Otra alternativa es escribir al comienzo del archivo batch: CHCP 1252. Interpretará los caracteres especiales en las rutas, aunque no representará bien los caracteres en la consola.

Windows-1252 a archivos batch


Finalmente he creado una tabla con los caracteres Windows-1252 y su equivalente en MS-DOS.

Carácter = Archivo batch
        =
    !   =   !
    "   =   "
    #   =   #
    $   =   $
    %   =   %
    &   =   &
    \'  =   \'
    (   =   (
    )   =   )
    *   =   *
    +   =   +
    ,   =   ,
    -   =   -
    .   =   .
    /   =   /
    0   =   0
    1   =   1
    2   =   2
    3   =   3
    4   =   4
    5   =   5
    6   =   6
    7   =   7
    8   =   8
    9   =   9
    :   =   :
    ;   =   ;
    <   =   <
    =   =   =
    >   =   >
    ?   =   ?
    @   =   @
    a = a
    b = b
    c = c
    d = d
    e = e
    f = f
    g = g
    h = h
    i = i
    j = j
    k = k
    l = l
    m = m
    n = n
    o = o
    p = p
    q = q
    r = r
    s = s
    T = T
    u = u
    v = v
    w = w
    x = x
    Y = Y
    Z = Z
    [   =   [
    \   =   \
    ]   =   ]
    ^   =   ^
    _   = _
    `   =   `
    a = a
    b = b
    c = c
    d = d
    e = e
    f = f
    g = g
    h = h
    i = i
    j = j
    k = k
    l = l
    m = m
    n = n
    o = o
    p = p
    q = q
    r = r
    s = s
    T = T
    u = u
    v = v
    w = w
    x = x
    Y = Y
    Z = Z
    {   =   {
    |   =   |
    }   =   }
    ~   =   ~
    €   = _
    ‚   =   '
    ƒ = Ÿ
    „ = ""
    …   =   .
    † = Å
    ‡ = Î
    ˆ   =   ^
    ‰   =   %
    š = s
    ‹   =   <
    œ = o
    ž = Z
    ‘   =   '
    ’   =   '
    “ = ""
    ” = ""
    •   =    
    –   =   -
    —   =   -
    ˜   =   ~
    ™ = T
    š = s
    ›   =   >
    œ = o
    ž = Z
    Ÿ = Y

Referencias:
Archivo batch
START

Nube de datos