Exporting uitable data to excel using matlab for macintosh - excel

I am stuck trying to export matlab uitable data to excel. I tried many things, and It has been impossible to solve this problem. After many days, I tried the code below using windows and it does work perfect, however, using the same for Macintosh is not longer working. The output is as follows:
"Error using dlmwrite (line 118) The input cell array cannot be converted to a matrix"
Searching for more information, I found an answer here ,(Using "xlswrite" MATLABs for cell arrays containing strings of different size) which doesn't work perfect. Finally I found this method which applies only for matlab using windows (http://www.mathworks.es/matlabcentral/answers/20819-export-uitable-s-data-to-a-spreadsheet-excel).
I hope you can help me with this problem.
Thanks in advance
Hector
function Save_File
hf = figure;
hExportButton = uicontrol('Parent',hf,'Units',...
'normalized','Position',[0 0.81 0.22 0.18],'Style','Pushbutton',....
'String',' Export Data!','FontSize',20,'Callback',#ExportButton_Callback);
dat = rand(5,5);
t=uitable('Data',dat,'ColumnName',{'First','Second','Third','Fourth','Fifth'},...
'Position',[7 10 500 300]);
Data=get(t,'Data');
ColumnName=get(t,'ColumnName');
set(t,'ColumnWidth',{93.5})
function ExportButton_Callback(~,~)
NewData= num2cell(Data,ones(size(Data,1),1),ones(size(Data,2),1));
CombData=[ColumnName';NewData];
FileName = uiputfile('*.xls','Save as');
xlswrite(FileName,CombData);
end
end

You should be able to convert the cell array into a number array with a cell2mat command and then use csvwrite or dlmwrite.
If the combo of numbers and strings is the issue, as stated in my comment above, you can use some simple looping to do this all for you. I posted some sample code below.
% Creating some temporary data for proof of concept
mat = randi([1,5],10,2);
header = {'Col1','Col2'};
cellVals = [header;num2cell(mat)];
% the real code that does the writing
fh = fopen('temp.csv','w'); % open a file with write privileges, will overwrite old versions
for ii = 1:size(cellVals,1)
first = 1;
for jj = 1:size(cellVals,2)
if first
fwrite(fh,num2str(cellVals{ii,jj},'%f'));
first = 0;
else
fwrite(fh,[',',num2str(cellVals{ii,jj},'%f')]);
end
end
fwrite(fh,sprintf('\r\n')); % print line break
end
fclose(fh); % close file out when done writing

Related

How to download the workspace into an Excel sheet where I can update a variable in Excel and they update in MATLAB as well?

Suppose I have a generic MATLAB script as follows:
A = [1 2 0; 2 5 -1; 4 10 -1];
b = [1;3;5];
x = A\b;
r = A*x - b;
These variables will be stored in the Workspace. How can I download the Workspace variables (A, b, x, r) in an Excel sheet, such that I can modify the variables in Excel and upload that Excel sheet unto the Current Folder in MATLAB and have the Workspace updated to the changes I did in Excel? For example, I download the workspace in Excel. I open the Excel sheet and change r=A*x-b to r='Hello World'. Then I upload that sheet onto MATLAB, and the new 'r' updates in the Workspace.
Please consider the following approach as a reference
First, your arrays and operations can be defined as strings, which are then evaluated. Please take this part of my proposal with a grain of salt and make sure that the instructions that you are evaluating are syntactically valid. Keep in mind that the eval function has its own risks
% Clean your workspace
clear
close
clc
% Create your two arrays and additional variables
A = [1 2 0; 2 5 -1; 4 10 -1];
b = [1;3;5];
% Define all the necessary operations as strings. Make sure that these
% operations are absolutely valid before proceeding. Here you can spend
% some time defining some error-checking logic.
x_oper = "A\b";
r_oper = "A*x - b";
% To be safe, we evaluate if the instructions are valid,
% otherwise we throw an error --> typos and other stuff can go wrong!
try
x = eval(x_oper); % be careful!
r = eval(r_oper); % be careful!
sprintf("Expressions successfully evaluated!")
catch err
sprintf("Error evaluating expression >> %s\n", err.message)
end
The values and instructions can be then formatted as individual tables to be saved as .csv files, which can be read using excel (or LibreOffice in my case).
Save your 'workspace' contents into two different files. For the sake of clarity, I am using one file for values and another one for operations
% Define to filenames
varsFile = "pseudo-workspace.csv"
operFile = "operations.csv"
% Convert variables and operations/instructions to tables
dataTable = table(A, b, x, r)
instrTable = table(x_oper, r_oper)
% Write the tables to their respective files
writetable(dataTable, varsFile)
writetable(instrTable, operFile)
Where the dataTable looks like this:
and the instrTable with the operations is:
After this point, your work is saved in two different files and are ready to be edited elsewhere. Perhaps you want to share the file with someone else or yourself in case you don't have access to Matlab on a different computer and you need to change the operations and/or values. Then, on a different .m file you read these files to your current workspace and assign them to the same variable tags:
% Now we read the values and operations from a previous session or
% externally edited in excel/text editor
rawValuesTable = readtable(varsFile)
clear A % I only clear my variables since I am working on the same m file
clear b
clear x
clear r
% Now we read the values and operations from a previous session or
% externally edited in excel/text editor
rawValuesTable = readtable(varsFile)
% Retrieve the values from A and b from the table that we just read
A = [rawValuesTable.A_1, rawValuesTable.A_2, rawValuesTable.A_3];
b = rawValuesTable.b;
rawOperations = readtable(operFile);
% The operations are read as cell arrays, therefore we need to
% evaluate them as strings only with the suffix {1}
try
x = eval(rawOperations.x_oper{1})
r = eval(rawOperations.r_oper{1})
sprintf("Expressions successfully evaluated!")
catch err
sprintf("Error evaluating expression >> %s\n", err.message)
end
Finally obtaining the same output, granted nothing was changed:
You could execute both procedures (write/read) using two different functions. Once again, this is my take on your particular case and you will surely come up with different ideas based on this

Python loop list in function call

This is my first question on StackOverflow. I have always found what I was looking for just googling, but this time I'm stuck and can't figure it out.
I'm a beginner programmer with python and still learning a lot.
I want to change a dateEdit box in a Userinterface with a small code to set det current date time.
the code looks like this.
self.dateEdit_2.setDateTime(QtCore.QDateTime.currentDateTime())
Now i want to change every dateEdit box the same, starting from 2 and going to 29, without typing every single line out.
i have tried to make a for loop with a filled list.
and i get it to print out what i want, but how does i get "set_date_numb" to be a attribute that does what i want.
hope you understand, Thanks.
dateTimeList = ['2','3','4','5','6','7','8','9',
'10','11','12','13','14','15','16','17','18','19','20',
'21','22','23','24','25','26','27','28','29']
indexval = 0
for i in range(len(dateTimeList)):
date_numb = (dateTimeList[indexval])
set_date_numb ='self.dateEdit_{}.setDateTime(QtCore.QDateTime.currentDateTime())'.format(date_numb)
print(set_date_numb)
indexval += 1
You could use getattr(), see the documentation here. Since the functions you are after are members of your instance you can grab them with their names as strings (which I think is the main problem you are facing):
dateTimeList = [str(x) for x in range(2,30)]
for dt in dateTimeList:
name = "dateEdit_{}".format(dt)
currentDateEdit = getattr(self, name)
currentDateEdit.setDateTime(QtCore.QDateTime.currentDateTime())

Ironpython write to Excel

I am trying to write data from Revit to Excel with RevitPythonShell.
So far I have collected all data in a zipped list and made an enumerated for loop to write the data to the corresponding rows and columns as following:
for index, data in enumerate(wall_zipped_list):
for count, parameters in enumerate(data):
wall_cell = worksheet_wanden.Range[(str(column_list[count]))+str(index+5)]
wall_cell.Value2 = data[count]
This is incredibly slow because the loop is calling Value2 everytime. A Revit model containing about 800 walls takes 2 minutes to write to Excel. So I tried a different method using a dictionary.
for k , v in data_dict.iteritems():
#print k, v[0]
worksheet_wanden.Range["A"+str(count)].Value2 = k
worksheet_wanden.Range["B"+str(count)].Value2 = v[0]
worksheet_wanden.Range["C"+str(count)].Value2 = v[1]
worksheet_wanden.Range["D"+str(count)].Value2 = v[2]
worksheet_wanden.Range["E"+str(count)].Value2 = v[3]
worksheet_wanden.Range["F"+str(count)].Value2 = v[4]
worksheet_wanden.Range["G"+str(count)].Value2 = v[5]
worksheet_wanden.Range["H"+str(count)].Value2 = v[6]
worksheet_wanden.Range["I"+str(count)].Value2 = v[7]
worksheet_wanden.Range["J"+str(count)].Value2 = v[8]
worksheet_wanden.Range["K"+str(count)].Value2 = v[9]
count += 1
This method is already a lot quicker. This takes about 20 seconds to fill about 800 rows with 10 columns in Excel. Am I missing some IronPython functionality which you can write dictionary or lists to Excel rows or columns?
I also looked at installing 3d party modules. But this is not really an option since RevitPythonShell usising IronPython 2.7.3 and I can't get pip install to work.
Thanks in advance.
Is it maybe faster to write to csv first in IronPython and then import it some way into excel?
This is more of a question on .NET/Excel interop. I think, based on this SO question you should be able to assign an array to a range.
That is, your current range is just one cell. You could try creating a 2d System.Array and assign it to the range... I tried it out here:
```
import clr
clr.AddReference("Microsoft.Office.Interop.Excel")
import Microsoft.Office.Interop.Excel as Excel
excel = Excel.ApplicationClass()
excel.Visible = True # makes the Excel application visible to the user
workbook = excel.Workbooks.Add()
worksheet = workbook.Worksheets.Add()
from System import Array
xlrange = worksheet.Range["A1:c3"]
a = Array.CreateInstance(object, 3, 3)
i = 0
for row in range(3):
for column in range(3):
a[row, column] = i
i += 1
xlrange.Value2 = a
```
This produces a result like this:
More information on IronPython and Excel can be found here: http://www.ironpython.info/index.php?title=Interacting_with_Excel
You could try installing the xlwt module and use that - avoiding COM interop.
It works
i = 0
xlrange_revit_type = worksheet_data.Range["C2:C" + str(len(revit_type_list)+1)]
a = Array.CreateInstance(object,len(revit_type_list), 3)
while i < len(revit_type_list):
a[i,0] = revit_type_list[i]
i += 1
xlrange_revit_type.Value2 = a
Is it possible to install a 3d party module like xlwt for RevitPythonShell? I can't find any documentation.
If you're referring to the Cells notation that you can use in VB, I don't know why it does not work, but you could create a definition:
def Cells(a,b):
return str(chr(a+96) + str(b))
Now you could call something like:
x1range = ws.Range(Cells(1,1),Cells(5,10))
and it will work the same. That is what I do.

Python3 - Advice on a while loop with range?

Good afternoon! I am relatively new to Python - and am working on an assignment for a class.
The goal of this code is to download a file, add a line of data to the file, then create a while loop that iterates through each line of data, and prints out the city name and the highest average temp from the data for that city.
My code is below - I have the output working, no problem. The only issue I am running into is an IndexError: list index out of range - at the end.
I have searched on StackOverflow - as well as digging into the range() function documentation online with Python. I think I just need to figure to the range() properly, and I'd be done with it.
If I take out the range, I get the same error - so I tried to change the for/in to - for city in mean_temps:
The result of that was that the output only showed 4 of the 7 cities - skipping every other city.
Any advice would be greatly appreciated!
here is my code - the screenshot link below shows output and the error as well:
!curl https://raw.githubusercontent.com/MicrosoftLearning/intropython/master/world_temp_mean.csv -o mean_temp.txt
mean_temps = open('mean_temp.txt', 'a+')
mean_temps.write("Rio de Janeiro,Brazil,30.0,18.0")
mean_temps.seek(0)
headings = mean_temps.readline().split(',')
print(headings)
while mean_temps:
range(len(city_temp))
for city in mean_temps:
city_temp = mean_temps.readline().split(',')
print(headings[0].capitalize(),"of", city_temp[0],headings[2], "is", city_temp[2], "Celsius")
mean_temps.close()
You have used a while loop, when you actually want to use a for loop. You have no condition on your while loop, therefore, it will evaluate to True, and run forever. You should use a for loop in the pattern
for x in x:
do stuff
In your case, you will want to use
for x in range(len(city_temp)):
for city in means_temp:
EDIT:
If you have to use a while loop, you could have variable, x, that is incremented by the while loop. The while loop could run while x is less than range(len(city_temp)).
A basic example is
text = "hi"
counter = 0
while counter < 10:
print(text)
counter += 1
EDIT 2:
You also said that they expected you to get out of a while loop. If you want a while loop to run forever unless a condition is met later, you can use the break command to stop a while or for loop.
I've been stuck with this as well with the index error. My original code was:
city_temp = mean_temp.readline().strip(" \n").split(",")
while city_temp:
print("City of",city_temp[0],headings[2],city_temp[2],"Celcius")
city_temp = mean_temp.readline().split(",")
So I read the line then, in the loop, print the line, create the list from reading the line and if the list is empty, or false, break. Problem is I was getting the same error as yourself and this is because city_temp is still true after reading the last line. If you add..
print(city_temp)
to your code you will see that city_temp returns as "" and even though it's an empty string the list has content so will return true. My best guess (and it is a guess) it looks for the split condition and returns back nothing which then populates the list as an empty string.
The solution I found was to readline into a string first (or at the end of the whole loop) before creating the list:
city_temp = mean_temp.readline()
while city_temp:
city_temp = city_temp.split(',')
print(headings[0].capitalize(),"of",city_temp[0],headings[2],"is",city_temp[2],"Celcius")
city_temp = mean_temp.readline()
This time city_temp is checked by the while loop as a string and now returns false. Hope this helps from someone else who struggled with this

How to write Fortran Output as CSV file?

Can any one tell me, how can I write my output of Fortran program in CSV format? So I can open the CSV file in Excel for plotting data.
A slightly simpler version of the write statement could be:
write (1, '(1x, F, 3(",", F))') a(1), a(2), a(3), a(4)
Of course, this only works if your data is numeric or easily repeatable. You can leave the formatting to your spreadsheet program or be more explicit here.
I'd also recommend the csv_file module from FLIBS. Fortran is well equipped to read csv files, but not so much to write them. With the csv_file module, you put
use csv_file
at the beginning of your function/subroutine and then call it with:
call csv_write(unit, value, advance)
where unit = the file unit number, value = the array or scalar value you want to write, and advance = .true. or .false. depending on whether you want to advance to the next line or not.
Sample program:
program write_csv
use csv_file
implicit none
integer :: a(3), b(2)
open(unit=1,file='test.txt',status='unknown')
a = (/1,2,3/)
b = (/4,5/)
call csv_write(1,a,.true.)
call csv_write(1,b,.true.)
end program
output:
1,2,3
4,5
if you instead just want to use the write command, I think you have to do it like this:
write(1,'(I1,A,I1,A,I1)') a(1),',',a(2),',',a(3)
write(1,'(I1,A,I1)') b(1),',',b(2)
which is very convoluted and requires you to know the maximum number of digits your values will have.
I'd strongly suggest using the csv_file module. It's certainly saved me many hours of frustration.
The Intel and gfortran (5.5) compilers recognize:
write(unit,'(*(G0.6,:,","))')array or data structure
which doesn't have excess blanks, and the line can have more than 999 columns.
To remove excess blanks with F95, first write into a character buffer and then use your own CSV_write program to take out the excess blanks, like this:
write(Buf,'(999(G21.6,:,","))')array or data structure
call CSV_write(unit,Buf)
You can also use
write(Buf,*)array or data structure
call CSV_write(unit,Buf)
where your CSV_write program replaces whitespace with "," in Buf. This is problematic in that it doesn't separate character variables unless there are extra blanks (i.e. 'a ','abc ' is OK).
I thought a full simple example without any other library might help. I assume you are working with matrices, since you want to plot from Excel (in any case it should be easy to extend the example).
tl;dr
Print one row at a time in a loop using the format format(1x, *(g0, ", "))
Full story
The purpose of the code below is to write in CSV format (that you can easily import in Excel) a (3x4) matrix.
The important line is the one labeled 101. It sets the format.
program testcsv
IMPLICIT NONE
INTEGER :: i, nrow
REAL, DIMENSION(3,4) :: matrix
! Create a sample matrix
matrix = RESHAPE(source = (/1,2,3,4,5,6,7,8,9,10,11,12/), &
shape = (/ 3, 4 /))
! Store the number of rows
nrow = SIZE(matrix, 1)
! Formatting for CSV
101 format(1x, *(g0, ", "))
! Open connection (i.e. create file where to write)
OPEN(unit = 10, access = "sequential", action = "write", &
status = "replace", file = "data.csv", form = "formatted")
! Loop across rows
do i=1,3
WRITE(10, 101) matrix(i,:)
end do
! Close connection
CLOSE(10)
end program testcsv
We first create the sample matrix. Then store the number of rows in the variable nrow (this is useful when you are not sure of the matrix's dimension beforehand). Skip a second the format statement. What we do next is to open (create or replace) the CSV file, names data.csv. Then we loop over the rows (do statement) of the matrix to write a row at a time (write statement) in the CSV file; rows will be appended one after another.
In more details how the write statement works is: WRITE(U,FMT) WHAT. We write "what" (the i-th row of the matrix: matrix(i,:)), to connection U (the one we created with the open statement), formatting the WHAT according to FMT.
Note that in the example FMT=101, and 101 is the label of our format statement:
format(1x, *(g0, ", "))
what this does is: "1x" insert a white space at the beginning of the row; the "*" is used for unlimited format repetition, which means that the format in the following parentheses is repeated for all the data left in the object we are printing (i.e. all elements in the matrix's row). Thus, each row number is formatted as: 'g0, ", "'.
g is a general format descriptor that handles floats as well as characters, logicals and integers; the trailing 0 basically means: "use the least amount of space needed to contain the object to be formatted" (avoids unnecessary spaces). Then, after the formatted number, we require the comma plus a space: **", ". This produces our comma-separated values for a row of the matrix (you can use other separators instead of "," if you need). We repeat for every row and that's it.
(The spaces in the format are not really needed, thus one could use format(*(g0,","))
Reference: Metcalf, M., Reid, J., & Cohen, M. (2018). Modern Fortran Explained: Incorporating Fortran 2018. Oxford University Press.
Tens seconds work with a search engine finds me the FLIBS library, which includes a module called csv_file which will write strings, scalars and arrays out is CSV format.

Resources