How can I hide selected ranges AND sort the displayed results (Aspose Cells)? - sorting

I can sort (descending) my displayed results by a selected value using this code:
PivotField field = pivotTable.RowFields[0];
field.IsAutoSort = true;
field.IsAscendSort = false;
field.AutoSortField = 1;
This is what I see (Total Purchases displayed are indeed shown from most to least):
Or, I can only display Description ranges whose "Percentage of Total" value is at least 1% with this code:
private void HideItemsWithFewerThan1PercentOfSales()
{
int FIRST_TOTAL_PRICE_ROW = 8;
int ROWS_BETWEEN_PERCENTAGES = 4;
var pivot = pivotTableSheet.PivotTables[0];
var dataBodyRange = pivot.DataBodyRange;
int currentRowBeingExamined = FIRST_TOTAL_PRICE_ROW;
int rowsUsed = dataBodyRange.EndRow;
pivot.RefreshData();
pivot.CalculateData();
// Get grand total of purchases for all items and months, and calculate what 1% of that is
Cell totalTotalPurchasesCell = pivotTableSheet.Cells[rowsUsed - 2, _grandTotalsColumnPivotTable + 1];
double totalTotalPurchases = Convert.ToDouble(totalTotalPurchasesCell.Value);
var onePercentOfTotalPurchases = totalTotalPurchases / 100;
// Loop through PivotTable data, hiding where percentage < 0.01 (1%)
while (currentRowBeingExamined < rowsUsed)
{
Cell priceCell = pivotTableSheet.Cells[currentRowBeingExamined, _grandTotalsColumnPivotTable + 1];
String priceStr = priceCell.Value.ToString();
Double price = Convert.ToDouble(priceStr);
if (price < onePercentOfTotalPurchases)
{
pivotTableSheet.Cells.HideRows(currentRowBeingExamined - 1, ROWS_BETWEEN_PERCENTAGES);
}
currentRowBeingExamined = currentRowBeingExamined + ROWS_BETWEEN_PERCENTAGES;
}
}
...like so:
...but I can't get them both to work at the same time. So I can either hide the Descriptions with less than 1% of the percntage OR I can sort by Total Purchases descending, but I'm not able to accomplish both at the same time. My code to try to accomplish both is as follows:
. . .
pivotTable.AddFieldToArea(PivotFieldType.Row, DESCRIPTION_COLUMN);
pivotTable.RowHeaderCaption = "Description";
// Dragging the second field to the column area.
pivotTable.AddFieldToArea(PivotFieldType.Column, MONTHYR_COLUMN);
pivotTable.ColumnHeaderCaption = "Months";
// Dragging the third field to the data area.
pivotTable.AddFieldToArea(PivotFieldType.Data, TOTALQTY_COLUMN);
pivotTable.DataFields[0].DisplayName = "Total Packages";
pivotTable.AddFieldToArea(PivotFieldType.Data, TOTALPRICE_COLUMN);
pivotTable.DataFields[1].DisplayName = "Total Purchases";
. . .
// Sort by "Total Purchases" descending
PivotField field = pivotTable.RowFields[0];
field.IsAutoSort = true;
field.IsAscendSort = false;
field.AutoSortField = 1; // This is the "Total Purchases" field
pivotTable.PivotTableStyleType = PivotTableStyleType.PivotTableStyleLight16;
pivotTable.RefreshDataFlag = true;
pivotTable.RefreshData();
pivotTable.CalculateData();
pivotTable.RefreshDataFlag = false;
List<String> contractItemDescs = GetContractItemDescriptions();
ColorizeContractItemBlocks(contractItemDescs);
HideItemsWithFewerThan1PercentOfSales();
FreezePanePivotTable(HEADER_ROW, 2);
FormatPivotTableNumbers();
ConfigureForPrinting(pivotTableSheet.Cells.Rows.Count);
It's as if the sorting order is not being respected when HideItemsWithFewerThan1PercentOfSales() is called - the row numbers that method "sees" is not the row numbers according to the sorting that has been established.
How can I get both the sorting AND the hiding to work?
NOTE: Calling HideItemsWithFewerThan1PercentOfSales(); prior to the sorting code does NOT work - it still shows/hides some of the wrong things.

