Select to view content in your preferred language

Crear Gráficos Informativos en la Ventana Emergente con Arcade

131
0
2 weeks ago
XanderBakker
Esri Esteemed Contributor
2 0 131

Proporcionar más información

Aunque es posible de crear visualización en la ventana emergente y proporcionar información más clara al usuario, a veces no es suficiente solamente proporcionar la información que tiene el feature que estamos consultando. Hay situaciones donde nos interesa conocer el indicador clave de rendimiento en relación con la vecindad y en relación con otros momentos en tiempo. Un ejemplo de esto podemos observar en este tablero donde representen SAIDI (duración de interrupciones de servicio por año) y SAIFI (cantidad de interrupciones de servicio al año):

Gráfico - SAIDI.png

Fuente: https://storymaps.arcgis.com/stories/a944c3b67bed44d8adbfecc4b0748a0f

En este ejemplo mediante un gráfico muestren el puntaje SAIDI en relación con los demás circuitos en la zona del servicio. Este indicador es un insumo importante para realizar inversiones en la red para mejorar la calidad del servicio.

Para el caso de hoy usaremos los datos de cobertura de servicios de Colombia a nivel de municipio para conocer el grado de cobertura en relación con los municipios vecinos. Abajo un ejemplo de lo que se puede crear con Arcade:

Grafico - resultado.png

Con Arcade es posible realizar un análisis donde consultamos los municipios vecinos del municipio seleccionado y analizar la cobertura y generar una visualización atractiva brindando información adicional para el usuario. (Aunque este ejemplo va a utilizar información de entidades vecinos, también es posible realizar este tipo de análisis sobre información multitemporal para entender el rendimiento como función del tiempo).

Para obtener los municipios vecinos, se puede aplicar un buffer pequeño al municipio inicial y seleccionar los municipios que intersecan con el buffer:

Grafico - Buffer análisis.png

Para agregar HTML a la ventana emergente, no se debe elegir la opción “Expresiones de atributos”, pero hacer clic en “Agregar contenido” y luego elegir “</> Arcade”:

Arcade - Agregar contenido.png

En el editor de Arcade se puede ver un ejemplo del formato para un gráfico que la expresión debe entregar:

Grafico - Sugerencia Arcade.png

Es un diccionario, que contiene una serie de datos para definir los datos, los campos, colores, tipo de gráfico y títulos. Un gráfico requiere bastante información y dependiendo del tipo de gráfico, pero siempre los datos se entregan a la propiedad "attributes" como un diccionario, los campos a la propiedad "fields" y el tipo de gráfico a la propiedad "type".

Una explicación del código Arcade:

  • Línea 1: acceder al nombre del municipio seleccionado
  • Línea 2: calcular un buffer de 25 metros alrededor del municipio seleccionado
  • Línea 3 a 4: intersecar la capa de municipios con el buffer para tener la selección de municipios vecinos (incluyendo el municipio inicial)
  • Línea 6 a 31: bucle por los municipios vecinos, calcular la cobertura de todos los servicios, registrar el resultado en un diccionario (municipio::cobertura). En este parte también se registren los colores, aunque este listado se va a modificar más adelante porque es necesario ordenar el diccionario de resultados.
  • Línea 33 a 39: cambiar el formato del diccionario (municipio::cobertura) a un listado que se pueden ordenar por cobertura.
  • Línea 41 a 48: función que permite ordenar listados (arrays)
  • Línea 50: ordenar los municipios vecinos de cobertura máxima a cobertura mínima
  • Línea 51 a 64: pasar el listado ordenado a un diccionario nuevamente (para el formato que requiere el gráfico) y crear una lista de colores según el municipio
  • Línea 66 a 70: calcular estadísticas de cobertura y crear un texto para mostrar debajo del gráfico
  • Línea 72 a 88: devolver el resultado (el gráfico, tipo “columnchart”), asignando el diccionario de datos a la propiedad “attributes”, el listado de campos (municipios) a la propiedad “fields” y el listado de colores a la propiedad “colors”. Es importante que el diccionario y las listas tienen el mismo orden para obtener el resultado deseado.

 

El código Arcade (1)

var mpio = $feature.MUNICIPIO;
var buf25m = Buffer($feature, 25, "meter");
var fs = Intersects($layer, buf25m);
var cnt = Count(fs);

var dct_score = {};
var flds = [];
var colors = [];
var ind = -1;
var i = 0
for (var f in fs) {
  i += 1;
  var place = f.MUNICIPIO; // "Zone " + Text(i, '00');
  var current_mpio = f.MUNICIPIO;
  var acue = f.P_ACUESI / (f.P_ACUENO + f.P_ACUESI) * 100.0;
  var alca = f.P_ACUESI / (f.P_ACUENO + f.P_ACUESI) * 100.0;
  var elec = f.P_ACUESI / (f.P_ACUENO + f.P_ACUESI) * 100.0;
  var gasn = f.P_ACUESI / (f.P_ACUENO + f.P_ACUESI) * 100.0;
  var tele = f.P_ACUESI / (f.P_ACUENO + f.P_ACUESI) * 100.0;
  var score = Round((elec*5+acue*4+tele*3+alca*2+gasn)/15.0, 1);

  dct_score[place] = score;
  Push(flds, place);
  if (current_mpio==mpio) {
    var cob = score;
    Push(colors, [255, 125, 175, 255])
    ind = i;
  } else {
    Push(colors, [127, 127, 127, 127]) 
  }
}

