Repository: vaexio/vaex

Issue:
[BUG-REPORT] bug of the export_csv in dataframe.py and possible fix
**Description**

I find a bug in the export_csv function which is implemented in dataframe.py.

`use_df.export_csv(outfn, header=False, quoting=None)`
```
{
Traceback (most recent call last):
  File "./produce_lc_from_hdf5.py", line 13, in <module>
    use_df.export_csv(outfn, header=False, quoting=None)
  File "/extra_disk/work_dir/Package/miniconda3/envs/astro/lib/python3.7/site-packages/vaex/dataframe.py", line 5855, in export_csv
    chunk_pdf.to_csv(path_or_buf=path, mode=mode, header=header, index=False, **kwargs)
TypeError: to_csv() got multiple values for keyword argument 'header'
}
```

**Software information**
 - Vaex version (`import vaex; vaex.__version__)`: 'vaex-core': '2.0.3', 'vaex-viz': '0.4.0', 'vaex-hdf5': '0.6.0', 'vaex-server': '0.3.1', 'vaex-astro': '0.7.0', 'vaex-jupyter': '0.5.2', 'vaex-ml': '0.9.0', 'vaex-arrow': '0.5.1'
 - Vaex was installed via: conda-forge
 - OS: Linux, Ubuntu 18.04.5 LTS

**Additional information**
In dataframe.py,
```
{
           if i1 == 0:  # Only the 1st chunk should have a header and the rest will be appended
                mode = 'w'
                header = True
            else:
                mode = 'a'
                header = False

            chunk_pdf.to_csv(path_or_buf=path, mode=mode, header=header, index=False, **kwargs)
}
```
causes a problem. The code needs changes that check where kwargs has header and index. If kwargs has header or index, header and index values should be the values provided in kwargs.


Discussion:
The following in dataframe.py is what I suggest to fix this issue. I confirm that this change fixes the issue.

```
{
        dtypes = self[expressions].dtypes
        n_samples = len(self)

        if "header" in kwargs:
            user_header = True
        else:
            user_header = False

        if "index" in kwargs:
            user_index = True
        else:
            user_index = False

        for i1, i2, chunks in self.evaluate_iterator(expressions, chunk_size=chunk_size, selection=selection):
            progressbar( i1 / n_samples)
            chunk_dict = {col: values for col, values in zip(expressions, chunks)}
            chunk_pdf = pd.DataFrame(chunk_dict)

            if i1 == 0:  # Only the 1st chunk should have a header and the rest will be appended
                mode = 'w'
                header = True
            else:
                mode = 'a'
                header = False

            if user_header and user_index:
                chunk_pdf.to_csv(path_or_buf=path, mode=mode, **kwargs)
            elif user_header:
                chunk_pdf.to_csv(path_or_buf=path, mode=mode, index=False, **kwargs)
            elif user_index:
                chunk_pdf.to_csv(path_or_buf=path, mode=mode, header=header, **kwargs)
            else:
                chunk_pdf.to_csv(path_or_buf=path, mode=mode, header=header, index=False, **kwargs)
}
```
Thanks @astromsshin 

@JovanVeljanoski what do you think? makes sense right?
Hi @maartenbreddels and @JovanVeljanoski ,
did you already have a chance to decide whether this will be integrated?
I am currently also facing this when trying to set index=False in the export_csv method.

Thanks!

Resolving patch:
diff --git a/packages/vaex-core/vaex/dataframe.py b/packages/vaex-core/vaex/dataframe.py
--- a/packages/vaex-core/vaex/dataframe.py
+++ b/packages/vaex-core/vaex/dataframe.py
@@ -6686,7 +6686,6 @@ def export_csv(self, path, progress=None, chunk_size=default_chunk_size, paralle
         :return:
         """
         import pandas as pd
-
         expressions = self.get_column_names()
         progressbar = vaex.utils.progressbars(progress)
         dtypes = self[expressions].dtypes
@@ -6694,19 +6693,22 @@ def export_csv(self, path, progress=None, chunk_size=default_chunk_size, paralle
         if chunk_size is None:
             chunk_size = len(self)
 
+        # By default vaex does not expect a csv file to have index like column so this is turned of by default
+        if 'index' not in kwargs:
+            kwargs['index'] = False
+
         for i1, i2, chunks in self.evaluate_iterator(expressions, chunk_size=chunk_size, parallel=parallel):
             progressbar( i1 / n_samples)
             chunk_dict = {col: values for col, values in zip(expressions, chunks)}
             chunk_pdf = pd.DataFrame(chunk_dict)
 
             if i1 == 0:  # Only the 1st chunk should have a header and the rest will be appended
-                mode = 'w'
-                header = True
+                kwargs['mode'] = 'w'
             else:
-                mode = 'a'
-                header = False
+                kwargs['mode'] = 'a'
+                kwargs['header'] = False
 
-            chunk_pdf.to_csv(path_or_buf=path, mode=mode, header=header, index=False, **kwargs)
+            chunk_pdf.to_csv(path_or_buf=path, **kwargs)
         progressbar(1.0)
         return
 


Test patch:
diff --git a/tests/export_test.py b/tests/export_test.py
--- a/tests/export_test.py
+++ b/tests/export_test.py
@@ -142,8 +142,8 @@ def test_export_string_mask(tmpdir):
 
 def test_export_unicode_column_name_hdf5(tmpdir):
     # prepare many columns for multithreaded export
-    src_dict = {"あ": [1, 2, 3], "a": [1, 2, 3], "b": [1, 2, 3], 
-            "c": [1, 2, 3], "d": [1, 2, 3], "a1": [1, 2, 3], 
+    src_dict = {"あ": [1, 2, 3], "a": [1, 2, 3], "b": [1, 2, 3],
+            "c": [1, 2, 3], "d": [1, 2, 3], "a1": [1, 2, 3],
             "b2": [1, 2, 3], "c3": [1, 2, 3], "d4": [1, 2, 3]}
     path = str(tmpdir.join('test.hdf5'))
     df = vaex.from_dict(src_dict)
@@ -202,6 +202,6 @@ def test_multi_file_naive_read_convert_export(tmpdir, dtypes):
 def test_export_csv(df_local, tmpdir):
     df = df_local
     path = str(tmpdir.join('test.csv'))
-    df.export_csv(path)
+    df.export_csv(path, index=False)
 
     assert '123456' in vaex.open(path)