openpyxl LineChart appears empty after adding reference to values - excel

I have the following code to create a line chart in Excel using openpyxl. The problem is that when the excel file is generated, the chart container is added to the worksheet, but it is empty and no chart is displayed. I've checked the reference object and looks fine. Any idea of what could be causing this?
c1 = LineChart()
c1.title = "Line Chart"
c1.style = 10
c1.y_axis.title = 'Utilization'
c1.x_axis.title = 'Month'
data = Reference(worksheet, min_col = 2, min_row = 2, max_col = 2, max_row = 10)
print(data) #this prints Sheet 1!$B$2:$B$10
c1.add_data(data)
worksheet.add_chart(c1, "E2")

I had very similar issue with openpyxl. It turned out to be a hyphen character ('-') in the worksheet name which used later in the x and y data reference for series. I replaced the hyphen with underscore ('_') character and it worked.
In your case replace the space in the worksheet name, or add single quotes before and after sheet name, i.e. 'Sheet 1'

ws = wb.create_sheet(title = work_sheet_name.replace('-', '_'))

Related

update data via macro from another workbook

I need some help with vba code. I'm self-lerning so please be understanding for simply cases ;)
I'm trying to create macro which will be looking for some records/cells in one workbook (FileA) (determined by 3 conditions) and then paste values to another workbook (FileB) and after that find in another tab in FileB some values where condition will be pasted value to match them with looking value (I belivie it could be done somehow with Vlookup but I get stuck).
Below problematic for me part of code (I'm working on some files found in work, no one use it now).
First issue is with Set Update, I don't know why it takes it as "Nothing"... conditions are true - I mean "pp1" is existing in column A in FileA.
Second issue shows when I change i start range to some "later" numbers, eg From i = 2280, macro is ignoring last line where should assign some values (again shows update2 as "nothing") but value if pp2 is existing in W column in tab data...
Dim name As String
name = "[path to file on sharepoint]"
Application.ScreenUpdating = False
Workbooks.Open Filename:=name
a = 1
For i = 2263 To 14000
If Workbooks("FileA").Sheets("Main").Cells(i, 11) = "CANCEL" And Workbooks("FileA").Sheets("Main").Cells(i, 6) = "DENIS" And Workbooks("FileA").Sheets("Main").Cells(i, 5) > 1301358454 Then
pp1 = Workbooks("FileA").Sheets("Main").Cells(i, 1)
If pp1 > 0 Then
Set Update = Workbooks("FileA").Worksheets("Main").Range("A:A").Find(pp1, lookat:=xlPart)
If Update > 0 Then
Update = Update.Row
Workbooks("FileB").Worksheets("lost").Cells(a, 1).Value = Workbooks("FileA").Worksheets("Main").Cells(Update, 5)
pp2 = Workbooks("FileB").Worksheets("lost").Cells(a, 1)
update2 = Workbooks("FileB").Worksheets("data").Range("W:W").Find(pp2, lookat:=xlPart).Row
Workbooks("FileB").Worksheets("lost").Cells(a, 5) = Workbooks("FileB").Worksheets("data").Cells(update2, 43)

Case insensitive search of an Excel file using Pandas read_excel

I need to get sheets from an Excel file with a certain name. Unfortunately sometimes the sheet names are not formatted correctly ie "Test Sheet" vs "Test sheet". I need a case insestive way of getting these sheets.
excel_file= pd.ExcelFile("file_name.xlsx")
sheet_needed = pd.read_excel(excel_file, sheet_name="Test Sheet") # <- This needs to be case insensitive
So pandas doesnt seem to have a good way of having a case insensitive search, However you can get the sheetnames as a list and pd.read will accept an index for the sheet name so I came up with this to solve the problem
excel_file= pd.ExcelFile("file_name.xlsx")
sheet_to_find = "Test Sheet"
# Get all the sheetnames as a list
sheet_names = excel_file.sheet_names
# Format the list of sheet names
sheet_names = [name.lower() for name in sheet_names]
# Get the index that matches our sheet to find
index = sheet_names.index(sheet_to_find.lower())
# Feed this index into pandas
sheet_needed = pd.read_excel(excel_file, sheet_name=index)
I don't know how to make that request case insesitive, but you could try to manipulate the file with openpyxl something like this:
import openpyxl
filename = 'file_name.xlsx'
wb = openpyxl.load_workbook(filename)
for ws in wb.worksheets:
ws.title = ws.title.title()
filename = 'new_'+filename
wb.save(filename)
wb.close()
the old title gets replaced with the 'titlelized' name of itself. You could also use the lower() or upper() function of the str object for that.

How can I stop python-docx from inserting a carriage return before my cell text

I want a paragraph inside a cell, but I get a stray carriage return which pushes down the text by one line:
My code:
from docx import Document
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Cm
document = Document()
document.add_heading("The Heading", 1).alignment = WD_ALIGN_PARAGRAPH.CENTER
table = document.add_table(rows=0, cols=2)
table.style = 'Table Grid'
for i in range(3):
row_cells = table.add_row().cells
row_cells[0].text = 'row {}, col 1'.format(i)
row_cells[0].width = Cm(3)
row_cells[1].width = Cm(8)
p = row_cells[1].add_paragraph()
p.add_run('This is an example of')
p.add_run(' some text').bold = True
p.add_run(' in a table cell.')
document.save('test.docx')
How can I get the cell text to align at the top of the cell without the stray CR? And how should I be setting the cell widths to 3 cm and 8 cm: setting _Cell.width isn't respected.
I worked this out: you get a free paragraph with each cell, so I just needed to add my text runs to this paragraph:
p = row_cells[1].paragraphs[0]
p.add_run('This is an example of')
p.add_run(' some text').bold = True
p.add_run(' in a table cell.')
To set the widths, I had to manipulate the columns directly and not set them cell-by-cell (despite this answer):
table.columns[0].width = Cm(3)
table.columns[1].width = Cm(8)
Tanks for the clear_content it made my image not to be placed beneath a linefeed, tanks for the coment, it was the last pice of advice I needed after hours of problemsolving:
#This seams to clear the content in my cell
tables[1].rows[0].cells[4]._element.clear_content()
#Then when the image is inserted to the cell it is not placed one linefeed down.
img = tables[1].rows[0].cells[4].add_paragraph().add_run().add_picture('AgressoLogga.png', width=Inches(0.4))

Using Matlab to create Excel charts with X and Y values from range

I have about 20 columns of data, each ~20,000 rows. All calculations are done in Matlab, and then charts are created.
Unfortunately, I need the whole output to be in an Excel File, including several editable charts. Using xlswrite I created the Excel file, now I am struggling to create the charts the way I want.
I tried using this code, but got several errors and wasn't able to choose the X and Y Values of the chart.
Excel = actxserver('Excel.Application');
WB = Excel.workbooks.Open('D:\...\Test.xlsx');
Charts = WB.Charts;
Chart = invoke(Charts,'Add');
invoke(Chart, 'SetSourceData', Excel.Range('Sheet1!$B$2:$B$16')); %% here an error occurs
The error:
Error using COM.Excel_Application/Range. Object returned error code: 0x800A03EC"
I have not been able to find any solutions for adding charts through the ActiveX object in Matlab. Any posts I have found on this topic were outdated or unhelpful.
Summary, my question is:
How can I insert charts in Excel using Matlab (using a general, up to date ActiveX code structure).
How can I select the columns for the XValue and the YValues (Range)
How can I get access to chart titles, axes, line appearance and legend
I'm using Excel 2016 and Matlab R2017a.
Edit:
during this week I developed a own solution, that still doesn't work perfectly but is close to what I want. Could you have a look on this code too please:
Important is only chart1. I wanted to set the XValue to column B and the YValues to column H - P of the sheet1 (Tabelle1).
%%%%% general Code to insert a Chart in Excel using Matlab %%%%%
%% start Excel and open Workbook
excel = actxserver('Excel.Application');
wb = excel.Workbooks.Open('C:\...\Test.xlsx');
%% makes the created sheet visible
excel.Visible = true;
%% add 1. Chart
chart1 = wb.Charts.Add;
%% set source data
chart1.SetSourceData(wb.Worksheets.Item('Tabelle1').Range('$B:$B, $H:$P')); % 'Tabelle1' is the german equal to sheet1, my excel is german
%% Name chart sheet
chart1.Name = '1. TestChart';
%% Set chart title, see https://msdn.microsoft.com/en-us/library/office/ff196832.aspx
chart1.HasTitle = true;
chart1.ChartTitle.Text = 'Test Title';
%% Set chart types, see https://msdn.microsoft.com/en-us/library/office/ff837417.aspx
chart1.ChartType = 'xlXYScatterSmoothNoMarkers';
%% Set chart legend, see https://msdn.microsoft.com/en-us/library/office/ff821884.aspx
chart1.HasLegend = true;
%% Set Axes Titles
chart1.Axes(1).HasTitle = true;
chart1.Axes(1).AxisTitle.Text = 'Time [s]'; % XAxes
chart1.Axes(2).HasTitle = true;
chart1.Axes(2).AxisTitle.Text = 'Temperature[°C]'; %YAxes
%% add 2nd chart
chart2 = wb.Charts.Add([], chart1); %place after chart1
chart2.SetSourceData(wb.Worksheets.Item('Tabelle1').Range('$B:$B, $Q:$Q'));
% ... same procedure as above
%% use to quit all open Excel processes
% excel.Quit;
another Error occurs:
Error using Interface.000208D8_0000_0000_C000_000000000046/Range
Error: Object returned error code: 0x800A03EC
Error in CodeTestmy (line 13)
chart1.SetSourceData(wb.Worksheets.Item('Tabelle1').Range('$B:$B, $H:$P'));
for now this question is nearly answered. For further bug related answers have a look at a related question
As I suggested in the comments, a better documented method for doing this would be to use VBA. As it happens, the VBA documentation can actually be used to take most of the guesswork out of interacting with the COM object directly from Matlab, as the syntax is similar.
Here is some updated Matlab code which achieves your three points. I have included links to the MSDN documentation where appropriate:
% Start Excel and open workbook
Excel = actxserver('Excel.Application');
WB = Excel.Workbooks.Open('C:\...\test.xlsx');
% Show the workbook
Excel.visible = 1;
% Add chart
Chart = invoke(WB.Charts,'Add');
% Get Sheet object
SheetObj = Excel.Worksheets.get('Item', 'Sheet1');
% Name chart sheet
Chart.Name = 'TestChart';
% Set source data range of chart
% X and Y data can also be set to Matlab arrays, by Srs.Values and Srs.XValues, ensuring equal length
% Y data
Srs = Chart.SeriesCollection.Add(SheetObj.Range('B2:B16'));
% X data, could be a Matlab array of correct length
Srs.XValues = SheetObj.Range('A2:A16');
% Series name
Srs.Name = 'Test Series';
% For chart types, see https://msdn.microsoft.com/en-us/library/office/ff837417.aspx
Chart.ChartType = 'xlXYScatterSmooth';
% Set chart title, see https://msdn.microsoft.com/en-us/library/office/ff196832.aspx
Chart.HasTitle = true;
Chart.ChartTitle.Text = 'Test Title';
% Set chart legend, see https://msdn.microsoft.com/en-us/library/office/ff821884.aspx
Chart.HasLegend = true;
Your error:
You were encountering an error because you were trying to access the Range object of the Excel application. This doesn't exist! All Range objects belong to a Sheet object, which is what I retrieve first in the above code.
Creating many series:
You say you have many columns of data, here is a way to include them through a loop. It also finds the last used row in each column.
% ... CREATE WORKBOOK / CHART AS BEFORE ...
%
Chart.Name = 'TestChart';
% Set source data range of chart, do X and Y data for each series
columns = 2:4;
colnames = {'xdata', 'my series 1', 'my series 2', 'my series 3'};
for col = columns
% Get Excel column *letter* from column *number*
colchar = strrep([char(96+floor((col-1)/26)) char(97+rem(col-1,26))],char(96),'');
% Last row of data, see https://msdn.microsoft.com/en-us/library/office/ff839539.aspx
% Data must be contiguous (no gaps / blank cells)
lastrow = num2str(SheetObj.Range([colchar, '2']).End('xlDown').Row);
% Y data, creating range strings by concatenation of column character and row number
Srs = Chart.SeriesCollection.Add(SheetObj.Range([colchar, '2:', colchar, lastrow]));
% X data, same approach is used for last row, but only column = 1 = "A"
Srs.XValues = SheetObj.Range(['A2:A', lastrow]);
% Set column name, to use the first row do
% Srs.Name = SheetObj.Range([colchar, '1']);
Srs.Name = colnames{col};
end
Chart.ChartType = 'xlXYScatterSmooth';
%
% ... TITLE / LEGEND AS BEFORE ...
Output chart sheet and input "Sheet1":
Edit:
In the above, I loop over the column numbers to populate the y data. If you know the column letter then you can just loop over colchar instead of creating it.
% There are shortcuts to creating a cell array of consecutive letters,
% Like columnletters = cellstr(('H':'J')');
for colchar = {'H', 'I', 'J'};
% ... same as the above for loop, but don't need to get colchar from col
lastrow = num2str(SheetObj.Range([colchar, '2']).End('xlDown').Row);
Srs = Chart.SeriesCollection.Add(SheetObj.Range([colchar, '2:', colchar, lastrow]));
Srs.XValues = SheetObj.Range(['A2:A', lastrow]);
Srs.Name = SheetObj.Range([colchar, '1']);
end

How to insert data into excel in Horizontal?

import xlwt
wb = xlwt.Workbook(encoding='utf-8')
ws = wb.add_sheet('Sheet1', cell_overwrite_ok=True)
data = (
[(1,),(2,),(3,)],
[('a',),('b',),('c',)],
[('e',),('f',),('g',)],
)
for index, value in enumerate(data):
for r_num, r_value in enumerate(value):
ws.write(r_num, index,r_value[0])
wb.save('test.xls')
My result is as below. But how can I insert mydata into excel in Horizontal?
If I understand you question the right way, you want the numbers to be in the top row. If so, you can just replace ws.write(r_num, index,r_value[0]) with ws.write(index, r_num,r_value[0]).

Resources