react-pivottable icon indicating copy to clipboard operation
react-pivottable copied to clipboard

Export options

Open podwards opened this issue 8 years ago • 23 comments

Hi, I'd like to be able to export the pivot table to CSV or Excel once the user is happy with the arrangement of a table. Do you have any tips for how to do this? I can't see anything built in to do this.

podwards avatar Nov 14 '17 06:11 podwards

This isn't possible at the moment but later this week I can port over the "TSV Export" renderer from the sister project at https://pivottable.js.org/ :)

nicolaskruchten avatar Nov 14 '17 14:11 nicolaskruchten

That'd be great!

podwards avatar Nov 14 '17 20:11 podwards

I just pushed some new renderers, including an "Exportable TSV" one which should do the trick!

nicolaskruchten avatar Nov 17 '17 21:11 nicolaskruchten

Great! Thanks a lot, I'll check it out.

podwards avatar Nov 22 '17 00:11 podwards

@podwards In line with my strategy for saving data in #10, you can modify your renderer to accept a function to pass pivotted data back to your main component, which you could then export however you see fit. I need to do this as well, and can share my specific code once I get there.

drheinheim avatar Jan 09 '18 05:01 drheinheim

@rheinheimer please share when you get there!

turnerniles avatar Jan 11 '18 05:01 turnerniles

Since PivotTableUI passes props on to the renderers, I've added this as an additional prop: onUpdateContent={this.onUpdateContent}. I then modified my PlotlyRenderer.js as below. However, the way I did it is just so I can plot right away. You could very well call props.onUpdateContent just before rendering, but after the PivotData is created.

<PlotlyComponent
    ....
    onAfterPlot={this.props.onUpdateContent({provider: PLOTLY_PROVIDER, data: [data], layout})}
/>

My onUpdateContent function is very simple:

onUpdateContent(content) {
    this.content = content;
}

This approach works, allowing you to then save content, but is, in fact, fundamentally limited. The main issue with this is that you cannot update your component state from within the renderer, which is called within a React render. This prevents any GUI component other than what's in the PivotTableUI from knowing what's in the PivotTable. I'm trying to figure out a hacky workaround for this.

drheinheim avatar Jan 13 '18 02:01 drheinheim

I'm happy to add to the API to make this less "hacky workaround" and more "supported good path" so please let me know what an ideal situation would look like for you and I'll see how close we can get!

nicolaskruchten avatar Jan 15 '18 03:01 nicolaskruchten

@nicolaskruchten I haven't yet gotten to this, but what I'm thinking is: don't use PivotData in the renderer, but instead have a final rendering component that just reads from props directly (okay, maybe a little necessary manipulation). Then, use the existing onChange to kick off a function to create the PivotData, using the new UI state, with a setState({data: myPivottedData}) at the end. This data would then be passed directly to the renderer. In this way, the pivotted data becomes accessible to other components, and the renderers become just passive consumers of data.

I don't know how this would fit into the API, but I think it should work. The existing renderer(s) would just need to be pulled apart a bit to achieve this.

drheinheim avatar Jan 15 '18 21:01 drheinheim

@nicolaskruchten Thanks for the amazing react app.

Is it possible to save all the selected axis values and other settings (using drag and drop), So next time we can load same formatted graph.

rit20j avatar May 14 '18 16:05 rit20j

@rit20j I'm glad you like it! In future please create a new issue instead of adding an unrelated comment to an existing one :)

To answer your question, you can just save all the props that you're passing to the component and that will save the state.

nicolaskruchten avatar May 18 '18 14:05 nicolaskruchten

@nicolaskruchten Congrats for the great component.

I had a necessity to export the pivot table after the user configures it. I found the solution bellow, and maybe it will help others:

` import { PivotData } from 'react-pivottable/Utilities'; const profile = { rows: [], cols: [], vals: [], aggregator: 'Count' }; export = () => { var pivotData = new PivotData(this.state.profile);

var rowKeys = pivotData.getRowKeys();
var colKeys = pivotData.getColKeys();
if (rowKeys.length === 0) {
  rowKeys.push([]);
}
if (colKeys.length === 0) {
  colKeys.push([]);
}

var headerRow = pivotData.props.rows.map(function (r) {
  return r;
});
if (colKeys.length === 1 && colKeys[0].length === 0) {
  headerRow.push(this.state.profile.aggregatorName);
} else {
  colKeys.map(function (c) {
    return headerRow.push(c.join('-'));
  });
}

var result = rowKeys.map(function (r) {
  var row = r.map(function (x) {
    return x;
  });
  colKeys.map(function (c) {
    var v = pivotData.getAggregator(r, c).value();
    row.push(v ? v : '');
  });
  return row;
});

result.unshift(headerRow);

return result.map(function (r) {
  return r.join(',');
}).join('\n');

}`

