The code snippet came from the official documentation of xlwings here and it is the setup for my question.
import xlwings as xw
sht = xw.Book().sheets[0]
sht.range('A1').value = [['Foo1', 'Foo2'], [1, 2]]
chart = sht.charts.add()
chart.set_source_data(sht.range('A1').expand())
chart.chart_type = 'line'
chart.name
Running print(chart.api) outputs the tuple below.
(<xlwings._xlwindows.COMRetryObjectWrapper at 0x1fcd60c9a90>, <xlwings._xlwindows.COMRetryObjectWrapper at 0x1fcd60c9f28>)
If I want to use the api attribute to do some basic chart manipulation like remove the legend and add a title, it only works if I do it to chart.api[1]. For instance the code below works fine. It removes the chart legend and adds a title.
chart.api[1].HasLegend = 0
chart.api[1].SetElement(2)
chart.api[1].ChartTitle.Text = 'A title'
However, anything I do to chart.api[0] yields an error, (for instance print(chart.api[0].HasLegend) yields an error). I can't understand what kind of object this is or how it is useful. I can't find anything regarding this in the official documentation.
Finally my question is: what is the object at the index 0 above? Please, help me grok what it is.
There is another post that addresses your question about the object at the index 0.
set chart name in Xlwings
The expression chart.api returns a tuple with two COM wrappers. I'm
not really sure why there are two COM wrappers, but it seems that you
need the second one to access the chart. Hence the use of chart.api[1]
here.
Related
After trying to use openpyxl to try to know which styles is applied in order to get the the actual background color of a cell after the conditional formatting has been applied and realized that I would have to write a formula parser (and it makes no sense to re-write excel and I would have to deal with chained formula cell values, etc).
I am now reaching the PyUno interface to get access via a libreoffice instance running headless and reaching the XSheetConditionalEntry object trough the PyOO interface.
Looks that I have reached the exact same place, I have the cell and the formula; but no way of knowing which of the conditional formatting styles applies or not:
def processFile(filename):
soffice = subprocess.Popen(officeCommand, shell=True)
desktop = pyoo.Desktop(pipe='hello')
doc = desktop.open_spreadsheet(filename)
sheet = doc.sheets['STOP FS 2023']
cell = sheet[5,24]
cellUno = cell._get_target()
print(f"{cellUno.getPropertyValue('CellBackColor')=}")
print(f"{cellUno.getPropertyValue('CellStyle')=}")
for currentConditionalFormat in cellUno.getPropertyValue('ConditionalFormat'):
print(f"{currentConditionalFormat.getStyleName()=}")
print(f"{currentConditionalFormat.getOperator()=}")
getting the following results
cellUno.getPropertyValue('CellBackColor')=-1
cellUno.getPropertyValue('CellStyle')='Default'
currentConditionalFormat.getStyleName()='ConditionalStyle_4'
currentConditionalFormat.getOperator()=<Enum instance com.sun.star.sheet.ConditionOperator ('BETWEEN')>
currentConditionalFormat.getStyleName()='ConditionalStyle_3'
currentConditionalFormat.getOperator()=<Enum instance com.sun.star.sheet.ConditionOperator ('NONE')>
currentConditionalFormat.getStyleName()='ConditionalStyle_2'
currentConditionalFormat.getOperator()=<Enum instance com.sun.star.sheet.ConditionOperator ('NONE')>
currentConditionalFormat.getStyleName()='ConditionalStyle_1'
currentConditionalFormat.getOperator()=<Enum instance com.sun.star.sheet.ConditionOperator ('NONE')>
The style that is being applied is the ConditoinalStyle_3
This post has helped a bit but it is intended to work inside of a macro, and looks like heir forum sign up is broken, as I would would have tried to ask the same question over there.
I am struggling with the following using openpyxl version 3.0.7
I want to copy the style of one cell to another. That means, background colour, font, etc.
However, I don't know how I can do that.
My initial idea was basically to do
sheet["E1"].font = sheet["D1"].font.
That bit shoots out TypeError: unhashable type: 'StyleProxy'.
Using just .style doesn't really do all that much so it's not suitable.
I found a few solutions online like the one from here. However, I don't know how I can apply it to my specific needs seeing as I struggle to even transfer the font from one cell to another.
Shortly after typing this out, I found the solution.
from copy import copy
wb = openpyxl.load_workbook('C:\\path...\\')
sheet = wb["Name of the worksheet"]
sheet["E1"].font = copy(sheet["D1"].font)
sheet["E1"].border = copy(sheet["D1"].border)
sheet["E1"].fill = copy(sheet["D1"].fill)
sheet["E1"].number_format = copy(sheet["D1"].number_format)
sheet["E1"].protection = copy(sheet["D1"].protection)
sheet["E1"].alignment = copy(sheet["D1"].alignment)
The only thing left to do would be to do this in a loop. That would be achievable by doing something like
for i in range(....):
sheet["E" + str(i)].font= copy(sheet["D" +str(i)].font)
etc.
There are several objects in the SmartSheet SDK API which are extensions of objects. For instance, CellLink and ObjectValue are an extensions of the Cell object. I've done some reading and understand that these are parent/child classes and involve inheritance. However, this concept still escapes me and I cannot figure out the syntax for creating a CellLink object.
new_cell = ss.models.Cell()
linked_cell = ss.models.Cell()
linked_cell.column_id = int(columnid)
linked_cell.sheet_id = int(sheetid)
linked_cell.row_id = int(rowid)
new_cell.link_in_from_cell = linked_cell
The example above gives me the most informative error message therefore, I assume it is the closest to the correct syntax of all the variations I have tried. Any help with this example and possibly the underlying concept would be greatly appreciated.
raise ValueError("`{0}` invalid type for {1} value".format(value,
self.object_type))
ValueError: `{"columnId": 2068210422966148}` invalid type for <class
'smartsheet.models.cell_link.CellLink'> value
I believe I have found the answer to this question. It seems as though you just need to create a dictionary of the attributes like:
ex_dict = {sheet_id: 0974792938, column_id: 07263839242, row_id:
2632938474839}
new_cell.link_in_from_cell = ex_dict
The trick is later in the code. Instead of creating a new row like:
row = ss.models.Row()
You need to update an existing row like:
row = ss.Sheets.get_row(sheet_id, row_id)
However, I am still having a weird error of:
Field \"createdAt\" was of unexpected type.
You should be sending Row and Cell objects with only the properties that you wish to change. You do not want to attempt to modify an existing Row object (e.g. with the createdAt property, but rather allocate a new one with appropriate row id and cells to update.
See https://github.com/smartsheet-samples/python-snippets/blob/04951c2ca8ae1a97386bdd3fa6e010f2845e1421/samples.py#L45 for a complete example of creating a cell link.
I have looked into many stackoverflow questions but none of them seemed to solve my problem. I am using Python and Openpyxl to fill a whole row with red given a certain condition. I did all the importations necessary :
from openpyxl.styles import PatternFill, NamedStyle, Color
from openpyxl.styles.colors import RED
And my code is the following :
for cell in sheet[i]:
cell.style = NamedStyle(fill=PatternFill(patternType='solid',
fill_type='solid',
fgColor=Color(RED)))
When I ask to print the first occurence of cell it gives me
<Cell 'Divers'.A4>
which is what I am looking for.
However, the following error comes every time : "Style Normal exists already". There is absolutely no cell formatting or style whatsoever in the rest of the code but the Excel file cells are indeed filled with yellow already.
Any idea on how to solve this ? Thanks in advance for any help.
If using a NamedStyle, you're required to pass a name.
red_foreground = NamedStyle(
name="RedForeground",
fill=PatternFill(
patternType='solid',
fill_type='solid',
fgColor=Color(RED)
)
)
Since you're assigning this NamedStyle to more than one cell, it makes sense to register it to your workbook.
wb.add_named_style(red_foreground)
Then you can update it's application to cells, like so:
for cell in sheet[i]:
cell.style = "RedForeground"
Reference:
Creating NamedStyle
NamedStyle Constructor
I also have this problem, and finally found that it was because there were 2 styles, of which had the same name. This is usually caused when you use copy.copy(style). Then after change one of the style.name = 'newname', it will work.
This code would solve already existing named styles.
for index,cur_style in enumerate(excel_workbook._named_styles):
if cur_style.name == 'my_new_style':
excel_workbook._named_styles[index] = my_new_style
my_new_style.bind(excel_workbook)
break
else:
excel_workbook.add_named_style(my_new_style)
However, in your case, you should use some other name than "Normal", because "Normal" is the default named style, just find another name and you can use the code I pasted
There is another way to solve traceback by adding existing styles:
if not 'Style_A' in wb.named_styles:
wb.add_named_style(Style_A)
The tooltip example presented in the reference guide show the following examples of formatting:
hover.tooltips = [
("index", "$index"),
("(x,y)", "($x, $y)"),
("radius", "#radius"),
("fill color", "$color[hex, swatch]:fill_color"),
("foo", "#foo"),
("bar", "#bar"),
("baz", "#baz{safe}"),
("total", "#total{$0,0.00}"
The 3 examples {safe}, {$0,0.00} and "$color[hex, swatch]:fill_color" are not clear: where can i find some documentation on them?
Basically I would like to understand what is possible and what isn't.
At the moment (for instance) I have 1 input that us a very long string (its a newspaper article) that I would like to format so it only shows the x first characters.
Other example I have a field #datetime that is retrieving its value from a datetime index. At the moment the tooltip displays that value as a int64 character. How to use a format tool such as Timestamp.strftime("%d-%m-%Y") so that it shows the date time in human readable format?
But I would like to have a clearer overview of what is possible/how that aspect of bokeh works
Since this answer was originally posted, new work has gone into Bokeh to make things simpler. A datetime field can be formatted as a datetime directly by the hover tool, by specifying a formatter, e.g.:
HoverTool(tooltips=[('label', '#datetime{%F}')],
formatters={'datetime': 'datetime'})
It is no longer necessary to pre-format date fields in the data source as below (although it certainly still works). For more information see Formatting Tooltip Fields
OLD ANSWER:
This is still an open issue for the project:
https://github.com/bokeh/bokeh/issues/1239
However, given some other recent work, this should now be fairly easy to implement this feature in a natural way. I have scheduled the task for the next 0.12.6 milestone.
Also, although Bokeh has extensive and rich documentation, there are still occasional gaps. This happens to be one of them, unfortunately. I note that there is an open issue to improve this:
https://github.com/bokeh/bokeh/issues/2595
I've updated it to make sure it is also included in the 0.12.6 milestone.
In the mean time, your best option is to pre-format the data as you want it to appear in the tooltip in Python. Then add a column to your data source that has the formatted version, the configure the hover tool to display this column:
source.data['formatted_date'] = my_pretty_print(source.date['date'])
hover.tooltips = [ ("date", "#formatted_date") ]