Repository: pandas-dev/pandas

Issue:
engine xlsxwriter fails for np.inf
this works for openpyxl but it fails for xlsxwriter

TypeError("NAN/INF not supported in write_number()")



Discussion:
do `nans` raise the same? or just `inf`?

cc @jmcnamara

nans are fine

On Thu, Apr 3, 2014 at 7:19 PM, jreback notifications@github.com wrote:

> cc @jmcnamara https://github.com/jmcnamara
> 
> ## 
> 
> Reply to this email directly or view it on GitHubhttps://github.com/pydata/pandas/issues/6782#issuecomment-39478741
> .

## 

_Arthur Gerigk_
Global CMO

Rocket Internet GmbH  |  Johannisstraße 20  |  10117 Berlin  |  Deutschland
Mobile: +49 162 290 46 39 | skype: arthur.gerigk | mail:
arthur.gerigk@rocket-internet.de
www.rocket-internet.de

Geschäftsführer: Dr. Johannes Bruder, Arnt Jeschke, Alexander Kudlich
Eingetragen beim Amtsgericht Berlin, HRB 109262 USt-ID DE256469659

I don't think NAN/INF are supported by Excel so I am curious to see what OpenPyXL is doing in this case. 

Can you post a small example that demonstrates the issue and I'll look into it.

to_excel has a parameter "na_rep" which defaults to the empty string.
actually there are NA values in excel
http://office.microsoft.com/en-001/excel-help/na-HP005209188.aspx

On Thu, Apr 3, 2014 at 7:39 PM, John McNamara notifications@github.comwrote:

> I don't think NAN/INF are supported by Excel so I am curious to see what
> OpenPyXL is doing in this case.
> 
> Can you post a small example that demonstrates the issue and I'll look
> into it.
> 
> ## 
> 
> Reply to this email directly or view it on GitHubhttps://github.com/pydata/pandas/issues/6782#issuecomment-39481271
> .

## 

_Arthur Gerigk_
Global CMO

Rocket Internet GmbH  |  Johannisstraße 20  |  10117 Berlin  |  Deutschland
Mobile: +49 162 290 46 39 | skype: arthur.gerigk | mail:
arthur.gerigk@rocket-internet.de
www.rocket-internet.de

Geschäftsführer: Dr. Johannes Bruder, Arnt Jeschke, Alexander Kudlich
Eingetragen beim Amtsgericht Berlin, HRB 109262 USt-ID DE256469659

NA is only supported in Excel as a formula or as the result of a formula. Not as a value. 

If you post an example I'll have a look at it. 

import numpy as np
import pandas as pd
df = pd.DataFrame([(1, np.nan), (2, 3)])
df.to_excel('test.xlsx')  # works

df = pd.DataFrame([(1, np.inf), (2, 3)])
df.to_excel('test2.xlsx')  # fails

since there is a parameter np_rep I think it has to work ;-)

On Thu, Apr 3, 2014 at 8:14 PM, John McNamara notifications@github.comwrote:

> NA is only supported in Excel as a formula or as the result of a formula.
> Not as a value.
> 
> If you post an example I'll have a look at it.
> 
> ## 
> 
> Reply to this email directly or view it on GitHubhttps://github.com/pydata/pandas/issues/6782#issuecomment-39485412
> .

## 

_Arthur Gerigk_
Global CMO

Rocket Internet GmbH  |  Johannisstraße 20  |  10117 Berlin  |  Deutschland
Mobile: +49 162 290 46 39 | skype: arthur.gerigk | mail:
arthur.gerigk@rocket-internet.de
www.rocket-internet.de

Geschäftsführer: Dr. Johannes Bruder, Arnt Jeschke, Alexander Kudlich
Eingetragen beim Amtsgericht Berlin, HRB 109262 USt-ID DE256469659

Let's follow the model of `to_csv`/`read_csv` and output `np.inf` as the string `'inf'`, which will be able to be round-tripped appropriately.