Please check the reply in this thread in Aspose.Cells forum.
Note: I am working as Developer Evangelist at Aspose

Related

Filtering data in range to populate drop-down menu

I have a spreadsheet which serves as a form for listing equipment in a contract. In a given row, selecting a distributor(col F) populates the Manufacturer field(col E) with a drop-down menu based on data in another sheet. What I need now is for the Model field(col D) to populate with a drop-down list based on the filtering of a series of ranges I've already defined (l01,l11,l12,l13), for the value from col E.
Here's my code so far:
function onEdit()
{
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sheet = ss.getActiveSheet(),
name = sheet.getName();
if (name != 'Addendum B') return;
var range = sheet.getActiveRange(),
col = range.getColumn();
if (col != 5) return;
var val = range.getValue(),
ctlg0 = SpreadsheetApp.openById("1nbCJOkpIQxnn71sJPj6X4KaahROP5cMg1SI9xIeJdvY"),
ctlg1 = SpreadsheetApp.openById("1Jzue8G0dAJC5CiY5_s-thaOiYEyfeJScb2ITNWa_dVQ"),
c01 = ctlg0.getSheetByName('MISC_CATALOG'),
c11 = ctlg1.getSheetByName('Part #A-I'),
c12 = ctlg1.getSheetByName('Part #J-R'),
c13 = ctlg1.getSheetByName('Part #S-9'),
l01 = c01.getRange("A2:B"),
l11 = c11.getRange("A2:B"),
l12 = c12.getRange("A2:B"),
l13 = c13.getRange("A2:B"),
//data = dv.getDataRange().getValues(),
//catCol = data[0].indexOf(val),
//list = [];
Logger.log(catCol)
for (var i = 1, len = 100; i < len; i++)
list.push(data[i][catCol]);
var listRange = dv.getRange(2,catCol +1,dv.getLastRow() - 1, 1)
Logger.log(list)
var cell = sheet.getRange(range.getRow(), col-1)
var rule = SpreadsheetApp.newDataValidation()
.requireValueInRange(listRange)
.build();
cell.setDataValidation(rule);
Logger.log(cell.getRow())
}
I've commented out the place where I ran out of coding knowledge to implement this myself. The above code is based on my existing data validation for col E. Sample sheets can be found here.
I have a basic understanding of coding, and have mostly taught myself by breaking down sample code and reading the GAS online reference material. Any assistance with this would be helpful, but please provide as much detail as you can by way of explanation so I can hopefully learn how to adapt this solution to future projects.

Frequencies - From fft to file to list using processing

