itext -- what's an easy to print "first right, then down" - itext

I would like to print a PdfPTable containing many more rows and columns than fit in one page of the PDF.
I would like to print "first right, then down", which is similar to row-major order. Print the first page-full of rows, but all columns for those rows. Then print the next page-full of rows, and again all columns for those rows.
As I understand it, iText can handle a PdfPTable containing more rows than fit on a page, but can't handle more columns than fit on a page. So I split the columns myself. But that means that I end up printing "first down, then right", which is not what I want.
Is there an easy way to do what I want? Note that I do not know the row heights ahead of time, because I call setMinimumHeight() on the PdfPCell objects.
The only way I can think of, which is clumsy, is to first split columns, as before. Then, for each sequence of columns that fit on one page, add rows one by one to a PdfPTable as long as they fit. When they don't, that's where we need to split the rows. At the end of this, we end up with PdfPTable objects for each set of rows and columns. We need to keep all of them in memory and add them to the PDF document in the right (row-major) order.
This seems rather inelegant, so I wanted to check if there's a cleaner solution. Thanks.

If you have really large tables, the most elegant way to maintain the overview and to distribute the table over different pages, is by adding the table to one really large PdfTemplate object and then afterwards add clipped parts of that PdfTemplate object to different pages.
That's what I've done in the TableTemplate example.
I create a table with 15 columns a total width of 1500pt.
PdfPTable table = new PdfPTable(15);
table.setTotalWidth(1500);
PdfPCell cell;
for (int r = 'A'; r <= 'Z'; r++) {
for (int c = 1; c <= 15; c++) {
cell = new PdfPCell();
cell.setFixedHeight(50);
cell.addElement(new Paragraph(String.valueOf((char) r) + String.valueOf(c)));
table.addCell(cell);
}
}
Now I write this table to a Form XObject that measures 1500 by 1300. Note that 1300 is the total height of the table. You can get it like this: table.getTotalHeight() or you can multiply the 26 rows by the fixed height of 50 pt.
PdfContentByte canvas = writer.getDirectContent();
PdfTemplate tableTemplate = canvas.createTemplate(1500, 1300);
table.writeSelectedRows(0, -1, 0, 1300, tableTemplate);
Now that you have the Form XObject, you can reuse it on every page like this:
PdfTemplate clip;
for (int j = 0; j < 1500; j += 500) {
for (int i = 1300; i > 0; i -= 650) {
clip = canvas.createTemplate(500, 650);
clip.addTemplate(tableTemplate, -j, 650 - i);
canvas.addTemplate(clip, 36, 156);
document.newPage();
}
}
The result is table_template.pdf where we have cells A1 to M5 on page 1, cells N1 to Z5 on page 2, cells A6 to M10 on page 3, cells N6 to Z10 on page 4, cells A11 to M15 on page 5 and cells N11 to Z15 on page 6.
This answers all Google's answers posted on Friday.

Related

Searching for a matched string within nested cell and delivering the index

I have a nested cell array which is called
values. Description as an image. In this example, there are 5 sub cells. Usually this number is variable from 1 to 30. Each cell has two subsub cells:
he first one, or values{5,1}{1,1}, has always only one char value
(in this example, TOTAL or MGS)
the second one, or values{5,1}{2,1}, has matrix consisting from tow columns: on the left - tempearature values, on the right - physical properties.
My goal is to find the sub cell containing the char value 'TOTAL' (values{5,1}) and somehow to get the index of the matrix (the output would be values{5,1}{2,1})
To adress the challenge, I have written my handmade solution. This code works if there is in the char 'TOTAL' in a{5,1}{1,1} and takes a corresponding value next to 298.15 K. However, the string 'TOTAL' could be elsewhere. In this case, I have a problem. In this solution, the double loop takes long time. So, do you have another solution how to find the index of a cell with 'TOTAL' avoiding loops?
for m = 1:numel(values)
for n = 1:numel(values(m))
a = values(m);
if string(a{5,1}{1,1}) == 'TOTAL'
k = a{5,1}{2,1}(:,1); %column with temp numbers
n = 298.15; %RT
[~,~,idx] = unique(round(abs(k-n)));
minVal = k(idx==1);
valueAtRT = sprintf('%f', a{1,1}{5,1}(length(a{1,1}{5,1})+idx));
break;
end
end
end
Thanks for any help.
I have found the solution assuming there is only one cell with 'TOTAL':
is = cellfun( #(cac) strcmp(cac{1},'TOTAL'), values, 'uniformoutput',false );
num = values{is}{2};
valueAtRT = interp1( num(:,1), num(:,2), 298.15, 'nearest', 'extrap' );
is delivers the index of the cell, where the char 'TOTAL' is stored and the third line delivers the value next to 298.15.

Matlab: repeat string elements N times

I have a 1x500 cell of words that have variable length. For example:
words = {'SO','TODAY', 'IS', 'THURSDAY',...}
In addition, I have two 500x1 arrays of integers, the first contains numbers referring to the starting row, the second contains numbers referring to the end row. For example:
startRow = 283 endRow = 309
309 332
332 367
... ...
What I need to do is, I need to fill a 1x3000 matrix of zeros from row 283-308 with the word 'SO' (so that the word is in every row), from row 309-331 with the word 'TODAY', from 332-367 with the word 'IS' and so on until the last element of endRow has been processed.
This is my code so far:
new_val = zeros(1,3000);
for t = 1:size(startRow,1)
count(1,t) = endRow(t)-startRow(t);
word{t} = words{t};
end
for i = 1:size(startRow,1)
new_val(1,startRow(i):endRow(i)-1) = repmat(word{1,i},count(i),1);
end
The problem occurs in the second loop because assignment dimensions mismatch. The size of the left hand element after one iteration is [1,26], the size of the right hand element is [26,2] after one iteration because apparently 'SO' is counted as 2 elements. I don't know what to do about this problem, so any suggestions, hints and tips are appreciated very much. Thank you!
You can't fill a matrix with strings !
So you have to create a [3000x1] cell array.
mycell = cell(3000,1);
And you fill the cell with:
for i = 1:length(startRow)
mycell(startRow(i):endRow(i)) = words(i);
end

Delete rows and columns of a matrix

I have the matrix below:
a = [1 2 1 4;
3 4 9 16;
0 0 -2 -4;
0 0 -6 -8]
How can I arbitrary remove any given rows or columns? for example second row and third column of the above matrix?
Just assign the column or line to the empty matrix:
a(2,:) = [];
a(:,3) = [];
Note : I compare the other solution to mine, following the link put inside. On a big array (created as rand(1e4)) and on 10 runs where I delete 2 columns and 2 rows, the average times are 0.932ms for the empty-matrix assignment, and 0.905ms for the kept-row (or -column) assignment. So the gap seen there is not as big as 1.5x mentioned in the link. Always perform a little benchmark first :) !
Edit Fastest solution is to create the index mask for rows and columns, and reassign your array with these masks. Ex:
a = rand(10000);
kr = true(size(a,1),1);
kr([72,6144]) = false; % some rows to delete
kc = true(1,size(a,2));
kc([1894,4512]) = false; % some columns to delete
a = a(kr,kc);
On this test, it's clearly twice faster than performing the suppression on rows and columns separately.
A slightly more efficient way (although possibly more complicated to set up) is to reassign all the rows you want to keep (when compared with setting the rows you want to delete to the empty matrix). So for example if you want to delete rows 5 and 7 from a matrix you can either do
A = A([1:4, 6, 8:end],:)
or
A = A(setdiff(1:size(A,1), [5,7] ),:)
but the best method is likely to use logical indexing (which is often a natural step in Matlab workflows anyway):
idx = true(size(A,1),1);
idx([5,7]) = false;
A = A(idx,:)