I simply copied the original code from "TSVExportRenderer" and used it to get the final result. With that I inserted a button that my users just press and I give him an excel (CSV) file. Using that function is possible to get the json, CSV, TSV just from the pivot result showed at the screen.

fernandocvlopes avatar Jul 05 '18 13:07 fernandocvlopes

@nicolaskruchten I just deleted a previous comment here regarding updating parent state to get pivotted data for export. I've now seen the latest revisions to react-plotly, and it seems the combination of onInitialized and onUpdate work great for this. Thanks for your great work!

drheinheim avatar Oct 03 '18 17:10 drheinheim

Hey I haven't been able to figure out how to export to a CSV and what @fernandocvlopes hasn't been able to work for me. Has anyone else been having the same problem?

JonasWangLilly avatar Mar 21 '19 16:03 JonasWangLilly

@fernandocvlopes - We are trying to achieve this functionality and wanted to know if you were able to successfully do it the way you describe above, is there a repo where we can follow and reproduce this. Thanks in advance!

ghost avatar Dec 04 '19 15:12 ghost

Hi, I'd like to export the pivot table to CSV or Excel once the user is happy with the arrangement of a table. Do you have any tips for how to do this? I can't see anything built in to do this.

rahulaggarwalg avatar Aug 29 '20 04:08 rahulaggarwalg

@nicolaskruchten Thank you for an amazing Pivot table app! I have been able to implement it for a lot of different functionalities. Just so that I can give back to better this app, here is my code for exporting the selected data by using @fernandocvlopes suggestion

`import React from 'react'; import PivotTableUI from 'react-pivottable/PivotTableUI'; import 'react-pivottable/pivottable.css'; import TableRenderers from 'react-pivottable/TableRenderers'; import Plotly from "plotly.js" import createPlotlyComponent from 'react-plotly.js/factory'; import createPlotlyRenderers from 'react-pivottable/PlotlyRenderers'; import { PivotData } from 'react-pivottable/Utilities';

const Plot = createPlotlyComponent(Plotly); const PlotlyRenderers = createPlotlyRenderers(Plot);

// see documentation for supported input formats class ExamplePivot extends React.Component { constructor(props) { super(props); this.state = {pivotTableUIConfig: {}}; }

render() {

    const dataTemp = [['a', 'b'], [1, 2],[3,4]];
    const { data, ...pivotTableUIConfig } = this.state.pivotTableUIConfig;
    const profile = {
        rows: [],
        cols: [],
        vals: [],
        aggregator: 'Count'
        };

        const exportdata = () => {
            if(this.state.pivotTableUIConfig.hasOwnProperty("renderers")){
              var pivotData = new PivotData(this.state.pivotTableUIConfig);
              
              var rowKeys = pivotData.getRowKeys();
              var colKeys = pivotData.getColKeys();
              if (rowKeys.length === 0) {
                rowKeys.push([]);
              }
              if (colKeys.length === 0) {
                colKeys.push([]);
              }
  
              
  
              var headerRow = pivotData.props.rows.map(function (r) {
                return r;
              });
              if (colKeys.length === 1 && colKeys[0].length === 0) {
                headerRow.push(this.state.pivotTableUIConfig.aggregatorName);
              } else {
                colKeys.map(function (c) {
                  return headerRow.push(c.join('-'));
                });
              }
  
              
  
              var result = rowKeys.map(function (r) {
                var row = r.map(function (x) {
                  return x;
                });
                colKeys.map(function (c) {
                  var v = pivotData.getAggregator(r, c).value();
                  row.push(v ? v : '');
                });
                return row;
              });
  
              
  
              result.unshift(headerRow);
              
              var FinalResult= (result.map(function (r) {
                return r.join(',');
              }).join('\n'));
  
              const element = document.createElement("a");
              const file = new Blob([FinalResult], {type: 'text/plain'});
              element.href = URL.createObjectURL(file);
              element.download = "myFile.csv";
              document.body.appendChild(element); // Required for this to work in FireFox
              element.click()
  
              
            }
            else{
              alert("No Selections Made")
            }
          }
    

    return (
      <div>
      <button onClick={exportdata}>Download</button>
      <PivotTableUI
            data={dataTemp}
            aggregatorName="Sum"
            vals={["a"]}
            onChange={s => this.setState({ pivotTableUIConfig: s })}
            renderers={Object.assign({}, TableRenderers, PlotlyRenderers)}
            {...pivotTableUIConfig}
        />
      </div>
    );
}

}

export default ExamplePivot;`