// create arr with dicts
var data = [];
var arr_score = [];
for (current_mpio in dct_score) {
  Push(arr_score, {"NAME": current_mpio, "SCORE": dct_score[current_mpio]})
  Push(data, dct_score[current_mpio]);
}

// sort the dct
function comparar(a,b){
  if (a['SCORE']<b['SCORE'])
    return 1;
  if (a['SCORE']>b['SCORE'])
    return -1;
  return 0;
}

var arr_sorted = Sort(arr_score, comparar);
var flds2 = [];
var colors2 = [];
for (i in arr_sorted) {
  var dct = arr_sorted[i];
  current_mpio = dct["NAME"];
  score = dct["SCORE"];
  Push(flds2, current_mpio);
  if (current_mpio == mpio) {
    ind = i+1;
    Push(colors2, [255, 125, 175, 255])
  } else {
    Push(colors2, [200, 200, 200, 255]) 
  }
}

// stats
var minval = Min(data);
var maxval = Max(data);
var meanval = Mean(data);
var stats = 'Valor max: ' + maxval + '%  | valor media: ' + Round(meanval, 1) + '%  | valor min: ' + minval + '%';

return {
    type: 'media',
    title : 'Cobertura en ' + mpio + ' comparado con municipios vecinos',
    description : 'Cobertura: ' + cob + '%, y la posición relativa es: ' + ind + '/' + cnt,
    attributes : dct_score,  
    mediaInfos: [{
        type : 'columnchart', //linechart | barchart | piechart | columnchart
        title : '', //'Cobertura en relación con muncipios vecinos',
        caption : stats, // 'Cobertura en relación con muncipios vecinos',
        altText : 'Cobertura en relación con muncipios vecinos', 
        value : {
          fields: flds2,  
          colors: colors2 //,
          //normalizeField : '',  
        }
      }]
  }

 

Abajo un ejemplo de usar un gráfico de torta usando los datos de iNaturalist (LivingAtlas) para mostrar las observaciones en un parque:

Grafico - resultado torta.png

El código Arcade (2)

// colores por categoría
var dct_cols = {"Aves": [242, 223, 97, 255], "Plantae": [15, 153, 84, 255],
            "Insecta": [170, 134, 49, 255], "Arachnida": [0, 0, 0, 255],
            "Unknown": [234, 238, 234, 255], "Amphibia": [51, 119, 255, 255],
            "Fungi": [82, 203, 163, 255], "Mollusca": [138, 86, 14, 255],
            "Mammalia": [187, 84, 101, 255], "Actinopterygii": [102, 179, 255, 255],
            "Protozoa": [161, 230, 230, 255], "Reptilia": [217, 193, 148, 255]};

// función para ordenar datos
function comparar(a,b){
  if (a['Conteo']>b['Conteo'])
    return -1;
  if (a['Conteo']<b['Conteo'])
    return 1;
  return 0;
}

// acceso a los datos y obtener las observaciones en el parque seleccionado
var fs = FeatureSetByName($map, "Observations", ["taxon_category_name"], false);
var observaciones = Intersects(fs, $feature);
var parque = $feature.Nombre;

// crear diccionario con las observaciones por categoría
var dct_atts = {}; 
var arr_flds = []; 
for (var obs in observaciones) {
  var category = obs.taxon_category_name;
  if (HasKey(dct_atts, category)) {
    dct_atts[category] += 1;
  } else {
    dct_atts[category] = 1
    Push(arr_flds, category);
  }
}

//convertir diccionario con los resultados en un listado
var arr_atts = [];
for (category in dct_atts) {
  Push(arr_atts, {'Category': category, 'Conteo': dct_atts[category]});
}

// ordenar el listado
var arr_atts2 = Sort(arr_atts, comparar);

// convertir listado a diccionario y crear listados de campos y colores
dct_atts = {};
arr_flds = [];
var arr_cols = [];
for (var i in arr_atts2) {
  var dct_info = arr_atts2[i];
  category = dct_info['Category'];
  var conteo = dct_info['Conteo'];
  dct_atts[category] = conteo;
  Push(arr_flds, category)
  Push(arr_cols, dct_cols[category]);
}

// devolver los datos en formato de gráfico de torta
return {
    type: 'media',
    title : 'Observaciones iNaturalist',
    //description : 'Observaciones por categoría en ' + parque,
    attributes : dct_atts,  
    mediaInfos: [{
        type : 'piechart', 
        caption : 'Observaciones por categoría en parque ' + parque,
        value : {
          fields: arr_flds,  
          colors: arr_cols, 
        }
      }]
  } 

 

About the Author
Solution Engineer for the Utilities Sector @ Esri Colombia - Ecuador - Panamá sr GIS Advisor / Python - Arcpy developer / GIS analyst / technical project leader / lecturer and GeoNet moderator, focusing on innovations in the field of GIS. Specialties: ArcGIS, Python, ArcGIS Enterprise, ArcGIS Online, Arcade, Configurable Apps, WAB, Mobile Apps, Insights, Spatial Analysis, LiDAR / 3D Laser Scanning / Point Clouds. UNME http://nl.linkedin.com/in/xanderbakker/ http://www.slideshare.net/XanderBakker http://www.scribd.com/xbakker http://twitter.com/#!/XanderBakker