Is there a method for calculating a stacked subtracted and summed tier in Power Pivot (DAX) - dax

Column W gives a simple explanation on how it should be calculated for quantity 500.. For a normal stack tier I have a working DAX formula below. However, that does not work for a stacked subtracted and summed tier.
VAR _quantity = [Quantity]
VAR _year_product = Quantity2022[YearProduct]
RETURN
MINX(FILTER(PriceList;
AND(_year_product=PriceList[YearProduct];_quantity>=PriceList[QFrom]));
PriceList[Price]*[Quantity]))
How can I do the same for a stacked tier?

Related

filter cost center with GL account and take the total

I am trying to filter the column "E" with each cost center, column "L" with each GL account and get the sum of amount column "I" in new sheet with entire row values. Also the negative amount to be highlighted. There are 75000 rows with 200 cost centers.

dcjs dynamic zooming to fit range of values

I have a rowchart in DCjs that plots the top N values of a given parameter. However, for the unfiltered data these differ from each other by a very small number.
I've had to label each row with it's unique identifier, as my random generator produced two identical names, meaning that if I use name as the dimension, I end up with one of ten thousand data points having a value greater than 100%.
However, the main problem here is that the difference between each row is tiny, and can be around 0.0001.
However if I zoom in on that part of the x-axis using
var max = dim.top[1][0].value;
var min = dim.top(10)[9].value;
chart
.dimension(dim)
.group(group)
.x(d3.scaleLinear()
.range([-100, chart.width()])
.domain([min-(max-min)*0.1,max])
)
.cap(10)
.othersGrouper(null)
.colors(['#ff0000']);
Firstly I loose the ID label on the left. Secondly as I also have to use .elasticX(false) for the zooming to work, it means that when I add filters, the range of the x-axis doesn't change with the values e.g.
Is there a way to get dynamic zooming such that the range of the x-axis depends on the range of values presented?
elasticX is a really simple feature which does pretty much what your code does, although it locks the min or max to zero depending if the data is positive or negative:
var extent = d3.extent(_rowData, _chart.cappedValueAccessor);
if (extent[0] > 0) {
extent[0] = 0;
}
if (extent[1] < 0) {
extent[1] = 0;
}
(calculateAxisScale source)
This code gets called (indirectly) before each render and redraw.
Here's some general purpose advice for when elasticX or elasticY doesn't do exactly what you want. I've never seen it fail! (Which is saying something in such a quirky codebase as dc.js.)
First, disable elasticX. Then create a function which calculates the X domain and sets it:
function custom_elastic(chart) {
var max = chart.dimension().top[1][0].value;
var min = chart.dimension().top(10)[9].value;
chart.x().domain([min,max]);
}
I've parameterized it on the chart for generality.
Now we can have this function called on the preRender and preRedraw events. These events will pass the chart when they fire:
chart.on('preRender', custom_elastic)
.on('preRedraw', custom_elastic);
And that should do it!
BTW, you probably don't want to set the range of the scale - this is set automatically by the chart, and it's a little more complicated than you have it since it takes margins into account.
Debugging the min and max
Looking at your fiddle I realized that I hadn't given a second look to how you are calculating the min and max.
I also hadn't noticed that you had the range start at -100.
Good first step logging it; it reports
min: 0.81, max: 0.82
which is incorrect. The top ten are from 0.96 to 1.
The issue is that the dimension's key is the id, so the rows returned by .top() are in reverse alphabetical order (the "largest" strings).
Again you're on the right track with
console.log(Group.top(Infinity))
Yes! The group will give you the top 10 by value.
var top10 = thischart.group().top(10);
var max = top10[0].value;
var min = top10[9].value;
Nice!
fiddle
But wait, doesn't it look like the bars are stretching off the left side of the chart?
Hacking the row chart with a renderlet to draw bars starting at the left edge
Okay now it's clear that the row chart doesn't support this. Here is a hack to resize the bars to the left edge:
chart.on('renderlet', function(chart) {
var transform = chart.select('g.row rect').attr('transform');
var tx = +transform.split('(')[1].split(',')[0];
chart.selectAll('g.row rect')
.attr('transform', null)
.attr('width', function(d) {
return +d3.select(this).attr('width') + tx;
})
chart.selectAll('g.row text.row')
.attr('transform', null);
})
All the row rects are going to be offset by a large negative number, which we grab first in tx. Then we remove the transform from both the rects and the text, and add tx to the width of the row rects.
fiddle
Great! But where's the last bar? Well, we took the top ten values for the min and max, so the tenth bar is the minimum value.
You'll have to figure out what works for you, but I found that looking at the top 20 values left the top 10 at good sizes:
var N = 20;
var topN = thischart.group().top(N);
var max = topN[0].value;
var min = topN[N-1].value;
final fiddle
This hack does not play well with the built-in transitions, so I turned them off for this chart:
chart.transitionDuration(0)
It would be a lot more work to hack that part, and better to fix it in the chart itself.

