Skip to content

Commit c75282c

Browse files
committed
Implement (beta) export to excel file support
1 parent da2da78 commit c75282c

15 files changed

+492
-18
lines changed

README.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,34 @@
2222
- [Requirements](#-requirements)
2323
- [Quick Start](#-quick-start)
2424
- [Usage](#-usage)
25-
- [Building](#-building)
2625
- [License](#-license)
2726

2827
---
2928

29+
<div align="center">
30+
31+
## 🎉 What's New
32+
33+
### 📊 Excel Export Support
34+
35+
Export your data and regression analysis directly to **Excel (.xlsx)** files!
36+
37+
### **Features:**
38+
39+
📈 **Visual Charts** - Automatically generated scatter plots with regression lines
40+
41+
📋 **Data Sheets** - Complete data tables with all your X and Y values
42+
43+
📊 **Regression Parameters** - Detailed regression statistics (intercept, slope, R²)
44+
45+
🎨 **Professional Formatting** - Ready-to-present Excel files with styled charts
46+
47+
`The exported Excel files include both raw data and beautiful visualizations, making it perfect for reports and presentations!`
48+
49+
</div>
50+
51+
---
52+
3053
## ✨ Features
3154

3255
- 📈 **Dynamic Chart** - Real-time linear regression visualization
@@ -38,6 +61,7 @@
3861
- 📊 **Auto Calculation** - Automatic regression line calculation (minimum 2 points)
3962
- 🟢 **Colors Selection** - Customizable colors for data points and regression line
4063
- 💫 **Symbol Selection** - Choose your favourite symbol for data points
64+
- 📐 **Excel Export** - Export data and charts to Excel (.xlsx) files
4165

4266
---
4367

@@ -90,8 +114,9 @@
90114

91115
- **Delete Values**: Select cells and press `Delete` or `Backspace`
92116
- **Move Values**: Select cells, drag to another location, and drop
93-
- **Save Data**: Click "Zapisz do pliku" to save data as JSON
117+
- **Save Data**: Click "Zapisz do pliku" to save data as JSON (includes chart settings)
94118
- **Load Data**: Click "Załaduj z pliku" to load data from JSON file
119+
- **Export to Excel**: Click "Eksportuj do Excela" to export data and charts to Excel (.xlsx)
95120

96121
### Chart Features
97122

@@ -112,6 +137,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
112137
- Built with [JFreeChart](https://www.jfree.org/jfreechart/) for chart visualization
113138
- GUI powered by [FlatLaf](https://www.formdev.com/flatlaf/)
114139
- JSON handling with [Gson](https://github.com/google/gson)
140+
- Excel export powered by [Apache POI](https://poi.apache.org/)
115141

116142
---
117143

assets/screen.png

30.4 KB
Loading

build.gradle.kts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ tasks.withType<ShadowJar> {
2020
"org/intellij/lang/annotations/**",
2121
"org/jetbrains/annotations/**",
2222
"org/checkerframework/**",
23-
"META-INF/**",
23+
"META-INF/DEPENDENCIES",
24+
"META-INF/LICENSE",
25+
"META-INF/LICENSE.txt",
26+
"META-INF/NOTICE",
27+
"META-INF/NOTICE.txt",
2428
"javax/**"
2529
)
2630
manifest {
@@ -49,6 +53,8 @@ dependencies {
4953
implementation("org.jfree:jfreechart:1.5.6")
5054
implementation("com.formdev:flatlaf:3.6.2")
5155
implementation("com.google.code.gson:gson:2.13.2")
56+
implementation("org.apache.poi:poi:5.4.0")
57+
implementation("org.apache.poi:poi-ooxml:5.4.0")
5258
}
5359

5460
tasks.build {

src/main/java/ovh/neziw/visualizer/LinearRegressionCalculator.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ public RegressionResult(final double slope, final double intercept) {
6161
this.intercept = intercept;
6262
}
6363

64+
public double getSlope() {
65+
return this.slope;
66+
}
67+
68+
public double getIntercept() {
69+
return this.intercept;
70+
}
71+
6472
public double predict(final double x) {
6573
return this.slope * x + this.intercept;
6674
}

src/main/java/ovh/neziw/visualizer/RegressionChart.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ private void updateRendererSettings() {
9090
this.renderer.setSeriesLinesVisible(1, true);
9191
this.renderer.setSeriesShapesVisible(1, false);
9292
this.renderer.setSeriesPaint(1, this.settings.getRegressionLineColor());
93-
93+
9494
final BasicStroke stroke;
9595
if (this.settings.isDashedLine()) {
96-
stroke = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
97-
10.0f, new float[]{5.0f, 5.0f}, 0.0f);
96+
stroke = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
97+
10.0f, new float[] {5.0f, 5.0f}, 0.0f);
9898
} else {
9999
stroke = new BasicStroke(2.0f);
100100
}

src/main/java/ovh/neziw/visualizer/RegressionVisualizer.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import ovh.neziw.visualizer.gui.FileDialogManager;
4242
import ovh.neziw.visualizer.gui.TableConfiguration;
4343
import ovh.neziw.visualizer.gui.UIManagerConfigurator;
44+
import ovh.neziw.visualizer.io.ExcelExportManager;
4445
import ovh.neziw.visualizer.io.TableFileManager;
4546

4647
public class RegressionVisualizer extends JFrame {
@@ -50,6 +51,7 @@ public class RegressionVisualizer extends JFrame {
5051
private final RegressionChart chart;
5152
private final ChartUpdater chartUpdater;
5253
private final TableFileManager fileManager;
54+
private final ExcelExportManager excelExportManager;
5355
private final ChartSettings chartSettings;
5456
private final ChartSettingsPanel settingsPanel;
5557

@@ -62,7 +64,9 @@ public RegressionVisualizer() {
6264
this.chartUpdater = new ChartUpdater(this.tableModel, this.chart);
6365
this.setupTableListeners();
6466
this.settingsPanel = this.createSettingsPanel();
65-
this.fileManager = this.createFileManager();
67+
final FileDialogManager dialogManager = new FileDialogManager(this);
68+
this.fileManager = this.createFileManager(dialogManager);
69+
this.excelExportManager = this.createExcelExportManager(dialogManager);
6670
this.setupUI();
6771
}
6872

@@ -89,11 +93,14 @@ private JTable createTable() {
8993
return table;
9094
}
9195

92-
private TableFileManager createFileManager() {
93-
final FileDialogManager dialogManager = new FileDialogManager(this);
96+
private TableFileManager createFileManager(final FileDialogManager dialogManager) {
9497
return new TableFileManager(this.tableModel, dialogManager, this::onDataLoaded, this.chartSettings);
9598
}
9699

100+
private ExcelExportManager createExcelExportManager(final FileDialogManager dialogManager) {
101+
return new ExcelExportManager(this.tableModel, dialogManager);
102+
}
103+
97104
private void onDataLoaded() {
98105
if (this.settingsPanel != null) {
99106
this.settingsPanel.refreshUI();
@@ -154,7 +161,8 @@ private JSplitPane createSplitPane(final JScrollPane tableScrollPane) {
154161
private ButtonPanel createButtonPanel() {
155162
return new ButtonPanel(
156163
() -> this.fileManager.saveToFile(this),
157-
() -> this.fileManager.loadFromFile(this)
164+
() -> this.fileManager.loadFromFile(this),
165+
() -> this.excelExportManager.exportToExcel(this)
158166
);
159167
}
160168

src/main/java/ovh/neziw/visualizer/gui/ButtonPanel.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,37 @@
2424
package ovh.neziw.visualizer.gui;
2525

2626
import java.awt.FlowLayout;
27+
import javax.swing.ImageIcon;
2728
import javax.swing.JButton;
2829
import javax.swing.JPanel;
2930

3031
public class ButtonPanel extends JPanel {
3132

32-
public ButtonPanel(final Runnable onSave, final Runnable onLoad) {
33+
public ButtonPanel(final Runnable onSave, final Runnable onLoad, final Runnable onExport) {
3334
this.setLayout(new FlowLayout(FlowLayout.LEFT));
3435
final JButton saveButton = new JButton("Zapisz do pliku");
3536
saveButton.addActionListener(e -> onSave.run());
3637
final JButton loadButton = new JButton("Załaduj z pliku");
3738
loadButton.addActionListener(e -> onLoad.run());
39+
final JButton exportButton = new JButton("Eksportuj do Excela");
40+
final ImageIcon excelIcon = this.loadExcelIcon();
41+
if (excelIcon != null) {
42+
exportButton.setIcon(excelIcon);
43+
}
44+
exportButton.addActionListener(e -> onExport.run());
3845
this.add(saveButton);
3946
this.add(loadButton);
47+
this.add(exportButton);
48+
}
49+
50+
private ImageIcon loadExcelIcon() {
51+
try {
52+
final java.net.URL iconUrl = ButtonPanel.class.getResource("/excel.png");
53+
if (iconUrl != null) {
54+
return new ImageIcon(iconUrl);
55+
}
56+
} catch (final Exception exception) {
57+
}
58+
return null;
4059
}
4160
}

src/main/java/ovh/neziw/visualizer/gui/ChartSettingsPanel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ private void setupPanel() {
122122
final JButton shapeButton = this.createShapeButton();
123123
this.add(shapeButton);
124124

125-
this.dashedLineCheckBox = new JCheckBox("Linia przerywana",
125+
this.dashedLineCheckBox = new JCheckBox("Linia przerywana",
126126
this.settings.isDashedLine());
127127
this.dashedLineCheckBox.addActionListener(e -> {
128128
this.settings.setDashedLine(this.dashedLineCheckBox.isSelected());

src/main/java/ovh/neziw/visualizer/gui/FileDialogManager.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public class FileDialogManager {
3333
private static final String JSON_EXTENSION = "json";
3434
private static final String JSON_DESCRIPTION = "Pliki JSON (*.json)";
3535
private static final String DEFAULT_FILENAME = "dane.json";
36+
private static final String EXCEL_EXTENSION = "xlsx";
37+
private static final String EXCEL_DESCRIPTION = "Pliki Excel (*.xlsx)";
38+
private static final String DEFAULT_EXCEL_FILENAME = "dane.xlsx";
3639

3740
private final JFrame parentFrame;
3841

@@ -68,10 +71,30 @@ private JFileChooser createFileChooser() {
6871
return fileChooser;
6972
}
7073

74+
public File showExcelSaveDialog() {
75+
final JFileChooser fileChooser = new JFileChooser();
76+
fileChooser.setFileFilter(new FileNameExtensionFilter(EXCEL_DESCRIPTION, EXCEL_EXTENSION));
77+
fileChooser.setDialogTitle("Eksportuj do Excela");
78+
fileChooser.setSelectedFile(new File(DEFAULT_EXCEL_FILENAME));
79+
final int result = fileChooser.showSaveDialog(this.parentFrame);
80+
if (result == JFileChooser.APPROVE_OPTION) {
81+
final File file = fileChooser.getSelectedFile();
82+
return this.ensureExcelExtension(file);
83+
}
84+
return null;
85+
}
86+
7187
private File ensureJsonExtension(final File file) {
7288
if (!file.getName().toLowerCase().endsWith("." + JSON_EXTENSION)) {
7389
return new File(file.getParent(), file.getName() + "." + JSON_EXTENSION);
7490
}
7591
return file;
7692
}
93+
94+
private File ensureExcelExtension(final File file) {
95+
if (!file.getName().toLowerCase().endsWith("." + EXCEL_EXTENSION)) {
96+
return new File(file.getParent(), file.getName() + "." + EXCEL_EXTENSION);
97+
}
98+
return file;
99+
}
77100
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* This file is part of "linear-regression-visualizer", licensed under MIT License.
3+
*
4+
* Copyright (c) 2025 neziw
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package ovh.neziw.visualizer.io;
25+
26+
import java.io.File;
27+
import java.io.FileOutputStream;
28+
import java.io.IOException;
29+
import java.util.List;
30+
import javax.swing.JFrame;
31+
import javax.swing.JOptionPane;
32+
import ovh.neziw.visualizer.DataTableModel;
33+
import ovh.neziw.visualizer.gui.FileDialogManager;
34+
35+
public class ExcelExportManager {
36+
37+
private final DataTableModel tableModel;
38+
private final ExcelExporter exporter;
39+
private final FileDialogManager dialogManager;
40+
41+
public ExcelExportManager(final DataTableModel tableModel, final FileDialogManager dialogManager) {
42+
this.tableModel = tableModel;
43+
this.exporter = new ExcelExporter();
44+
this.dialogManager = dialogManager;
45+
}
46+
47+
public void exportToExcel(final JFrame parentFrame) {
48+
final File file = this.dialogManager.showExcelSaveDialog();
49+
if (file == null) {
50+
return;
51+
}
52+
try (final FileOutputStream outputStream = new FileOutputStream(file)) {
53+
final List<DataTableModel.DataPoint> dataPoints = this.tableModel.getAllDataPoints();
54+
this.exporter.exportToExcel(outputStream, dataPoints);
55+
this.showSuccessMessage(parentFrame,
56+
"Dane zostały wyeksportowane do pliku: " + file.getName());
57+
} catch (final IOException exception) {
58+
this.showErrorMessage(parentFrame,
59+
"Błąd podczas eksportowania do pliku Excel:\n" + exception.getMessage());
60+
}
61+
}
62+
63+
private void showSuccessMessage(final JFrame parentFrame, final String message) {
64+
JOptionPane.showMessageDialog(parentFrame, message, "Sukces",
65+
JOptionPane.INFORMATION_MESSAGE);
66+
}
67+
68+
private void showErrorMessage(final JFrame parentFrame, final String message) {
69+
JOptionPane.showMessageDialog(parentFrame, message, "Błąd",
70+
JOptionPane.ERROR_MESSAGE);
71+
}
72+
}

0 commit comments

Comments
 (0)