You need to use the styler object and not the dataframe to call to_excel(). Something like this:
import pandas as pd
def highlight(val):
if isinstance(val, (int, float)):
color = 'red' if val < 0 else 'green'
return 'color: %s' % color
df_final = pd.DataFrame({'Data': [1, "foo", -1, -5, 5, 6, -5]})
writer = pd.ExcelWriter('pandas_test.xlsx', engine='xlsxwriter')
styler = df_final.style.applymap(highlight)
styler.to_excel(writer)
writer.save()
Output:

Updated the highlight() function to have it only apply to numbers. You may need to strengthen/extend it a bit more for other data types.
Alternatively, you could use an Excel conditional format, like this:
import pandas as pd
# Create a Pandas dataframe from some data.
df_final = pd.DataFrame({'Data': [1, "Foo", -1, -5, 5, 6, -5]})
# Create a Pandas Excel writer using XlsxWriter as the engine.
writer = pd.ExcelWriter('pandas_conditional.xlsx', engine='xlsxwriter')
# Convert the dataframe to an XlsxWriter Excel object.
df_final.to_excel(writer, sheet_name='Sheet1')
# Get the xlsxwriter workbook and worksheet objects.
workbook = writer.book
worksheet = writer.sheets['Sheet1']
# Add a format. Light red fill with dark red text.
red_format = workbook.add_format({'bg_color': '#FFC7CE',
'font_color': '#9C0006'})
# Add a format. Green fill with dark green text.
green_format = workbook.add_format({'bg_color': '#C6EFCE',
'font_color': '#006100'})
# Calculate the range to which the conditional format is applied.
(max_row, max_col) = df_final.shape
min_row = 1 # Skip header.
min_col = 1 # Skip index.
max_row = min_row + max_row -1
max_col = min_col + max_col -1
# Apply a conditional format to the cell range.
worksheet.conditional_format(min_row, min_col, max_row, max_col,
{'type': 'cell',
'criteria': '<',
'value': 0,
'format': red_format})
worksheet.conditional_format(min_row, min_col, max_row, max_col,
{'type': 'cell',
'criteria': '>=',
'value': 0,
'format': green_format})
# Close the Pandas Excel writer and output the Excel file.
writer.save()
Output2:
