I started playing with Tableau. My data looks like below.
I want to create Calculated Field that divides my viz by color. I've got problem with dealing with dates. As you can see variable Quarter consists quarters of each year. What I want is to get rid of those gaps. I know my calculated field is done wrong but I tried so many different options and none of them worked. Basically I want each President starts (for example Donald Trump) his president's seat at 01.01.2017 and finishes it at 31.12.2020.
How should I write it to actually work?
IF YEAR([Quarter]) >= 1981 and YEAR([Quarter]) <= 1989 then 'Ronald Reagan'
ELSEIF YEAR([Quarter]) >= 1989 and YEAR([Quarter]) <= 1993 then 'George H. W. Bush'
ELSEIF YEAR([Quarter]) >= 1993 and YEAR([Quarter]) <= 2001 then 'Bill Clinton'
ELSEIF YEAR([Quarter]) >= 2001 and YEAR([Quarter]) <= 2009 then 'George W. Bush'
ELSEIF YEAR([Quarter]) >= 2009 and YEAR([Quarter]) <= 2017 then 'Barack Obama'
ELSEIF YEAR([Quarter]) >= 2017 and YEAR([Quarter]) <= 2021 then 'Donald Trump'
END
The breaks you see in the line aren’t caused by your calculation, but here are two suggestions nonetheless - and some other tips.
Compare against complete dates, either using date literals (enclosed in # signs) or calling a function like MakeDate(). And you can simplify and speed up your calc by taking advantage of the knowledge that prior tests failed - I.e. to not repeat those tests, as shown below.
if [Quarter] < #01/20/1981# then ‘Historical’
elseif [Quarter] < #01/20/1989# then 'Ronald Reagan'
elseif [Quarter] < #01/20/1993# then 'George H. W. Bush'
elseif [Quarter] < #01/20/2001# then 'Bill Clinton'
elseif [Quarter] < #01/20/2009# then 'George W. Bush''
elseif [Quarter] < #01/20/2017# then 'Barack Obama'
elseif [Quarter] < #01/20/2021# then 'Donald Trump'
else ‘Joe Biden’
end
#AniGoyal’s suggestion to make a separate table and use a join is a good idea too, but the join calc won’t look like the one above - hint - it would have 2 tests
As to the gaps between marks ...
After you place this field on the color shelf, try changing its role from dimension to attribute (and back) to see which view you prefer. You could also directly drag the tiles in your color legend to sort them in chronological order.
Related
I am having a bit of tough time wrapping my head around this. I have a column based on response time in hours and our company's SLA (service level agreement) is that all incoming inquires should be answered within 2 days (the response time in hours is total hours spent on responding to inquiry).
The problem is that our company operates with winter time (7 h 45 min) and summer time (7 h). My dataset consist both and I want Power BI to differientiate winter and summer time when I try to compute SLA. In winter time 1 working day = 7 h 45 min and in summer time = 7 h. I have just used the average of summer/winter time = 7 h 30 min. The SLA column consist 3 data types, "Innen en arbeidsdag", "Innen to arbeidsdager" and "over 2 arbeidsdager".
My dataset is called 'Masterdata' and I have used this syntax so far:
SLA = SWITCH(TRUE(),Masterdata[Svartid i t]>15,
"Over to arbeidsdager", Masterdata[Svartid i t]>7.5,
"Innen to arbeidsdager", Masterdata[Svartid i t]<=7.5, "Innen en arbeidsdag")
my columns 'Svartid i t' (response time) 'SLA' is so far ok and looks like this:
Svartid i t SLA
6,12 Innen en arbeidsdag
11,73 Innen to arbeidsdager
20,42 Over to arbeidsdager
1,07 Innen en arbeidsdag
etc etc
But how can I use DATES in this syntax to tell Power BI that 'Svartid i t' (response time) YTD column from 15th May to 15th September is summer time, Working day = 7 h?
Summer time: 'Svartid i t' <= 7, "Innen en arbeidsdag", 'Svartid i t' > 7, "Innen to arbeidsdager", 'Svartid i t' > 14, "Over to arbeidsdager"
Winter time: 'Svartid i t' <= 7.75, "Innen en arbeidsdag", 'Svartid i t' > 7.75, "Innen to arbeidsdager", 'Svartid i t' > 15.5, "Over to arbeidsdager"
You can use this formula:
VAR hours =
IF( (MONTH(MasterData[YTD]) >= 5 && DAY(MasterData[YTD]) >= 15)
&& (MONTH(MasterData[YTD]) <= 9 && DAY(MasterData[YTD]) <= 15),
7, 7.45 )
RETURN
SWITCH (
TRUE (),
Masterdata[Svartid i t] > 2 * hours, "Over to arbeidsdager",
Masterdata[Svartid i t] > hours, "Innen to arbeidsdager",
Masterdata[Svartid i t] <= hours, "Innen en arbeidsdag"
)
Make sure to put it in a calculated column. Your sample data is not suitable to verify the formula, so I changed it. But the result will look like this:
I have dates that look like "17-JAN-19", "18-FEB-20". When I attempt to use the Dates package Date("17-JAN-19", "d-u-yy") I get reasonably 0019-01-17. I could do Date("17-JAN-19", "d-u-yy") + Year(2000) but that introduces the possibility of new errors (I was going to give the example of leap year but that generally works though there is the very rare error Date("29-FEB-00", "d-u-yy")+Year(1900)).
Is there a date format that embeds known information about century?
As mentioned in https://github.com/JuliaLang/julia/issues/30002 there are multiple heuristics for assigning the century to a date. I would recommend being explicit and handling it through a helper function.
const NOCENTURYDF = DateFormat("d-u-y")
"""
parse_date(obj::AbstractString,
breakpoint::Integer = year(now()) - 2000,
century::Integer = 20)
Parses date in according to DateFormat("d-u-y") after attaching century information.
If the year portion is greater that the current year,
it assumes it corresponds to the previous century.
"""
function parse_date(obj::AbstractString,
breakpoint::Integer = year(now()) - 2000,
century::Integer = 20)
# breakpoint = year(now()) - 2000
# century = year(now()) ÷ 100
#assert 0 ≤ breakpoint ≤ 99
yy = rpad(parse(Int, match(r"\d{2}$", obj).match), 2, '0')
Date(string(obj[1:7],
century - (parse(Int, yy) > breakpoint),
yy),
NOCENTURYDF)
end
parse_date("17-JAN-19")
parse_date("29-FEB-00")
So I have a chart that looks like this:
Here is what I have in the chart expert:
And here is the code for #ZZ_TAT_Name - A:
if {IB_MESSAGES.MSG_ID} = next({IB_MESSAGES.MSG_ID}) and {IB_MESSAGES.MSG_ID} = previous({IB_MESSAGES.MSG_ID}) then "na" else
IF {#Final Turnaround Minutes} > 0 and {#Final Turnaround Minutes} < 15 THEN "UNDER 15"
ELSE IF {#Final Turnaround Minutes} >= 15 and {#Final Turnaround Minutes} < 30 THEN "BETWEEN 15 & 30"
ELSE IF {#Final Turnaround Minutes} >= 30 and {#Final Turnaround Minutes} < 60 THEN "BETWEEN 30 & 60"
ELSE if {#Final Turnaround Minutes} > 60 then "OVER 60"
//else "*Total Messages"
I am wanting to get rid of the riser that shows 11. That riser is the total DistinctCount of IB_MESSAGES.MSG_ID. How would I be able to remove this? Why is this even showing up?
From what you've mentioned below, it seems 11 out of 22 records appear to fall into none of the if-else categories, leading to the unlabeled blue column. The easiest way to proceed is to intervene before the chart is rendered and reduce the incoming data to only values that belong in the other columns:
There's a few ways to handle this, but I would recommend adding an intermediary Formula that returns the exact same records, except any record that doesn't meet the if/else standards will be replaced with null. Something like:
IF (
{IB_MESSAGES.MSG_ID} = next({IB_MESSAGES.MSG_ID})
AND
{IB_MESSAGES.MSG_ID} = previous({IB_MESSAGES.MSG_ID})
)
OR (
{#Final Turnaround Minutes} > 0
AND
{#Final Turnaround Minutes} > 60
)
THEN
//repeat the original value here
ELSE
null
Done correctly, the intermediary formula will return 11 records and 11 nulls when evaluated in the Details section of the report. From here, you can change your chart to read the formula and it should evaluate only 11 non-null values.
i hope, that here there is specialist of clementine or IBM SPSS MODELER.
My question: How use Clem expression to transform date?
For example i have this format of date
27.10.15.15:05
27.10.15.15:45
27.10.15.16:10
if the date value < 30 then, round to 1 min
i.e. not 15:05, but 15:01 , if the date value > 30 min then, round to 31 min, i.e. not 15:45, but 15:31. What about 16:10, since it < 16:30 then, round to 16:01.
generally speaking date must be in the follow format
27.10.15.15:01
27.10.15.15:31
27.10.15.16:01
One man told me, that it's should to use this expression datetime_in_seconds(?)
But i really don't know how use it. Please help me to transform this date in needed for me format
I resolved this problem. Maybe anyone needs in this desicion.
Modeler has uncomfortable possibilities for data transformation
if (abs(time_mins_difference(datetime_time(time), datetime_time(datetime_hour(time), 1, 0))) < 15) then
datetime_timestamp(datetime_year(time), datetime_month(time), datetime_day(time), datetime_hour(time), 1, datetime_second(time))
else if (abs(time_mins_difference(datetime_time(time), datetime_time(datetime_hour(time), 1, 0))) > 15) and (abs(time_mins_difference(datetime_time(time), datetime_time(datetime_hour(time), 1, 0))) < 45) then
datetime_timestamp(datetime_year(time), datetime_month(time), datetime_day(time), datetime_hour(time), 31, datetime_second(time))
else
datetime_timestamp(datetime_year(time), datetime_month(time), datetime_day(time), datetime_hour(time)+1, 1, datetime_second(time))
endif
endif
I have a variable with a date table that looks like this
* table:
[day]
* number: 15
[year]
* number: 2015
[month]
* number: 2
How do I get the days between the current date and the date above? Many thanks!
You can use os.time() to convert your table to seconds and get the current time and then use os.difftime() to compute the difference. see Lua Wiki for more details.
reference = os.time{day=15, year=2015, month=2}
daysfrom = os.difftime(os.time(), reference) / (24 * 60 * 60) -- seconds in a day
wholedays = math.floor(daysfrom)
print(wholedays) -- today it prints "1"
as #barnes53 pointed out could be off by one day for a few seconds so it's not ideal, but it may be good enough for your needs.
You can use the algorithms gathered here:
chrono-Compatible Low-Level Date Algorithms
The algorithms are shown using C++, but they can be easily implemented in Lua if you like, or you can implement them in C or C++ and then just provide Lua bindings.
The basic idea using these algorithms is to compute a day number for the two dates and then just subtract them to give you the number of days.
--[[
http://howardhinnant.github.io/date_algorithms.html
Returns number of days since civil 1970-01-01. Negative values indicate
days prior to 1970-01-01.
Preconditions: y-m-d represents a date in the civil (Gregorian) calendar
m is in [1, 12]
d is in [1, last_day_of_month(y, m)]
y is "approximately" in
[numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366]
Exact range of validity is:
[civil_from_days(numeric_limits<Int>::min()),
civil_from_days(numeric_limits<Int>::max()-719468)]
]]
function days_from_civil(y, m, d)
if m <= 2 then
y = y - 1
m = m + 9
else
m = m - 3
end
local era = math.floor(y/400)
local yoe = y - era * 400 -- [0, 399]
local doy = math.modf((153*m + 2)/5) + d-1 -- [0, 365]
local doe = yoe * 365 + math.modf(yoe/4) - math.modf(yoe/100) + doy -- [0, 146096]
return era * 146097 + doe - 719468
end
local reference_date = {year=2001, month = 1, day = 1}
local date = os.date("*t")
local reference_days = days_from_civil(reference_date.year, reference_date.month, reference_date.day)
local days = days_from_civil(date.year, date.month, date.day)
print(string.format("Today is %d days into the 21st century.",days-reference_days))
os.time (under Windows, at least) is limited to years from 1970 and up. If, for example, you need a general solution to also find ages in days for people born before 1970, this won't work. You can use a julian date conversion and subtract between the two numbers (today and your target date).
A sample julian date function that will work for practically any date AD is given below (Lua v5.3 because of // but you could adapt to earlier versions):
local
function div(n,d)
local a, b = 1, 1
if n < 0 then a = -1 end
if d < 0 then b = -1 end
return a * b * (math.abs(n) // math.abs(d))
end
--------------------------------------------------------------------------------
-- Convert a YYMMDD date to Julian since 1/1/1900 (negative answer possible)
--------------------------------------------------------------------------------
function julian(year, month, day)
local temp
if (year < 0) or (month < 1) or (month > 12)
or (day < 1) or (day > 31) then
return
end
temp = div(month - 14, 12)
return (
day - 32075 +
div(1461 * (year + 4800 + temp), 4) +
div(367 * (month - 2 - temp * 12), 12) -
div(3 * div(year + 4900 + temp, 100), 4)
) - 2415021
end