I'm doing a project where I'm outputting the frequencies from real time mic input through fft to a txt doc and then retrieving (or trying to retrieve) them to a list of 4 frequencies. My list array is turning out empty, ie the console prints [] and no numbers in them. Pl tell me what is wrong with the logic/code. This is within the void draw()
for (int i = 0; i<fft.specSize(); i++) {
float freq = fft.getFreq(i);
int freqint = (int) freq;
//println(freqint);
output.println(freqint);}
Scanner input = new Scanner("...\\list.txt");
while (input.hasNextInt()) {
list.get(input.nextInt(4));
}
println(list);
input.close();
Split your taks into subtasks:
get FFT data (and 4 frequencies)
Save/Load float values to disk
Put the 1 and 2 together
It looks like you already have the first part done.
It's unclear what the 4 frequencies are, but you can figure that out on your own.
The part that is confusing is that you call the get FFT data once then try to save it straight to disk. I'm not 100% that's what you mean to do.
Double check if you need to save few samples/seconds worth of FFT data first.
I would imagine a more generic scenario like this:
load previously saved FFT data (if any)
process FFT data (for as long as needed - might need a start/stop boolean) and append
save current FFT data
Moving on to saving and loading data.
You've got a few of options build into Processing for storing data:
Strings via saveStrings()/loadStrings()
CSV Table via saveTable()/loadTable()/Table
JSON via JSONObject/JSONArray and available load/save functions
XML
I recommend reading Daniel Shiffman's Data Tutorial
Dealing with saving/loading floating point values to disk alone,
here's a basic proof of concept snippet using Strings:
int fftSpecSize = 10;//this will be fft.specSize() in your case
String values = "";
for(int i = 0 ; i < fftSpecSize; i++){
//random(1) is a placeholder for fft.getFreq(i);
values += random(1);
//if it's not the last value, add a separator character (in this case space)
if(i < fftSpecSize-1){
values += " ";
}
}
println("values to save:");
println(values);
println();
//save data
saveStrings("fftSingleRead.txt",values.split(" "));
//load data
String[] readValues = loadStrings("fftSingleRead.txt");
//print raw loaded data
println("readValues from .txt file:");
println(readValues);
println();
//parse values:
for(int i = 0 ; i < readValues.length; i++){
float value = float(readValues[i]);
println("readValues[",i,"] = ",value);
}
additionally here's a Table example too:
Table fftValues;
int specSize = 10;
//create a new table
fftValues = new Table();
//add columns - one per FFT bin
for(int i = 0 ; i < specSize; i++){
fftValues.addColumn();
}
//add some data, a row per reading
//create a new row
TableRow newRow = fftValues.addRow();
//add each fft value to the row
for(int fftCount = 0 ; fftCount < specSize; fftCount++){
//placeholder for newRow.setFloat(fftCount,fft.getFreq(fftCount));
newRow.setFloat(fftCount,random(1));
}
//add the row to the table
fftValues.addRow(newRow);
//save to disk
saveTable(fftValues,"fftValues.csv","csv");
//load from disk
Table readValues = loadTable("fftValues.csv","csv");
//access the data that has been saved in the table
for(int rowCount = 0; rowCount < readValues.getRowCount(); rowCount++){
TableRow currentRow = readValues.getRow(rowCount);
print("row[",rowCount,"] = ");
for(int columnCount = 0; columnCount < currentRow.getColumnCount(); columnCount++){
float value = currentRow.getFloat(columnCount);
print(value);
if(columnCount < currentRow.getColumnCount() - 1){
print(",");
}
}
println();
}
Try the code, see the output, read the comments, read the reference, tweak/retry/understand and adapt to your problem.

Progress when assigning datasource to XtraTreeList

