Compare Date in Condition [Vega-Lite] - datetime

I'm super new to this and trying out Observable and Vega-Lite for the first time. The following code works when the datum is a quantitative string but not when it's a date.
vl.color({"condition":{"test":"datum['dateAnnounced']<'2020-03-15'","value":"black"}, "value":"red"})
Can someone show me the correct way to compare Date fields, please? Thanks in advance!

condition.test accepts Predictate. It has string format which you're using, but also it could be an object like this:
condition: {
test: {
field: 'dateAnnounced', // your date field
lt: { year: 2020, month: 3, date: 15 } // 'less than' a date in Vega DateTime format
}
}
They call this object "field predicate". It has field prop and a comparison operator lt or gt or equal, etc.
There are some examples from Field Predicate section of the doc:
{"field": "car_color", "equal": "red"} // car_color === red
{"field": "height", "lt": 180} // height < 180
{"field": "date", // 2006-01-01 < date && date < 2008-02-20
"range": [
{"year": 2006, "month": "jan", "date": 1},
{"year": 2008, "month": "feb", "date": 20}
]
}

Related

iterate an array with conditions such that certain elements can be revisited multiple time

For the input below:
{
"vals": [
{
"month": "Jan 2022",
"value": 0,
"amount": -200,
"date": "01-02-2022"
},
{
"month": "Feb 2022",
"value": 0,
"amount": -200,
"date": "28-02-2022"
}
],
"items": [
{
"date": "01-02-2022",
"amount": -200
},
{
"date": "04-02-2022",
"amount": 100
},
{
"date": "28-02-2022",
"amount": -200
},
{
"date": "10-03-2022"
"amount": 250
},
{
"date": "12-03-2022"
"amount": 50
}
]
}
I want the below output
{
"vals": [
{
"month": "Jan 2022",
"value": 37
},
{
"month": "Feb 2022",
"value": 12
}
]
}
for month "Jan 2022" of vals, we have debit amount on 01-02-2022. So need go through the items arrays from 01-02-2022 till the total sum of amount matches with vals "Jan 2022" amount value and we need to the no of days between i.e. 01-02-2022 and 10-03-2022
for month "Feb 2022" instead of going through items array again from first we should continue where we left for Jan 2022.
{
"date": "10-03-2022"
"amount": 250
}
of this item 100 is considered for Jan 2022 and 150 is considered for Feb 2022.
so I need to loop items array such that I should continue where I left for an element of vals array.
{
"date": "10-03-2022"
"amount": 250
}
this element of items array should be considered twice once for Jan 2022 and second for Feb 2022
But
{
"date": "04-02-2022"
"amount": 100
}
should considered only once as the 100 will not completely serve Jan 2022 amount i.e. -200
I hope I made it clear.
Unfortunately there are some aspects of the problem which I do not understand, but the following should help as it addresses the key need:
I need to loop items array such that I should continue where I left for an element of vals array.
The key to doing this cleanly is to define a helper function which allows us to keep track of where to resume the search:
# input: [ $index, $array ] where $index is null or >= -1
# output: the first index, $i, in the array for which
# $i > $index and $array[$i].amount == $v , or else null
def value($v):
. as [ $index, $array ]
| if $index == null then null
else first( range($index + 1; $array|length) | select($array[.].amount == $v) ) // null
end ;
For computing the number of days between two dates, another helper function will be useful:
# Date format: dd-mm-year
def days($finish; $start):
[$finish, $start]
| map(strptime("%d-%m-%Y") | mktime) # seconds
| (.[0] - .[1]) / 86400 + 0.5 | trunc ;
Now we have simply to build up the result by visiting the elements of .vals:
.items as $items
| reduce .vals[] as $val ({ix: 0, date: .vals[0].date, array: []};
([.ix, $items] | value($val.amount)) as $ix
| .ix = $ix
| if $ix == null
then .
else .date as $date
| .array += [$val | {month, value: days($items[$ix].date; $date) }]
| .date = $date
end )
As already stated, this is probably not exactly what you want, but should provide a suitable framework for you.

How can I change date formats "2022-06-04T00:00:00.000Z" to "1525844100000" for react highcharts

I've the following date: "2022-06-04T00:00:00.000Z" format, We've need of date calculation for highcharts in this numeric type format "1525844100000" so how can I calculate in react-highcharts
xAxis: {
type: 'datetime',
ordinal: false,
startOnTick: false,
endOnTick: false,
minPadding: 0,
maxPadding: 0,
Date: false,
tickInterval: 4 3600 1000,
minRange: 1 24 3600000,
dateTimeLabelFormats: {
day: '%l %P',
hour: '%l %P'
},
offset: 0,
},
series: [
{
"data": [[1.424304e+12, 0.25]],
color: '#FFA749',
},
],
"highcharts": "^6.1.1",
"react-highcharts": "^16.0.2",
I've given above my charts details
In order to convert ISO-8601 to timestamp format, use getTime() JS method.
let timestamp = new Date('2022-06-04T00:00:00.000Z').getTime()
// expected output: 1654300800000
Demo: https://jsfiddle.net/BlackLabel/vnLdum1k/

Create multi-line chart on Kibana vega with legend based on inner buckets key values