What kind of scale does my area graph need for the x-axis?

I am making an area graph in D3 that I am testing with 4 points. The y-axis is a linear scale from 0 to the largest value of data.count. The x-axis is a time scale that sets the domain with d3.extent - the min & max of data.date. These dates are created from month & year values so they are all the 1st of their month.
Imagine that there are 4 columns in the graph. The x-value for the data points should fall in the center of each column. This means that the first point would not actually touch the y-axis, as would be normal for an area graph. The distance from the y-axis to the first point is half a column.
I need to add a data point ON the y-axis so it looks like the data starts somewhere and goes TO the first data point. And I need to add a data point on the right hand edge of the graph so it looks like the data flatlines at the end.
I tried adding those additional start & end points to my data array and giving them appropriate values for date (the 15th of, or halfway through, their respective months). This gave me 6 points total. BUT, instead of having half a column's width to the left of the first point, and half a column's width to the right of the 4th point, all 6 points were evenly spaced & that's not what I need.
Is there a different type of scale I should use for the x-axis or a different way entirely to go about this?
I found a workaround and would like to share it for anyone else in the same situation.
My first attempt was to simply modify the dates of the first & last elements. Since each point represented the first of the month but needed to fall in the middle of the columns, I modified the first date to be the 15th of its month and the last date to be the 15th of the previous month instead of the 1st of the next month. This almost worked but was slightly off center because some months have 28 or 31 days.
So instead, I changed the x-axis to a linear scale with a range of 0 to the width of the div that wraps the entire area graph.
Then I looped through my data array and added an xval property to each object that was calculated this way:
if(i === 0){
xval = 0;
}else{
xval = (columnWidth * i) - (columnWidth/2);
}
Then, when I calculated the area graph coordinates, I passed xval to .x like this:
var area = d3.area()
.x(function(d) { return x(d.xval); })
.y1(function(d) { return y(d.count); });
area.y0(y(0));

Algorithm for calculating variable column widths for set table width