I have a XtraTreeList and I assign a huge datasource (with millions of items) to it
xtraTree.TreeViewData = dataSource;
This operation takes 80 seconds to complete, which is totally fine given the amount of nodes.
I'd just like to display a somewhat reliable progress bar to the user, indicating how many nodes have been processed.
I have tried:
looking in the event list, but I only found PrintExportProgress
googling for the topic, hoping I would find something on the DevExpress support pages
I'm using the WinForms variant, version 15.2 if that matters.
This is not about displaying progress while I build the datasource. There are 2 steps:
build the datasource (read from file) - this also takes 60 seconds, but I do that myself and I have no problem here
assign the datasource to the XtraTreeList - works, but I don't get progress information and it needs to be done on the UI thread, which is blocking
This is also not about cross-thread updating of the progress bar. I know how to do that.
Hey I did the same thing in a project that I built using WinForms ... except I only had 4500 items - these items were files that I had to extract data from. What I did is at each file that I processed (at the bottom of my foreach loop) I called a method to update my progress bar on my form:
Form1.UpdateProgressbar();
Inside my Form1.cs, I did this:
public void UpdateProgressbar()
{
progressBar2.Increment(1);
label7.Text = "Processed: " + Convert.ToString(progressBar2.Value) + " out of " + Globals.totalartistcount + " Artists";
label8.Text = "Processed: " + Globals.songcounter + " Songs. Processing: " + Globals.artist;
label9.Text = "Total Number of Songs to process: " + Globals.totalsongcount;
progressBar2.Update();
Application.DoEvents();
}
If I remember right the
Application.DoEvents();
was critical to actually see the progress bar move and the labels update their text. I initialized my progress bar this way:
/* ------ progress bar ------------------------------------------ */
public void InitializeProgressBar(DirectoryInfo di)
{
int songcount = 0;
int artistcount = 0;
int index = 0;
//Get Total number of folders
foreach (var sf in di.GetDirectories())
{
//find index of artist to process
//this is just an array of artist names and if true or false to process
for (int i = 0; i <= Globals.artists.GetUpperBound(0); i++)
{
if (sf.Name == Globals.artists[i, 0])
{
index = i;
break;
}
}
if (Globals.artists[index, 1] != "false")
{
// Get a total number of files to process (MAX)
foreach (var fi in sf.GetFiles("*.mp3"))
{
songcount++;
}
artistcount++;
}
}
Globals.totalartistcount = artistcount;
Globals.totalsongcount = songcount;
progressBar2.Minimum = 0;
progressBar2.Maximum = artistcount - 1;
progressBar2.Value = 0;
Application.DoEvents();
}
There, I hope that helps.

Is there a way to mass input data validation in google sheets

I'm trying to create a drop down menu with contents based on a another cell in the same row. For example if A1 = 'yes' then the drop down in B2 gives you the options of 'yes' or 'no'. I can do this I have the list data set up and to code works. The problem is I need to do this 155 times in 4 different sheets. Is there a faster way to do this than right clicking and editing the data validation rules for each cell. Here's a link to the test sheet I'm working on :
https://docs.google.com/spreadsheets/d/1rd_Ig_wpof9R_L0IiA1aZ9syO7BWxb6jvBhPqG8Jmm4/edit?usp=sharing
You can set data validation rules with a script, as documented here. Here's a reference for starting with Apps scripts.
I wrote a function that does approximately what you described. It works with the range B3:B157 of the sheet '9th grade' in the current spreadsheet. For each of them, it sets the validation rule to be: a value in the same row, columns B and C of sheet 'List Data'. The line with
....... = listData.getRange(i+3, 2, 1, 2);
will need to be modified if the source range of validation is to be different. Here, the parameters are: starting row, starting column, number of rows, number of columns. So, 2 columns starting with the second, in row numbered i+3.
function setRules() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var grade = ss.getSheetByName('9th Grade');
var listData = ss.getSheetByName('List Data');
var range = grade.getRange('B3:B157');
var rules = range.getDataValidations();
for (var i = 0; i < rules.length; i++) {
var sourceRange = listData.getRange(i+3, 2, 1, 2);
rules[i][0] = SpreadsheetApp.newDataValidation().requireValueInRange(sourceRange).build();
}
range.setDataValidations(rules);
}
I land in this issue for a diferent reason: "Just mass DataValidation copy (or update) in one column". Thanks, to user3717023 that bring me a light.
I hope that helps someone this simplification.
function setRules() {
//select spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var leads = ss.getSheetByName('Leads');
//Select correct Datavalidation
var rangeNewDataValidation = leads.getRange('M2:M2');
var rule = rangeNewDataValidation.getDataValidations();
//Copy (or Update) Datavalidation in a specific (13 or 'M') column
var newRule = rule[0][0].copy();
Logger.log(leads.getMaxRows())
for( var i=3; i <= leads.getMaxRows(); i++){
var range = leads.getRange(i, 13);
range.setDataValidations([[newRule.build()]]);
}
}

jQuery Isotope 2.1 Pagination