I had a query response providing the data of format
{
"key_as_string": "2022-02-28T00:00:00.000Z",
"key": 1646006400000,
"doc_count": 2070,
"count": {
"doc_count": 3992,
"categories_count": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 1,
"doc_count": 3070
},
{
"key": 5,
"doc_count": 316
},
{
"key": 3,
"doc_count": 178
},
{
"key": 0,
"doc_count": 26
},
{
"key": 7,
"doc_count": 26
},
{
"key": 6,
"doc_count": 20
},
{
"key": 2,
"doc_count": 10
}
]
}
}
}
How do I create a multi-line chart with legends that based each key value as one line and
y-axis is the doc_count and x-axis is the key_as_string time. I also need to handle the case that inner buckets will not output empty key count (missing key values that have count 0), but the key can be only in range of 0-7.
To create a multi-line chart refer to the gallery. This is a line chart. My advice, look around the gallery for things you want to include in your visualisation and extract those pieces, don't forget to refer to the documentation too.
For the 0 bucket, this is something I've encountered before. Try doing the term aggregation before the date_histogram aggregation. The date_histogram aggregation produces buckets for 0 counts whereas the term does not.

Conditional if/then/else for JMESPath?

Am trying to do a simple if/then/else using JMESPath
For example: 'if the input is a string, return the string, else return the "value" property of the input'. An input of "abc" would return "abc". An input of {"value":"def"} would return "def"
With jq this is easy: if .|type == "string" then . else .value end
With JMESPath, I can get the type
type(#)
or the input:
#
or the value property:
value
but I have not found a way to combine them into an if-then-else. Is there any way to do this?
It is possible but not cleanly. The general form is to:
Make the value you are testing an array (wrap in square braces)
Apply the map function to map the filtered array to what value you want if true
At this point you have an array that is populated with one (true) item if the array filter passed, otherwise it is empty
Concat to that array one item (the false value)
Finally, take item at index 0 in this array - which will be the result of the condition
This should allow you to also derive possible transformations for both the false and true conditions
For example, if the test data is as so:
{
"test": 11
}
Depending on the value you can get either produce the results (using test data 11 and 2 as example):
"Yes, the value is 11 which is greater than 10"
OR
"No the value is 2 which is less than or equal to 10"
Like so:
[
map(
&join(' ', ['Yes, the value is', to_string(#), 'which is greater than 10']),
[test][? # > `10`]
),
join(' ', ['No the value is', to_string(test), ' which is less than or equal to 10'])
][] | #[0]
So to abstract a template:
[
map(
&<True Expression Here>,
[<Expression you are testing>][? # <Test Expression>]
),
<False Expression Here>)
][] | #[0]
people[?general.id !=100] || people
{
"people": [
{
"general": {
"id": 100,
"age": 20,
"other": "foo",
"name": "Bob"
},
"history": {
"first_login": "2014-01-01",
"last_login": "2014-01-02"
}
},
{
"general": {
"id": 101,
"age": 30,
"other": "bar",
"name": "Bill"
},
"history": {
"first_login": "2014-05-01",
"last_login": "2014-05-02"
}
}
]
}
if else condition works here

Convert timezone specific date to locale using moment

I have the following data for a timezone:
{
"Id": "Pacific Standard Time",
"DisplayName": "(UTC-08:00) Pacific Time (US & Canada)",
"StandardName": "Pacific Standard Time",
"DaylightName": "Pacific Daylight Time",
"BaseUtcOffset": "-08:00:00",
"AdjustmentRules": [{
"DateStart": "0001-01-01T00:00:00Z",
"DateEnd": "2006-12-31T00:00:00Z",
"DaylightDelta": "01:00:00",
"DaylightTransitionStart": {
"TimeOfDay": "0001-01-01T02:00:00Z",
"Month": 4,
"Week": 1,
"Day": 1,
"DayOfWeek": 0,
"IsFixedDateRule": false
},
"DaylightTransitionEnd": {
"TimeOfDay": "0001-01-01T02:00:00Z",
"Month": 10,
"Week": 5,
"Day": 1,
"DayOfWeek": 0,
"IsFixedDateRule": false
},
"BaseUtcOffsetDelta": "00:00:00"
}, {
"DateStart": "2007-01-01T00:00:00Z",
"DateEnd": "9999-12-31T00:00:00Z",
"DaylightDelta": "01:00:00",
"DaylightTransitionStart": {
"TimeOfDay": "0001-01-01T02:00:00Z",
"Month": 3,
"Week": 2,
"Day": 1,
"DayOfWeek": 0,
"IsFixedDateRule": false
},
"DaylightTransitionEnd": {
"TimeOfDay": "0001-01-01T02:00:00Z",
"Month": 11,
"Week": 1,
"Day": 1,
"DayOfWeek": 0,
"IsFixedDateRule": false
},
"BaseUtcOffsetDelta": "00:00:00"
}],
"SupportsDaylightSavingTime": true
}
and the following date:
2019-01-05T07:30:07Z
Using moment, i'd like to convert this to my current locale which is
en-GB
How do i go about doing this with momentjs?
the problem seems to be that the date format i have is not compatible with moment.
I've prepared a jsfiddle with variables that i have access to:
http://jsfiddle.net/jimmyt1988/xe7ha5ms/1/
Your input is in ISO 8601 format recognized by moment. You can parse it using moment.tz:
The moment.tz constructor takes all the same arguments as the moment constructor, but uses the last argument as a time zone identifier.
then you can convert it to desired timezone using tz():
The moment#tz mutator will change the time zone and update the offset.
You can set locale on a moment object using locale() and then use format() to display value.
Here a code sample:
console.log(
moment.tz('2019-01-05T07:30:07', 'America/Los_Angeles') // parse input in given tz
.tz('Europe/London') // Convert moment to desired zone
.locale('en-gb') // set en-gb locale
.format('LLLL') // display result
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.23.0/moment-with-locales.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data-2012-2022.min.js"></script>
Figured it out, by using the utcOffset method:
http://jsfiddle.net/jimmyt1988/xe7ha5ms/2/
moment("2019-01-05T07:30:07Z")
.utcOffset("-08:00:00")
.format("DD/MM/YYYY HH:mm:ss");

Resources