BLOG
|
Usar Campos de tipo "DateOnly" en ArcGIS Dashboards En este blog compartiremos una manera de usar campos de fecha solamente (DateOnly) en un tablero de control (ArcGIS Dashboards). Nuevos tipos de campos Desde finales del año pasado contamos con nuevos tipos de campos en ArcGIS Online, pero el soporte para estos tipos de campos todavía no está en ArcGIS Dashboards. Más información sobre los nuevos campos: https://www.esri.com/arcgis-blog/products/arcgis-online/mapping/time-is-on-your-side-with-new-field-types-in-arcgis-online/ Al publicar un servicio desde ArcGIS Pro con estos nuevos tipos de campos en el esquema, genere un aviso indicando que el uso puede ser limitado y efectivamente eso es el caso para los tableros que configures en ArcGIS Dashboards. ¿Dónde están mis campo? Al publicar un conjunto de datos con campos de tipo fecha solamente ("DateOnly"), estos aparecen correctamente al explorar el servicio en ArcGIS Online: Pero en el momento de configurar alguna visualización como un gráfico de serie en ArcGIS Dashboards, se puede notar que estos campos no aparecen: Arcade al rescate Afortunadamente, es posible usar las expresiones de datos basadas en Arcade para crear en memoria un conjunto de datos con el esquema adaptado tal que ArcGIS Dashboard puede usar la fecha para crear la visualización deseada. Para conocer más acera de la creación de expresiones de datos con Arcade, puede consultar este página web: https://doc.arcgis.com/es/dashboards/latest/get-started/create-data-expressions.htm El concepto consiste en leer el featureset, modifcar el esquema, convertir la fecha, y convertir estos datos a un featureset en memoria. La gestión de fechas es algo que requiere un poco más de atención cuando se va a trabajar con expresiones de datos. No es posible escribir una fecha directamente a un campo de fecha, y es necesaria traducir la fecha a un epoch. Epoch o "Unix Time" se define como la cantidad de segundos transcurridos desde la medianoche UTC del 1 de enero de 1970, sin contar segundos intercalares. @DavidNyenhuis1 contestó a una pregunta en la comunidad compartiendo una manera para tomar un featureset y crear un "copia" en memoria con la posibilidad de modificar los datos en el proceso según la necesidad: https://community.esri.com/t5/arcgis-online-ideas/arcade-allow-date-values-in-date-fields/idc-p/1265782/highlight/true#M9860 Tomando esto como base se puede crear la solución que buscamos. Lo que es necesario es ajustar la expresión para modificar el esquema en el proceso. Abajo la expresión de datos con Arcade. La expresión es genérico aunque es necesario cambiar la referencia al featureset en la linea 40, conectando a su portal, especificando el ID del servicio y el índice de la capa a usar. // basado en:
// source: https://community.esri.com/t5/arcgis-online-ideas/arcade-allow-date-values-in-date-fields/idi-p/1204894
// de: David Nyenhuis
// Since a esriTypeDate can't take an Arcade Date, need to cast to EPOCH
// Pass in a feature
function CastDatesToEpoch(feat) {
var modifiedAttributes = {};
for (var att in feat) {
if(TypeOf(feat[att]) == 'Date') {
modifiedAttributes[att] = Number(feat[att])
Console('${feat[att]} is now ${Number(feat[att])}')
} else if(TypeOf(feat[att]) == 'DateOnly') {
modifiedAttributes[att] = Number(feat[att])
Console('${feat[att]} is now ${Number(feat[att])}')
}
else {
modifiedAttributes[att] = feat[att]
}
}
return modifiedAttributes
}
function ModifySchema(sch) {
var txt = Text(sch);
var sch2 = Dictionary(txt);
var lst_flds = sch2["fields"];
for (var i in lst_flds) {
var dct_fld = lst_flds[i];
if (dct_fld["type"] == "esriFieldTypeDateOnly") {
dct_fld["type"] = "esriFieldTypeDate";
}
lst_flds[i] = dct_fld;
}
sch2["fields"] = lst_flds
return sch2;
}
// get the layer
var fs = FeatureSetByPortalItem(Portal('https://utility-esri-co.maps.arcgis.com'), 'bf4a31341a5d49be90de6ce471a0b647', 0);
// Define a new dictionary feature set
var sch = Schema(fs);
var sch2 = ModifySchema(sch);
var dict = {
'fields': sch2.fields,
'geometryType': sch2.geometryType, // Can be esriGeometryNull, esriGeometryPoint, esriGeometryPolyline, esriGeometryPolygon;
'features': []
};
// Do something to each feature, like add a field, then add it to the dictionary
var index = 0;
for (var f in fs) {
// Add each feature to new dictionary and cast dates to EPOCH
dict.features[index] = {
'geometry': Geometry(f),
'attributes': CastDatesToEpoch(f)
}
index++;
}
// Convert dictionary to feature set.
return FeatureSet(Text(dict)); Al usar la expresión de datos como fuenta para crear por ejemplo un gráfico de serie ahora si aparecen los campos de las fechas: Resultado y aspectos para tener en cuenta Abajo se puede ver un ejemplo generado a partir de la expresión de datos que brinda acceso a a los campos de fecha: En caso de usar expresiones de datos es importante tener algunos aspectos en cuenta: Lo más importante es la experiencia del usuario final y para logar una buena experiencia del usuario el rendimiento del tablero debe ser bien. La expresión de datos que presentamos en este blog lea todo el featureset y lo replique en memoria. Esto funcione bien con una conjunto de datos de en este caso unos 1500 registros, pero si la capa es muy grande el usuario va a notar una reducción del rendimiento. Si la visualización no requiere todos los datos, aplique un filtro a los datos en el momento de leer la capa. Seguramente el soporte para estos nuevos campos va a aparecer en tiempo en las aplicaciones de ArcGIS. Si el objetivo es crear visualizaciones con base en fechas es mejor evitar el uso de estos campos en los conjuntos de datos hasta que se cuenta con soporte completa de estos campos. La expresión en este ejemplo solamente toma encuenta el caso de modificar un campo de solo fecha. No gestione campos de solo tiempo ni combine campos de solo fecha y solo tiempo en un campo de fecha.
... View more
2 weeks ago
|
1
|
0
|
132
|
POST
|
Hi @RaimonReventós , Almost a year ago I posted an idea (internally) with the title "Provide the location clicked in the pop-up to the Arcade expression". However, the idea is still open...
... View more
07-27-2022
02:21 PM
|
2
|
1
|
1430
|
DOC
|
Hi @Vanilla2020 , Have a look at the "GetFieldNamesOnPrivacy" function below: Function HasDomain(f, fldname) {
return Domain(f, fldname) != Null;
}
Function GetAlias(f, fldname) {
var esquema = Schema(f);
var flds = esquema["fields"];
for (var i in flds) {
var fldinfo = flds[i];
if (fldinfo["name"]==fldname) {
return fldinfo["alias"];
}
}
return fldname;
}
Function GetFieldNamesOnPrivacy(f) {
// privacy_level with values from 0 to 5)
// I want to display, say field_A, field_B, field_C, field_D
// for locations with privacy level larger than 2,
// while only field_A and field_B
var fldlst = [];
var level = f["privacy_level"];
if (level > 2) {
fldlst = ["field_A", "field_B"];
} else {
fldlst = ["field_A", "field_B", "field_C", "field_D"];
}
return fldlst;
}
var fs = FeatureSetByName($datastore, "_8_de_formulario");
var oid = $feature.objectid;
var sql = "OBJECTID = @oid";
var f = First(Filter(fs, sql));
// var excludeflds = ['globalid', 'objectid', 'prueba', "x_coord","y_coord","EditDate","Editor"];
var flds = GetFieldNamesOnPrivacy(f);
var info = [];
var atts = {};
for (var i in flds) {
var fldname = flds[i];
if (!IsEmpty(f[fldname])) {
var alias = GetAlias(f, fldname);
Push (info, {'fieldName': alias})
if (HasDomain(f, fldname)) {
atts[alias] = DomainName(f, fldname);
} else {
atts[alias] = f[fldname];
}
}
}
return {
type: 'fields',
title: 'Detalles de la actividad',
description : '(con Arcade)',
fieldInfos: info,
attributes : atts
}
... View more
07-27-2022
02:16 PM
|
0
|
0
|
8144
|
POST
|
Hi @AdamGebhart , I am glad that @KenBuja shared a good solution. Apart from the solution provided by Ken, there are many ways to do this. You can compare by exact date and time (probably the date has a time like 6 pm since it is stored as UTC date time and there is a difference between your local time zone and UTC): if ($feature.StatusDate == Date(2022, 11, 31, 18, 0, 0)) { ... } Another way (when the time does not matter) is to translate it to text and compare it as a string: if (Text($feature.StatusDate, "M/D/YY") == "12/31/22") { ... }
... View more
06-21-2022
01:27 PM
|
2
|
1
|
718
|
DOC
|
Hi @jschuckert , Good question... The FeatureSetByRelationshipName function is available in ArcGIS Online, but was not available in ArcGIS Enterprise at version 10.5.1. This might make the request to the server invalid or perhaps the response is not getting through correctly. Have you verified if there is something in the logs of ArcGIS Server?
... View more
06-21-2022
10:27 AM
|
0
|
0
|
4655
|
DOC
|
Hi @VanessaSimps , The comment above your comment explains just how to do that using the new Map Viewer and Arcade elements. Let me know if you have any questions on how to do this.
... View more
06-21-2022
10:14 AM
|
0
|
0
|
8399
|
POST
|
Hi @FredIausly1 , When I test with the TimeStamp() and Now() functions they return different results. The TimeStamp() will return the current date-time in UTC and Now() will return the current date-time in my Local time zone. You can use the ToLocal() and ToUTC() functions to switch between the time zones, but there is no function to automatically change to another time zone that is not UTC or Local. Be aware that the ToLocal and ToUTC functions will simply add or extract the number of hours difference between UTC and Local time zone indifferent is you provide a UTC or Local time. Also, in ArcGIS Online, date-time is stored in UTC and when you manually create a date it will be assumed to be in UTC. You can however use the DateAdd() function and add or subtract the number of hours to obtain the date-time in another time zone, but you should account for Daylight Saving Time depending on the date.
... View more
06-21-2022
10:12 AM
|
0
|
1
|
1662
|
POST
|
Hi @OliverSandoval_p , Sorry for the delay, but when I look at the distances that you get I wonder how big your feature is... Distances of 65M feet are about halfway around the globe. If I use Infinity or the searchDist as the initial minimum distance it will return the same result:
... View more
06-03-2022
10:41 AM
|
0
|
1
|
1130
|
POST
|
Hi @NCESOpen_Data , Sorry for the delay. In your case you can use something like: var txt = $feature["Your text field"];
if (Lower(txt) != 'unavailable') {
txt = Left(txt, Count(txt)-4);
}
return txt; A small example: var list = ['New Orleans, LA', 'Unavailable', 'Redlands, CA', 'Manhattan, NY'];
for (var i in list) {
var txt = list[i];
if (Lower(txt) != 'unavailable') {
txt = Left(txt, Count(txt)-4);
}
Console(txt);
} This will write to the console: New Orleans
Unavailable
Redlands
Manhattan
... View more
05-24-2022
03:43 PM
|
0
|
0
|
8638
|
POST
|
Hi @ArmstKP , I am not sure, so I can't confirm, but based on what you are seeing I can imagine that there are restrictions with this datasource.
... View more
05-10-2022
09:23 AM
|
0
|
0
|
665
|
POST
|
Hi @SSMGroup , ArcGIS Dashboards in ArcGIS Online is also updated with each update of ArcGIS Online: https://www.esri.com/arcgis-blog/?s=#what's%20new&products=ops-dashboard
... View more
05-02-2022
09:09 AM
|
0
|
0
|
1041
|
DOC
|
Hi @erica_poisson , Yes, you can when you use the new Map Viewer. In this case, you will not add an expression (virtual field) to the pop-up, but you will add an Arcade Element and configure something like: Function HasDomain(f, fldname) {
return Domain(f, fldname) != Null;
}
Function GetAlias(f, fldname) {
var esquema = Schema(f);
var flds = esquema["fields"];
for (var i in flds) {
var fldinfo = flds[i];
if (fldinfo["name"]==fldname) {
return fldinfo["alias"];
}
}
return fldname;
}
Function GetFieldNames(f, excludeflds) {
var fldlst = [];
var esquema = Schema(f);
var flds = esquema["fields"];
for (var i in flds) {
var fldinfo = flds[i];
// Console(fldinfo["name"]);
// Console(Includes(excludeflds, fldinfo["name"]));
if (!Includes(excludeflds, fldinfo["name"])) {
Push(fldlst, fldinfo["name"]);
}
}
Console(fldlst)
return fldlst;
}
var fs = FeatureSetByName($datastore, "_8_de_formulario");
var oid = $feature.objectid;
var sql = "OBJECTID = @oid";
var f = First(Filter(fs, sql));
var excludeflds = ['globalid', 'objectid', 'prueba', "x_coord","y_coord","EditDate","Editor"];
var flds = GetFieldNames(f, excludeflds);
var info = [];
var atts = {};
for (var i in flds) {
var fldname = flds[i];
if (!IsEmpty(f[fldname])) {
var alias = GetAlias(f, fldname);
Push (info, {'fieldName': alias})
if (HasDomain(f, fldname)) {
atts[alias] = DomainName(f, fldname);
} else {
atts[alias] = f[fldname];
}
}
}
return {
type: 'fields',
title: 'Detalles de la actividad',
description : '(con Arcade)',
fieldInfos: info,
attributes : atts
} In this case, I have a feature service that stores the results of a Survey with a lot of conditional questions. In order to avoid the empty (non-relevant) fields being showed in the pop-up, you can use this to only show those that have information. On line 33 you define the layer that you want to connect to and on line 37 I define a list of fields that I don't want to show.
... View more
05-02-2022
09:05 AM
|
0
|
0
|
8730
|
POST
|
HI @SSMGroup , ArcGIS Online is updated 4 times every years. To have a look at what has been updated in each version I recommend the blogs: https://www.esri.com/arcgis-blog/?s=#What%27s%20new%20arcgis%20online&products=arcgis-online There are also videos available on the ArcGIS Channel: https://www.youtube.com/playlist?list=PLGZUzt4E4O2IulSSoNHnpaprsxhbWPa3B The documentation will normally reflect the changes in the latest version: https://doc.arcgis.com/en/arcgis-online/reference/whats-new.htm
... View more
05-02-2022
08:56 AM
|
0
|
1
|
1058
|
POST
|
Hi @EfeUngun , A couple of thoughts on the subject. There is a ISOWeekday function: Returns the day of the week of the given date, based on the ISO 8601 standard. Values range from 1-7 where Monday is 1 and Sunday is 7. However, if you believe that statistics are shifted, it might be good to have a look at the data and especially the dates. Normally dates are stored in UTC time and when working with dates it will take into account your timezone to work with the dates correctly. If the data was loaded into a featureservice this might be something to validate. It is possible to use ToLocal or ToUTC functions to alter the date (or a personalized DateAdd function) before creating the statistics but it takes some validation to be sure that the outcome is correct.
... View more
04-27-2022
02:32 PM
|
0
|
0
|
1052
|
POST
|
Hi @DanielShaffer2 , Just to clarify: "Your code examples above work great for Popups, but not within the Change Style dialogs. (OrderBy, Filter & FeatureSets are not available there). I was pretty much there already with popups." As I mentioned at the end of my previous response, the Arcade expression would be used in multiples Field Calculations and as you also confirmed will not be your first option. A scheduled Python Notebook is probably a lot better to accomplish the desired result. I recommend having a look at the path "Learn Python with ArcGIS Notebooks" Path: https://learn.arcgis.com/en/paths/learn-python-with-arcgis-notebooks/ , which should be available to you without cost. Here is an example of a Notebook that I have used in the past to update information in a featureset based on related data. # load libraries
from arcgis.gis import GIS
from copy import deepcopy
# create a connection to the active portal (AGOL)
gis = GIS("home")
# Item Added From Toolbar
# Title: ValvulasIBAL_v02 | Type: Feature Service | Owner: xbakker.spx
item = gis.content.get("00000000000000000000000000000000") # replace with your item ID
# I have a hosted service with one featureset and 1 table, that why I use 0 as index
flayer = item.layers[0]
tbl = item.tables[0]
print("features: {}".format(len(flayer.query(where="1=1"))))
print("records: {}".format(len(tbl.query(where="1=1"))))
# returns:
# - features: 58
# - records: 6
# function to determine the last state of the asset
def UltimoEstado(tbl, glob):
sql = "ParentGlobalID='{" + glob + "}'" # my query based in global ID
top_filter = {"topCount": 1, "orderByFields": "FechaCambio desc"} # filter definition, take top 1 when data is ordered by date (descending)
ts = tbl.query(where=sql, order_by_fields='FechaCambio DESC') # apply query to table
cnt = 0
estado = "Abierta" # if there is no related record, default to "Open" status for valve
if len(ts) > 0:
for row in ts:
if cnt == 0:
estado = row.attributes["EstadoValvula"] # read out the value from the field than contains the state of the asset
else:
# only take the first record for the most recent status
break
cnt += 1
return estado
# similar function to read out the last update date
def UltimaGestion(tbl, glob):
sql = "ParentGlobalID='{" + glob + "}'"
top_filter = {"topCount": 1, "orderByFields": "FechaCambio desc"}
ts = tbl.query(where=sql, order_by_fields='FechaCambio DESC')
cnt = 0
ultimagestion = None # if there is no related record, default date to None
if len(ts) > 0:
for row in ts:
if cnt == 0:
ultimagestion = row.attributes["FechaCambio"] # read out the value from the field than contains the date of the update
else:
# only take the first record for the most recent date
break
cnt += 1
return ultimagestion
# define a query to get all the features
fs = flayer.query(where="1=1")
# Loop to run through all the valves
actualizar_features = []
for feat in fs:
# read the globalID
glob = feat.attributes["GlobalID"]
# call the function llamar to get the last update from the related table (state and date)
estado = UltimoEstado(tbl, glob)
ultimagestion = UltimaGestion(tbl, glob)
# make a deep copy of the current feature
nuevo_feature = deepcopy(feat)
# update the values in the deepcopy
nuevo_feature.attributes['EstadoActual'] = estado
nuevo_feature.attributes['UltimaGestion'] = ultimagestion
# add the updated feature to a list
actualizar_features.append(nuevo_feature)
# update the featureset
flayer.edit_features(updates=actualizar_features) Make sure when you create a new notebook to select the "Standard" option to avoid unnecessary consumption of credits.
... View more
04-26-2022
03:53 PM
|
0
|
1
|
3206
|
Title | Kudos | Posted |
---|---|---|
1 | 2 weeks ago | |
1 | 03-18-2020 08:08 AM | |
1 | 09-25-2020 12:14 PM | |
1 | 05-22-2019 12:53 PM | |
1 | 03-12-2021 05:45 AM |
Online Status |
Offline
|
Date Last Visited |
Monday
|