Using Matlab to randomly split an Excel Sheet

I have an Excel sheet containing 1838 records and I need to RANDOMLY split these records into 3 Excel Sheets. I am trying to use Matlab but I am quite new to it and I have just managed the following code:
[xlsn, xlst, raw] = xlsread('data.xls');
numrows = 1838;
randindex = ceil(3*rand(numrows, 1));
raw1 = raw(:,randindex==1);
raw2 = raw(:,randindex==2);
raw3 = raw(:,randindex==3);
Your general procedure will be to read the spreadsheet into some matlab variables, operate on those matrices such that you end up with three thirds and then write each third back out.
So you've got the read covered with xlsread, that results in the two matrices xlsnum and xlstxt. I would suggest using the syntax
[~, ~, raw] = xlsread('data.xls');
In the xlsread help file (you can access this by typing doc xlsread into the command window) it says that the three output arguments hold the numeric cells, the text cells and the whole lot. This is because a matlab matrix can only hold one type of value and a spreadsheet will usually be expected to have text or numbers. The raw value will hold all of the values but in a 'cell array' instead, a different kind of matlab data type.
So then you will have a cell array valled raw. From here you want to do three things:
work out how many rows you have (I assume each record is a row) by using the size function and specifying the appropriate dimension (again check the help file to see how to do this)
create an index of random numbers between 1 and 3 inclusive, which you can use as a mask
randindex = ceil(3*rand(numrows, 1));
apply the mask to your cell array to extract the records matching each index
raw1 = raw(:,randindex==1); % do the same for the other two index values
write each cell back to a file
xlswrite('output1.xls', raw1);
You will probably have to fettle the arguments to get it to work the way you want but be sure to check the doc functionname page to get the syntax just right. Your main concern will be to get the indexing correct - matlab indexes row-first whereas spreadsheets tend to be column-first (e.g. cell A2 is column A and row 2, but matlab matrix element M(1,2) is the first row and the second column of matrix M, i.e. cell B1).
UPDATE: to split the file evenly is surprisingly more trouble: because we're using random numbers for the index it's not guaranteed to split evenly. So instead we can generate a vector of random floats and then pick out the lowest 33% of them to make index 1, the highest 33 to make index 3 and let the rest be 2.
randvec = rand(numrows, 1); % float between 0 and 1
pct33 = prctile(randvec,100/3); % value of 33rd percentile
pct67 = prctile(randvec,200/3); % value of 67th percentile
randindex = ones(numrows,1);
randindex(randvec>pct33) = 2;
randindex(randvec>pct67) = 3;
It probably still won't be absolutely even - 1838 isn't a multiple of 3. You can see how many members each group has this way
numel(find(randindex==1))

Cell Array: show content and print name cell UITABLE

It is a basic problem but I am not so much experienced in Matlab(Guide).
What I have now is a cell array called Z with 21x2 elements: 21 rows 2 columns.
What I would like to do is to get only the first column (to show only 21x1).
Then, in this column there is a list of names. Inside the 21 rows of this cell there are repeated names. I would like to run through each row of this 21x1 column, detect which are repeated. The repeated ones should be printed in the uitable in a white colour.
Any ideas?
I believe this should deal with the core of your question:
A={'abc' 6;'de' 7;'abc' 8};
[C, ia] = unique(A(:,1));
idx = setdiff(1:size(A,1),ia);
A(idx,1)
This code will list all duplicates.