I need to figure out an algorithm that will calculate the optimized size of the column widths given the following:
the width of the table is fixed to the size of the page
the data inside the columns will be variable thus the width of the columns are variable
the width must be optimized to know when to wrap a column and when not to
So given the following data:
'From' => '03/06/2014',
'To' => '03/06/2014',
'First Name' => 'John Doe',
'Status' => 'approved',
'Type' => 'PTO',
'Amount' => '8 Hours',
'Notes' => 'Oops! Who knew I would need one more day. This should be all I need over the next week to support my trip.'
How can I calculate the optimal column widths so that the 'notes' column does not squeeze the other widths down to a less than acceptable width?
UPDATE: I currently know the width of the page & the width of the font so I can calculate the max width requirements for each column. It should fill the available space on the page. However, I would prefer the columns not wrap unless necessary. Like this:
An easy solution is to assign attributes to your colums; for example your Notes columns could be flexible. Then you could calculate the maximum width of each column over all rows, set that width for all non-flexible columns and then distribute the remaining space evenly (or possibly weighted by their max width) to the flexible columns.
But you could also try to find out the attributes with some simple conditions:
a column can be word-wrapped if any of its entries has spaces in it. In your example, the dates and possibly the status and type entries cannot be wrapped. The name shouldn't be wrapped under normal circumstances but could be wrapped, if the name is long or if more than one name is given. The notes column should be wrapped.
a column should be flexible if its maximum width exceeds, say, the width a cell would have if all sizes were evenly distributed.
Then go about as described above: Calculate all non-flexible columns width. Check if there is enough space; if not, make the wrappable columns flexible, too. Then calculate the width of the flexible cells, weighted by their maximum widths.
A possible pseudocode algorithm is below. It makes liberal use of various heuristics, so you should probably take it with a grain of salt. You can adjust these conditions according to your use case, but it will be difficult to cater for all possible cases.
function layout(table[], width, gutter, col[])
var maxw[col.length] # max. text width over all rows
var maxl[col.length] # max. width of longest word
var flex[col.length] # is column flexible?
var wrap[col.length] # can column be wrapped?
var colw[col.length] # final width of columns
foreach row in table:
for i = 0 to col.length:
cell = row[i]
maxw[i] = max(maxw[i], textwidth(cell))
if cell.find(" "):
maxl[i] = max(maxl[i], wordwidth(cell))
var left = width - (col.length - 1) * gutter
var avg = left / col.length
var nflex = 0
# determine whether columns should be flexible and assign
# width of non-flexible cells
for i = 0 to col.length:
flex[i] = (maxw[i] > 2 * avg) # ???
if flex[i]:
nflex++
else:
colw[i] = maxw[i]
left -= colw[i]
# if there is not enough space, make columns that could
# be word-wrapped flexible, too
if left < nflex * avg:
for i = 0 to col.length:
if !flex[i] and wrap[i]:
left += width[i]
colw[i] = 0
flex[i] = true
nflex += 1
# Calculate weights for flexible columns. The max width
# is capped at the page width to treat columns that have to
# be wrapped more or less equal
var tot = 0
for i = 0 to col.length:
if flex[i]:
maxw[i] = min(maxw[i], width) # ???
tot += maxw[i]
# Now assign the actual width for flexible columns. Make
# sure that it is at least as long as the longest word length
for i = 0 to col.length:
if flex[i]:
colw[i] = left * maxw[i] / tot
colw[i] = max(colw[i], maxl[i])
left -= colw[i]
return colw
The W3C publishes algorithms for stuff like this in it's CSS 3 Tables Algorithms.
A simpler algorithm that I have used successfully and is quite trivial to implement can be found in the HTML4.1 specs:
The minimum and maximum cell widths are then used to determine the
corresponding minimum and maximum widths for the columns. These in
turn, are used to find the minimum and maximum width for the table.
Note that cells can contain nested tables, but this doesn't complicate
the code significantly. The next step is to assign column widths
according to the available space (i.e., the space between the current
left and right margins).
For cells that span multiple columns, a simple approach consists of
apportioning the min/max widths evenly to each of the constituent
columns. A slightly more complex approach is to use the min/max widths
of unspanned cells to weight how spanned widths are apportioned.
Experiments suggest that a blend of the two approaches gives good
results for a wide range of tables.
The table borders and intercell margins need to be included in
assigning column widths. There are three cases:
The minimum table width is equal to or wider than the available space. In this case, assign the minimum widths and allow the user to scroll horizontally. For conversion to braille, it will be necessary to replace the cells by references to notes containing their full content. By convention these appear before the table.
The maximum table width fits within the available space. In this case, set the columns to their maximum widths.
The maximum width of the table is greater than the available space, but the minimum table width is smaller. In this case, find the difference between the available space and the minimum table width, lets call it W. Lets also call D the difference between maximum and minimum width of the table.
For each column, let d be the difference between maximum and minimum width of that column. Now set the column's width to the minimum width plus d times W over D. This makes columns with large differences between minimum and maximum widths wider than columns with smaller differences.
I encountered a problem similar to this using ITextPDF with a 14 column table. The data was variable, where some columns could wrap and others couldn't.
My solution was to find the largest word in each column by using split(" "). This reduces the odds of a word, date or number getting cut in half. Here is the code. Sorry I don't have time to edit this to a more general format, hopefully it will help someone anyways.
//This array will store the largest word found in each of the 14 columns
int[] maxStringLengthPerColumn = new int[14];
for(int i = 0; i < maxStringLengthPerColumn.length; i++)
maxStringLengthPerColumn[i]=0;
//for each row in table...
ArrayList<PdfPRow> rows = table.getRows();
for(int a = 0; a < rows.size(); a++){
//for each cell in row
PdfPCell[] cellsInRow = rows.get(a).getCells();
for(int b = 0; b < cellsInRow.length; b++){
//Split cell contents at " " and find longest word in each cell
String[] splitCell = cellsInRow[b].getPhrase().getContent().split(" ");
//find the longest string left after split
int largestStringSize = 0;
for(int c = 0; c < splitCell.length; c++){
if(splitCell[c].length()>largestStringSize){
largestStringSize=splitCell[c].length();
}
}
if(largestStringSize>maxStringLengthPerColumn[b]){
//I found that adding 4 to the value worked, change this number to fine tune.
maxStringLengthPerColumn[b] = largestStringSize + 4;
}
}
}
/*The pdf library can set width with just an array, you may need to
convert these values to something else depending on the application. For
example if you have a width of 800 pixels, the width of col1 would be
maxStringLengthPerColumn[0] / (sum of maxString0 - 13) * 800*/
table.setWidths(maxStringLengthPerColumn);

