Power BI Desktop add the value of two rows by Staff Name - powerbi-desktop

I want to add the value for two rows for a specific StaffName and Allowance. the Allowance types are "R-02 - Research Component for HDR supervision" and "R-03 - Research". So for the following example:
Acuna = 70, Agosti = 290 and Akagi = 22
I will then compare this value to ensure it is less than 40% of their FTE.

I have found:
Measure = calculate(sum('sdowner SPV_REP_PERSONALTAB'[Total]),FILTER(ALL('sdowner SP_ALLOWANCETYPE'),'sdowner SP_ALLOWANCETYPE'[Allowance]="R-02 - Research Component for HDR supervision")) + calculate(sum('sdowner SPV_REP_PERSONALTAB'[Total]),FILTER(ALL('sdowner SP_ALLOWANCETYPE'),'sdowner SP_ALLOWANCETYPE'[Allowance]="R-03 - Research"))
This gives me:
So now I need to figure out how to only display the Measure for the last row of each name. I tried this:
Measure 2 = if(containsstring(min('sdowner SP_ALLOWANCETYPE'[Allowance]), "R-03 - Research"),calculate(sum('sdowner SPV_REP_PERSONALTAB'[Total]),FILTER(ALL('sdowner SP_ALLOWANCETYPE'),'sdowner SP_ALLOWANCETYPE'[Allowance]="R-02 - Research Component for HDR supervision")) + calculate(sum('sdowner SPV_REP_PERSONALTAB'[Total]),FILTER(ALL('sdowner SP_ALLOWANCETYPE'),'sdowner SP_ALLOWANCETYPE'[Allowance]="R-03 - Research")), "")
However that gave me:
So I applied a filter to Total greater than zero. To give me:

Related

PowerBi - Two Measures to show in one card

I was reviewing a video on line and the video had a card with two measures. I took a screenshot:
There is the main one: Total Sales and a sub measurement: Target sales. How can I get two measures into one card? So whoever is looking at this dashboard can see that the current total sales is this and the target is this.
you can try this in you measure :
My_measure =
var total_sales = *do some calculations*
var target_sales = *do some calculations*
return
total_sales & UNICHAR(10) & target_sales
You can also check this link
Concatenate text with newlines in PowerBI
To know more about UNICHAR()
https://learn.microsoft.com/en-gb/dax/unichar-function-dax

extremely slow add a table to python-docx from a csv file