sandheepsebastain avatar Sep 20 '20 18:09 sandheepsebastain

Is it possible to save all the selected axis values and other settings (using drag and drop), So next time we can load same formatted graph/table.

rahulaggarwalg avatar Sep 21 '20 07:09 rahulaggarwalg

Is it possible to save all the selected axis values and other settings (using drag and drop), So next time we can load same formatted graph/table.

@rahulaggarwalg The pivotTableUIConfig state contains all your saved configurations, which you can save to a json file or to a cookie. Another option is to refer the documentation for the js version of PivotTable that is saving the configuration to a cookie and modifying that for your react purposes https://pivottable.js.org/examples/save_restore.html

sandheepsebastain avatar Sep 21 '20 13:09 sandheepsebastain

@nicolaskruchten Thank you for an amazing Pivot table app! I have been able to implement it for a lot of different functionalities. Just so that I can give back to better this app, here is my code for exporting the selected data by using @fernandocvlopes suggestion

`import React from 'react'; import PivotTableUI from 'react-pivottable/PivotTableUI'; import 'react-pivottable/pivottable.css'; import TableRenderers from 'react-pivottable/TableRenderers'; import Plotly from "plotly.js" import createPlotlyComponent from 'react-plotly.js/factory'; import createPlotlyRenderers from 'react-pivottable/PlotlyRenderers'; import { PivotData } from 'react-pivottable/Utilities';

const Plot = createPlotlyComponent(Plotly); const PlotlyRenderers = createPlotlyRenderers(Plot);

// see documentation for supported input formats class ExamplePivot extends React.Component { constructor(props) { super(props); this.state = {pivotTableUIConfig: {}}; }

render() {

    const dataTemp = [['a', 'b'], [1, 2],[3,4]];
    const { data, ...pivotTableUIConfig } = this.state.pivotTableUIConfig;
    const profile = {
        rows: [],
        cols: [],
        vals: [],
        aggregator: 'Count'
        };

        const exportdata = () => {
            if(this.state.pivotTableUIConfig.hasOwnProperty("renderers")){
              var pivotData = new PivotData(this.state.pivotTableUIConfig);
              
              var rowKeys = pivotData.getRowKeys();
              var colKeys = pivotData.getColKeys();
              if (rowKeys.length === 0) {
                rowKeys.push([]);
              }
              if (colKeys.length === 0) {
                colKeys.push([]);
              }
  
              
  
              var headerRow = pivotData.props.rows.map(function (r) {
                return r;
              });
              if (colKeys.length === 1 && colKeys[0].length === 0) {
                headerRow.push(this.state.pivotTableUIConfig.aggregatorName);
              } else {
                colKeys.map(function (c) {
                  return headerRow.push(c.join('-'));
                });
              }
  
              
  
              var result = rowKeys.map(function (r) {
                var row = r.map(function (x) {
                  return x;
                });
                colKeys.map(function (c) {
                  var v = pivotData.getAggregator(r, c).value();
                  row.push(v ? v : '');
                });
                return row;
              });
  
              
  
              result.unshift(headerRow);
              
              var FinalResult= (result.map(function (r) {
                return r.join(',');
              }).join('\n'));
  
              const element = document.createElement("a");
              const file = new Blob([FinalResult], {type: 'text/plain'});
              element.href = URL.createObjectURL(file);
              element.download = "myFile.csv";
              document.body.appendChild(element); // Required for this to work in FireFox
              element.click()
  
              
            }
            else{
              alert("No Selections Made")
            }
          }
    

    return (
      <div>
      <button onClick={exportdata}>Download</button>
      <PivotTableUI
            data={dataTemp}
            aggregatorName="Sum"
            vals={["a"]}
            onChange={s => this.setState({ pivotTableUIConfig: s })}
            renderers={Object.assign({}, TableRenderers, PlotlyRenderers)}
            {...pivotTableUIConfig}
        />
      </div>
    );
}

}

export default ExamplePivot;`

hi @sandheepsebastain , this works great but when we set cols, the ''Totals' column and row is missing image image

you can see in react pivot there is Totals column at the right side but there is nothing on csv

irfanandratama avatar Oct 12 '20 05:10 irfanandratama

I followed the above code @nicolaskruchten i am getting this error in console

Module not found: Error: Can't resolve 'fs' in /node_modules/image-size/lib'

can you anyone suggest me a better solution?

Barath-appmocx avatar Jan 15 '21 06:01 Barath-appmocx

@irfanandratama how u get the first initial data withOut onchange setState?? please help

Buddikazz avatar Sep 14 '21 04:09 Buddikazz