Geographic grid search algorithm

Many of the location based services provide APIs for finding places/venues/spots around a given latitude longitude pair. I'm looking into how I can search for these places across an entire city.
I can build a grid for a city by getting its bounds from the Google Maps Geocoder and then incrementing the lat/longs to lay down points to form the grid. I've prototyped this grid (click the Fill Grid button to see all of the points) to visualize this idea.
// gather a collection of lat/long pairs that represents a grid of the city
var latIncrement = .04;
var lngIncrement = .04;
var newLat = nw.lat();
while(newLat >= sw.lat()) {
var newLng = nw.lng();
while(newLng <= ne.lng()) {
// western and northern border as well as grid infill
addMarker(new google.maps.LatLng(newLat, newLng));
newLng += lngIncrement;
}
// eastern border
addMarker(new google.maps.LatLng(newLat, ne.lng()));
newLat -= latIncrement;
}
// southern border
var newLng = sw.lng();
while(newLng <= se.lng()) {
addMarker(new google.maps.LatLng(sw.lat(), newLng));
newLng += lngIncrement;
}
addMarker(se);
I can then take all of these points and run searches for them against the LBS APIs.
My question is, are there more scientific ways/algorithms to establish this grid? I'd like to learn more about them. I'm just arbitrarily incrementing the lat/lngs until I reach the border of the grid. The density of places is going to vary wildly by city and area of a city, so sometimes the increment will be too small, and sometimes too large. I'm looking for ideas about how to tune this a little better?
A perhaps more efficient/clean way would be to find the bounding rectangle of the city, which is the rectangle with each edge being the extreme cardinal points between the city border points, if you can find them, and then filling them in iteratively. But that is basically what you are already doing, anyway.
As for place density, do you have a specific API that you are going to be using this with? If you know the "reach" of the your API's points when detecting places, you ever only have to have grid points as close as their radius.
That being said, have you looked into seeing perhaps if the API directly supports searching for places within a border? That might be your best and cleanest bet.
After reading your comment, here is a possibly inefficient way that I'm going to think over and refine in the future, but it might help you get started.
Place a point in the center of your city, and observe all locations detected. Find the convex hull of your locations, and place a new point on each location on the convex hull. Then, add to your list of locations all locations that fall within reach of these newly added points.
Then, find the convex hull of those, and repeat the same process.
This might actually reduce your amount of points for sparsely populated cities. For dense ones, it might be less than optimal, but it might get you started on a working track.
While I was facing same problem. I came up with a solution, where you will go do grid search in a top down recursive way. This will work if that API supports bounding box search. Initially assume your city as a square. Now fetch data/places using API in that square (bounding box query). Now if number of returned places are more than some threshold, than split the city square into 4 equal squares and repeat the process for each square. Don't split if number of returned places are less. This will prevent grid searching into non business areas (squares) like forests,rivers etc. Here is the prototype python code for that:
Here fetch is function which fetch results from API based on bounding box with sw as southwest latitude,logitude tuple and ne as northeast latitude,logitude tuple
allresults = []
def grid_search(sw,ne):
global results
results = fetch(sw,ne)
if len(results) <= 10:
return
allresults.append(results)
swlat,swlon = sw
nelat,nelon = ne
grid_search( (swlat + delta, swlon), (nelat, sw + delta) )
grid_search( (swlat + delta, swlon + delta), ne )
grid_search( sw, (swlat + delta, swlon + delta) )
grid_search( (swlat,swlon + delta), (swlat + delta, nelon) )

Resources