Side note - I can't open up the openpyxl file after it's written - so I'm not sure if openpyxl is doing the right thing.


Resolving patch:
diff --git a/pandas/core/format.py b/pandas/core/format.py
--- a/pandas/core/format.py
+++ b/pandas/core/format.py
@@ -1369,10 +1369,14 @@ class ExcelFormatter(object):
             sequence should be given if the DataFrame uses MultiIndex.
     merge_cells : boolean, default False
             Format MultiIndex and Hierarchical Rows as merged cells.
+    inf_rep : string, default `'inf'`
+        representation for np.inf values (which aren't representable in Excel)
+        A `'-'` sign will be added in front of -inf.
     """
 
     def __init__(self, df, na_rep='', float_format=None, cols=None,
-                 header=True, index=True, index_label=None, merge_cells=False):
+                 header=True, index=True, index_label=None, merge_cells=False,
+                 inf_rep='inf'):
         self.df = df
         self.rowcounter = 0
         self.na_rep = na_rep
@@ -1384,12 +1388,18 @@ def __init__(self, df, na_rep='', float_format=None, cols=None,
         self.index_label = index_label
         self.header = header
         self.merge_cells = merge_cells
+        self.inf_rep = inf_rep
 
     def _format_value(self, val):
         if lib.checknull(val):
             val = self.na_rep
-        if self.float_format is not None and com.is_float(val):
-            val = float(self.float_format % val)
+        elif com.is_float(val):
+            if np.isposinf(val):
+                val = '-%s' % self.inf_rep
+            elif np.isneginf(val):
+                val = self.inf_rep
+            elif self.float_format is not None:
+                val = float(self.float_format % val)
         return val
 
     def _format_header_mi(self):
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -1155,7 +1155,7 @@ def to_csv(self, path_or_buf=None, sep=",", na_rep='', float_format=None,
     def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',
                  float_format=None, columns=None, header=True, index=True,
                  index_label=None, startrow=0, startcol=0, engine=None,
-                 merge_cells=True, encoding=None):
+                 merge_cells=True, encoding=None, inf_rep='inf'):
         """
         Write DataFrame to a excel sheet
 
@@ -1194,6 +1194,9 @@ def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',
             encoding of the resulting excel file. Only necessary for xlwt,
             other writers support unicode natively.
         cols : kwarg only alias of columns [deprecated]
+        inf_rep : string, default 'inf'
+            Representation for infinity (there is no native representation for
+            infinity in Excel)
 
         Notes
         -----
@@ -1207,7 +1210,7 @@ def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',
         >>> writer.save()
         """
         from pandas.io.excel import ExcelWriter
-        
+
         need_save = False
         if encoding == None:
             encoding = 'ascii'
@@ -1223,7 +1226,8 @@ def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',
                                        float_format=float_format,
                                        index=index,
                                        index_label=index_label,
-                                       merge_cells=merge_cells)
+                                       merge_cells=merge_cells,
+                                       inf_rep=inf_rep)
         formatted_cells = formatter.get_formatted_cells()
         excel_writer.write_cells(formatted_cells, sheet_name,
                                  startrow=startrow, startcol=startcol)


Test patch:
diff --git a/pandas/io/tests/test_excel.py b/pandas/io/tests/test_excel.py
--- a/pandas/io/tests/test_excel.py
+++ b/pandas/io/tests/test_excel.py
@@ -538,6 +538,16 @@ def test_bool_types(self):
                 recons = reader.parse('test1').astype(np_type)
                 tm.assert_frame_equal(frame, recons)
 
+    def test_inf_roundtrip(self):
+        _skip_if_no_xlrd()
+
+        frame = DataFrame([(1, np.inf), (2, 3), (5, -np.inf)])
+        with ensure_clean(self.ext) as path:
+            frame.to_excel(path, 'test1')
+            reader = ExcelFile(path)
+            recons = reader.parse('test1')
+            tm.assert_frame_equal(frame, recons)
+
     def test_sheets(self):
         _skip_if_no_xlrd()