I'm trying to paginate items using jQuery Isotope 2.1. I have a set of items which can be filtered. I'd like to be able to limit the displayed items using a range. If I want to display 10 items per page, I'd tell it show all items between 11 and 20 in the filtered set for page 2, for example.
To make matters more complex, items can be sorted as well.
Is there any way to do this?
I thought about toggling a "active" class on the filtered items, then using JS and CSS I would only show items with the "active" class that are within the current range. Not sure if that's the most efficient approach.
Thanks,
Howie
I was able to solve the problem by prototyping the _filter method.
Firstly, I call the _sort method before attempting to filter the items since sorting will affect which items are displayed on each page.
Then I added a few parameters to the options object, such as page and items_per_page. Using these two values, I can calculate the first and last item for the intended page. Even though it's not necessary for pagination, I also added a parameter called activeClass which defaults to active and is added to all matching items. In addition I added and odd-item and an even-item class to each item so that in a list view, for example, I can alternate the row colors.
Lastly, I set a property on the this object called all_matches to the entire set of filtered items. This way I can calculate the total number of pages for my pager. Then I return only the filtered items for the current page.
On the layoutComplete event, I use the page and items_per_page values from the options object in order to calculate the first and last item and update my pager.
I happen to be using Bootstrap along with a customized version of the Bootpag pager which accepts itemsPerPage and totalItems.
You can check out the codepen here. Hope it helps.
Isotope.prototype._filter = function (items)
{
//console.log('FILTER ' + arguments.callee.caller.toString());
var filter = this.options.filter;
filter = filter || '*';
var matches = [];
var all_matches = [];
var hiddenMatched = [];
var visibleUnmatched = [];
var start, end;
//console.log('page: ' + this.options.page + ' items per page: ' +
this.options.items_per_page);
start = (this.options.page - 1) * this.options.items_per_page;
end = this.options.page * this.options.items_per_page;
//console.log('start: ' + start + ' end: ' + end + ' page: ' +
this.options.page);
// we want to set the current value of filteredItems to all items
before we sort
// we must sort first becuase we need to make sure we are showing
// the correct results for each page in the correct order
this.filteredItems = items;
this._sort();
if (this.options.activeClass === undefined ||this.options.activeClass === '')
{
this.options.activeClass = 'active';
}
var test = this._getFilterTest(filter);
// test each item
for (var i = 0, len = items.length; i < len; i++)
{
//console.log('item: ' + i, $(items[i].element).find('.grid-item-title .asset-link').text(), items[i]);
var item = items[i];
if (item.isIgnored)
{
continue;
}
// add item to either matched or unmatched group
var isMatched = test(item);
// add to matches if its a match
if (isMatched)
{
all_matches.push(item);
// before we add it to the matched set, let's make sure if falls within range
// it needs to be part of the current page set otherwise we filter it out
if (all_matches.length > start && all_matches.length <= end)
{
matches.push(item);
var odd_even = (matches.length % 2 === 0) ? 'even-item' : 'odd-item';
$(item.element).addClass(this.options.activeClass + ' ' + odd_even);
} else
{
// we need to reset isMatched if we're not using it on the current page
isMatched = false;
$(item.element).removeClass(this.options.activeClass + ' odd-item even-item');
}
}
// add to additional group if item needs to be hidden or revealed
if (isMatched && item.isHidden)
{
// reveal these items
hiddenMatched.push(item);
} else if (!isMatched && !item.isHidden)
{
// hide these items
visibleUnmatched.push(item);
}
}
var _this = this;
function hideReveal()
{
_this.reveal(hiddenMatched);
_this.hide(visibleUnmatched);
}
if (this._isInstant)
{
this._noTransition(hideReveal);
} else {
hideReveal();
}
// set all matches as a property on 'this' since we'll need it later to build the pager
this.all_matches = all_matches;
return matches;
};
H

Resources