I have to add a table from a CSV file around 1500 rows and 9 columns, (75 pages) in a docx word document. using python-docx.
I have tried differents approaches, reading ths csv with pandas or directly openning de csv file, It cost me around 150 minutes to finish the job independently the way I choose
My question is if this could be normal behavior or if exist any other way to improve this task.
I'm using this for loop to read several cvs files and parsing it in table format
for toTAB in listBRUTO:
df= pd.read_csv(toTAB)
# add a table to the end and create a reference variable
# extra row is so we can add the header row
t = doc.add_table(df.shape[0]+1, df.shape[1])
t.style = 'LightShading-Accent1' # border
# add the header rows.
for j in range(df.shape[-1]):
t.cell(0,j).text = df.columns[j]
# add the rest of the data frame
for i in range(df.shape[0]):
for j in range(df.shape[-1]):
t.cell(i+1,j).text = str(df.values[i,j])
#TABLE Format
for row in t.rows:
for cell in row.cells:
paragraphs = cell.paragraphs
for paragraph in paragraphs:
for run in paragraph.runs:
font = run.font
font.name = 'Calibri'
font.size= Pt(7)
doc.add_page_break()
doc.save('blabla.docx')
Thanks in advance
You'll want to minimize the number of calls to table.cell(). Because of the way cell-merging works, these are expensive operations that really add up when performed in a tight loop.
I would start with refactoring this block and see how much improvement that yields:
# --- add the rest of the data frame ---
for i in range(df.shape[0]):
for j, cell in enumerate(table.rows[i + 1].cells):
cell.text = str(df.values[i, j])
python-docx walk the whole table every single time you access its "cells" property.
so you better call ".cell" as less as possible and use a cache for cells instead.
these are two examples access a table with size 3*1500:
code 1: about 150.0s
for row in table.rows:
print('processing: {0:30s}'.format(row.cells[0].text),end='\r')
code 2: about 1.4s
clls=table._cells
for row_idx in range(len(clls)//table._column_count):
print('processing: {0:30s}'.format(
clls[0 + row_idx*table._column_count].text),end='\r')
clls=table._cells in code 2 use "_cells" to process the cell-merging, so ccls[column_idx + row_idx*table._column_count].text works just as fine as table.rows[row_idx].cells[column_idx].text, and dont require table to be exactly rectangular
For rectangular table without merged cells you can export all cells into list-of-lists structure and fill them very quickly (less then 0.5s vs 15s for ~300 lines tables with 3 columns):
from docx.table import _Cell
def get_cells_grid(table):
cells = [[]]
col_count = table._column_count
for tc in table._tbl.iter_tcs():
cells[-1].append(_Cell(tc, table))
if len(cells[-1]) == col_count:
cells.append([])
return cells
cells = get_cells_grid(t)
for i in range(df.shape[0]):
for j in range(df.shape[i]):
cells[i][j].text = str(df.values[i, j])
Function based on table._cells() code: https://github.com/python-openxml/python-docx/blob/da75fcf01f7f322e846e2ac3e1936aedd766acc8/docx/table.py#L162
Just to add my experience, if you have to create a huge table, create the whole structure first, meaning all the rows and cells you will need; and then store the cells like so
table_cells = table._cells (according to #kztopia)
And from there you can manipulate cells as you wish, merging, adding text etc... with a rather optimized fastness since you make only one call to cell()
In my use case, for a table being, in my opinion, not so big (~130rows, 8cells per row), it used to take 9sec to create the whole thing and now i'm at .5 or so.
Keep in mind that, the bigger the table, the more time it'll take to execute cell().

Convert long formula into an ARRAYFORMULA

Document: https://docs.google.com/spreadsheets/d/1N4cGw5eUq_3gCJh1w39qVatX9KV1_Hr-AqRHj_nbckA/edit#gid=1770960621
Question
How can I convert the following simple formulas at Schedule!C20:I29 into a single, simple ARRAYFORMULA at Schedule!C20?
=Count(Filter(Students!$B$5:$B, Find(C6, Filter(Students!$J$5:$O,Students!$J$4:$O$4 = 'Current Class'!$B$3))))
.
NOTE:
The above code is only a partial solution. I will substitute the ARRAYFORMULA version of the code into the correct part of the code at Current Class!L6
The C6 reference above can take on any cell between Schedule!C6:I15. I have named that range Timetable_Code. I thought I could do the following, but I was wrong...
=Arrayformula(Count(Filter(Students!$B$5:$B, Find(Timetable_Code, Filter(Students!$J$5:$O,Students!$J$4:$O$4 = 'Current Class'!$B$3)))))
Background
Originally, I created a table that now resides at 1st Version - Current Class!L6. This tab is only for your reference and will be deleted soon. Each cell has a formula with a slight modification. This formula works correctly; however, it is a behemoth and would be hard to modify...
=if(COUNTIF(Meta!$B$5:$B, CONCATENATE("=",if(L$5 = "THURSDAY", "TH", if(L$5 = "SUNDAY", "SU", left(L$5,1))), if(left($K6, 2) = "12", 0, left($K6, 1)))), CONCATENATE(if(L$5 = "THURSDAY", "TH", if(L$5 = "SUNDAY", "SU", left(L$5,1))), if(left($K6, 2) = "12", 0, left($K6, 1)), " ( ", Count(Filter(Students!$B$5:$B, Find(CONCATENATE(if(L$5 = "THURSDAY", "TH", if(L$5 = "SUNDAY", "SU", left(L$5,1))), if(left($K6, 2) = "12", 0, left($K6, 1))), Filter(Students!$J$5:$O,Students!$J$4:$O$4 = $B$3)))), " )") ,"")
.
Pros
I don't have to create any helper data.
All calculations are "in-memory"
Cons
Too large
Hard to modify
I like the output, but I don't like the cons, so I started to create a more edit-friendly version of the code that I am mostly OK with. This code is located at Current Class!L6 (and a secondary copy at Schedule!C33 - it will be deleted.) It has a single formula at Current Class!L6...
=arrayformula(if(COUNTIF(Meta!$B$5:$B, ("=" & Timetable_Code)), (Timetable_Code & " ( " & Timetable_StudentCount & " )") ,""))
.
Pros
Very easy to understand
Very easy to modify
No need to copy formula over to other cells
Cons
Two ( 2 ) helper tables were created ( one of which I think is unneeded)
Again, I like the output, but I really don't like the second helper table (Schedule!C20). I feel like this table can be eliminated, but I have not been able to figure out how.
If you really want to use arrayformula, here it is. For Schedule!C20.
=arrayformula((len(concatenate(index(Students!J5:O, , match('Current Class'!$B$3, Students!J4:O4, 0))))-len(substitute(concatenate(index(Students!J5:O, , match('Current Class'!$B$3, Students!J4:O4, 0))),C6:I15,"")))/len(C6:I15))
Probably you can use filter(as you did before) instead of index & match part, but I prefer index & match and don't want to dig more. Also you can use one help cell to store filter or index & match result to shorten the formula.
The core idea is from counting occurrences of given character in a string, ie len(a1) - len(substitute(a1, .... You can find many documents about it in the net.
Anyway, if I were you, I'd be satified with the current state. Just lock and hide the help tables or sheets. Nobody cares hidden sheets and if something bad happens, you can revert any change.
After getting a good answer from #Sangbok Lee, I decided to break apart each part of the function he gave to me. While doing that I found a highly unlikely connection to some work I did in the Google Sheets last week. A helper column I had in another tab kind of did what Sangbok Lee was trying to do. All I had to do was split that helper column into two columns (1 for the previous final calculation, 1 for) and calculate an additional count column
After reworking both of our formulas, and testing the result, I found a solution that I am even more satisfied with!
=arrayformula(if(countif(Meta!$B$5:$B, (Timetable_Code)), (Timetable_Code & " ( " & vlookup(Timetable_Code, StudentCount_Lookup, 2, false) & " )") ,""))
.
Check out the differences in the Google Sheet
Look at 1st Version - Current Class!L6 tab for the 1st version
Look at Current Class!L6 for the 2nd version
Look at Current Class!U6 for the 3rd and final version
Also look at tab Meta and Schedule for the differences.
Note: Green is old data, Red is new data

Matlab Data Preprocessing and Dynamic Struct Assignments

I'm quite new to Matlab and I'm struggling trying to figure out how to properly preprocess my data in order to make some calculations with it.
I have an Excel table with financial log returns of many companies such that every row is a day and every column is a company:
I imported everything correctly into Matlab like this:
Now I have to create what's caled "rolling windows". To do this I use the following code:
function [ROLLING_WINDOWS] = setup_returns(RETURNS)
bandwidth = 262;
[rows, columns] = size(RETURNS);
limit_rows = rows - bandwidth;
for i = 1:limit_rows
ROLLING_WINDOWS(i).SYS = RETURNS(i:bandwidth+i-1,1);
end
end
Well if I run this code for the first column of returns everything works fine... but my aim is to produce the same thing for every column of log returns. So basically I have to add a second for loop... but what I don't get is which syntax I need to use in order to make that ".SYS" dynamic and based on my array of string cells containing company names so that...
ROLLING_WINDOWS(i)."S&P 500" = RETURNS(i:bandwidth+i-1,1);
ROLLING_WINDOWS(i)."AIG" = RETURNS(i:bandwidth+i-1,2);
and so on...
Thanks for your help guys!
EDIT: working function
function [ROLLING_WINDOWS] = setup_returns(COMPANIES, RETURNS)
bandwidth = 262;
[rows, columns] = size(RETURNS);
limit_rows = rows - bandwidth;
for i = 1:limit_rows
offset = bandwidth + i - 1;
for j = 1:columns
ROLLING_WINDOWS(i).(COMPANIES{j}) = RETURNS(i:offset, j);
end
end
end
Ok everything is perfect... just one question... matlab intellissense tells me "ROLLING_WINDOWS appears to change size on every loop iteration bla bla bla consider preallocating"... how can I perform this?
You're almost there. Use dynamic field names by building strings for fields. Your fields are in a cell array called COMPANIES and so:
function [ROLLING_WINDOWS] = setup_returns(COMPANIES, RETURNS)
bandwidth = 262;
[rows, columns] = size(RETURNS);
limit_rows = rows - bandwidth;
%// Preallocate to remove warnings
ROLLING_WINDOWS = repmat(struct(), limit_rows, 1);
for i = 1:limit_rows
offset = bandwidth + i - 1;
for j = 1:columns
%// Dynamic field name referencing
ROLLING_WINDOWS(i).(COMPANIES{j}) = RETURNS(i:offset, j);
end
end
end
Here's a great article by Loren Shure from MathWorks if you want to learn more: http://blogs.mathworks.com/loren/2005/12/13/use-dynamic-field-references/ ... but basically, if you have a string and you want to use this string to create a field, you would do:
str = '...';
s.(str) = ...;
s is your structure and str is the string you want to name your field.

Populate Drop Down List Box (DDLB) with two values in PowerBuilder

I've created a Drop Down List Box (DDLB) in my window (I'm using PowerBuilder 10.5). Once I would call my function, the DDLB would fill with all the different cities from my table. This is the code I've used:
FOR li_i=1 TO ii_br_red
ls_city = dw_city.GetItemString(li_i, 'city')
IF ddlb_city.FindItem(ls_city, 1) = -1 THEN
ddlb_city.AddItem(ls_city) END IF; NEXT
Next part of the code is in the ddlb "selectionchanged" event...
dw_city.SetFilter("city = '" + this.text + "'")
dw_city.Filter()
This works great, and after calling my function (via click on a command button) I'd get a list of all different cities in my table, ex.
Paris
London
New York
Washington
No town would be listed twice.
What I need to do now is add a country next to every city in my DDLB. So that after clicking my command button I would get this in my DDLB:
Paris (France)
London (GB)
New York (USA)
Washington (USA)
Any advice? Thanks in advance...
SECOND QUESTION, similar to this subject: I have an SQL code:
SELECT distinct name FROM table1;
This gives me 8 different names. What I want to do is fill another DDLB, ddlb_1 with these names, but this must occur on the open event of my program. This is what I've written in the open event of my program:
string ls_name
SELECT distinct name INTO :ls_name FROM tabel1;
ddlb_1.AddItem(ls_name)
But this only gives me the first name. I'm guessing I need some kind of count, but I just can't pull it off.
If you do not want to change the design of the program, and as you states that the country is in the same DW, you could hack the code a little to add the country to the ddlb (I suppose that the country is available on the same row of the dw):
String ls_country
FOR li_i=1 TO ii_br_red
ls_city = dw_city.GetItemString(li_i, 'city')
IF ddlb_city.FindItem(ls_city, 1) = -1 THEN
ls_country = dw_city.GetItemString(li_i, 'country')
ddlb_city.AddItem(ls_city + ' (' + ls_country + ')')
END IF
NEXT
A quick and dirty hack to get back the value in the event to filter the DW would be
int p
string ls_city
ls_city = this.text
p = pos(ls_city, '(')
if p > 0 then ls_city = left(ls_city, p - 2) //skip the "space + (country)" part
dw_city.SetFilter("city = '" + ls_city + "'")
dw_city.Filter()
But this kind of code is difficult to maintain and should be replaced by something else, as the processing of the city value is strongly coupled to its representation in the list.
A better solution would be a dropdowndatawindow, or (worse) an array of the cities names where the index of a city + country in the ddlb would correspond to the index of the bare city name suitable for filtering the DW
I think you should modify the "source" datawindow' select, and you should get the final result which you want, and you would only need to copy the datas from the datawindow to the ddlb. You should use distinct in the select something like this:
select distinct city + ' (' + country_code + ')' from cities_and_countries_table
of course you should replace the "city", "country_code" to the actual column name in your table as well the table-name. With this you will get every city only once and they will be already concatenated with the country code.
Br. Gábor
Does it really have to be DDLB? I would give the user a Single Line Edit for the city name and filter the DW as the user types.
To answer my own second question, this is how I've done it finally...
String ls_name
DECLARE xy CURSOR FOR
SELECT distinct name FROM table1;
OPEN xy;
FETCH xy INTO :ls_name;
do until sqlca.sqlcode <> 0
ddlb_1.AddItem(ls_name);
FETCH xyINTO :ls_name;
loop
CLOSE xy;
I'm new to PowerBuilder, But I just used that kind of scenario, however I used a DDW (Drop Down Data Window) Instead of a List Box On this case, you can display more than one column as soon as the DW gets the focus and you'd be able to dynamically populate the data. Give it a try. It worked for me, DW's are a pain in the neck when you're just starting (as in my case) but you can do a lot with it

Resources