How to make plotting with "jfreecharts" more dynamic? - java
Introduction
My goal is to input a set of products and choose an option for display such as:
System.out.print("Input number of products to represent: ");
prodNum = scan.nextInt();
String[] prodName = new String[prodNum];
System.out.print("Enter which products to represent: ");
for (int i = 0; i < prodName.length; i++)
{
prodName[i] = scan.next();
}
System.out.println("----Options----");
System.out.println("1. Cantidad");
System.out.println("2. Calidad");
System.out.println("3. RealmQ");
System.out.println("4. Coste");
option = scan.nextInt();
userOptionWas(option);
then by using JFreeCharts I wanted to be able to choose how many lines (for each product I input) and what option to display (quantity, quality and stuff) which is stored inside some obviously named arrays.
My approach
private XYDataset multipleLine(int prodNum, String[] prodName, int option){
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries product3 = new XYSeries("product3");
XYSeries product4 = new XYSeries("product4");
XYSeries product5 = new XYSeries("product5");
XYSeries product6 = new XYSeries("product6");
XYSeries product7 = new XYSeries("product7");
XYSeries product8 = new XYSeries("product8");
switch(prodNum)
{
case(2):
{
if (option == 1)
{
XYSeries product1 = new XYSeries(prodName[0]);
XYSeries product2 = new XYSeries(prodName[1]);
for (int i = 0; i < CSVinput.cantidad.length; i++)
{
try
{
if (CSVinput.nombre[i].equals(prodName[0]))
{
product1.add(i, CSVinput.cantidad[i]);
}
}catch(ArrayIndexOutOfBoundsException e){}
}
}
if (option == 2)
{
}
if (option == 3)
{
}
if (option == 4)
{
}
}
}
return dataset;
}
Halfway through implementing my idea I started to wonder if it is not possible to do it, or just I am in the wrong path to my goal.
What I expect
I want to be able to create different plots from a simple menu I showed before.
If it is possible, dynamic (if I input 2 products the program displays 2 lines referring to each product)
Extra Notes
I am new at JFreeCharts.
Take a moment here at product1.add(i, CSVinput.cantidad[i]); where I use (int)"i" instead of my (String)"date" format. Why I am not able to use a String? Is there any way to bypass this?
What I expect from this question
I would like to know more efficient and friendly ways to achieve this without too much unnecessary complexity.
Data Example
2018/12/29-Tejido,321 908,13.55,43.18,$15.98,
2018/12/29-Ropa,195 045,20.55,45.93,$123.01,
2018/12/29-Gorra de visera,126 561,17.43,42.32,$79.54,
2018/12/29-Cerveza,80 109,3.37,17.93,$12.38,
2018/12/29-Mercancías de playa,75 065,11.48,39.73,$105.93,
2018/12/29-Bebidas alcohólicas,31 215,4.84,27.90,$32.29,
2018/12/29-Artículos de cuero,19 098,23.13,44.09,$198.74,
2018/12/29-Bolsas y carteras,7 754,23.09,41.34,$1 176.54,
2018/12/30-Tejido,252 229,12.86,43.14,$18.87,
2018/12/30-Ropa,132 392,18.09,46.02,$177.58,
2018/12/30-Gorra de visera,87 676,14.42,42.46,$122.48,
2018/12/30-Cerveza,44 593,2.72,17.79,$18.71,
2018/12/30-Mercancías de playa,44 593,8.26,39.56,$200.78,
2018/12/30-Bebidas alcohólicas,27 306,4.30,23.88,$31.95,
2018/12/30-Artículos de cuero,16 147,21.08,43.91,$207.49,
2018/12/30-Bolsas y carteras,6 552,21.11,40.59,$1 195.41,
2019/01/02-Tejido,321 908,13.55,43.18,$15.98,
2019/01/02-Ropa,195 045,20.55,45.93,$123.01,
2019/01/02-Gorra de visera,126 561,17.43,42.32,$79.54,
2019/01/02-Cerveza,80 109,3.37,17.93,$12.38,
2019/01/02-Mercancías de playa,75 065,11.48,39.73,$105.93,
2019/01/02-Bebidas alcohólicas,31 215,4.84,27.90,$32.29,
2019/01/02-Artículos de cuero,19 098,23.13,44.09,$198.74,
2019/01/02-Bolsas y carteras,7 754,23.09,41.34,$1 176.54,
2019/01/03-Tejido,1 164 607,12.87,43.14,$15.54,
2019/01/03-Ropa,131 409,17.18,45.97,$161.17,
2019/01/03-Gorra de visera,79 242,13.54,43.17,$100.38,
2019/01/03-Cerveza,48 332,2.80,18.10,$17.48,
2019/01/03-Mercancías de playa,46 157,8.70,38.39,$180.54,
2019/01/03-Bebidas alcohólicas,25 210,4.04,23.72,$33.52,
2019/01/03-Artículos de cuero,14 321,19.56,39.92,$216.00,
2019/01/03-Bolsas y carteras,5 814,19.85,39.68,$1 227.29,
EDIT:
Thanks a lot for the help I think I have learnt but the way is never ending as by some reason, the instance which takes the dataset does not plot the dataset
What I am missing?.
PD: Let me know in the comments if you need CSVinput in order to provide a solution.
import java.awt.Color;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Scanner;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.general.SeriesException;
import org.jfree.data.time.Day;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import webscrapper.CSVinput;
/**
*
* #author Jonathan
*/
public class TimeSeriesChartExample extends ApplicationFrame{
//To parse dates below and be able to debug outside the loop
public static String[] dateSplit;
//Instace that declares properties and uses the dataset to create the chart
public TimeSeriesChartExample(String title)
{
super(title);
// Create dataset
XYDataset dataset = createDataset();
// Create chart
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Titulo", // Chart
"Date", // X-Axis Label
"Number", // Y-Axis Label
dataset);
//Changes background color
XYPlot plot = (XYPlot)chart.getPlot();
plot.setBackgroundPaint(new Color(255,228,196));
}
//Create the set of data to be plotted
private XYDataset createDataset()
{
//A collection of datasets
TimeSeriesCollection dataset = new TimeSeriesCollection();
//The object were this new series are added thus it's name
TimeSeries prod1 = new TimeSeries("Cantidad");
//"For each" name stored in the array
for (int i = 0; i < CSVinput.nombre.length; i++)
{
//If name equals
if ("Ropa".equals(CSVinput.nombre[i]))
{
//Pass the "i" position to work it
dateSplit = CSVinput.fecha[i].split("/");
//Parse the date
int day = Integer.parseInt(dateSplit[2]);
int month = Integer.parseInt(dateSplit[1]);
int year = Integer.parseInt(dateSplit[0]);
System.out.println("day is: " + day);
//Pass the parsed date and the value from CSV.cantidad at "i" position referring to the name "Ropa"
prod1.add(new Day(day, month, year), CSVinput.cantidad[i]);
System.out.println(CSVinput.cantidad[i]);//Debug stuff
}
}
//Add everything to the dataset
dataset.addSeries(prod1);
//Return it
return dataset;
}
private XYDataset createDataset2()
{
//A collection of datasets
TimeSeriesCollection dataset = new TimeSeriesCollection();
//The object were this new series are added thus it's name
TimeSeries prod2 = new TimeSeries("Cantidad");
//"For each" name stored in the array
for (int i = 0; i < CSVinput.nombre.length; i++)
{
//If name equals
if (CSVinput.nombre[i] == "Tejido")
{
//Pass the "i" position to work it
dateSplit = CSVinput.fecha[i].split("/");
//Parse the date
int day = Integer.parseInt(dateSplit[0]);
int month = Integer.parseInt(dateSplit[1]);
int year = Integer.parseInt(dateSplit[2]);
//Pass the parsed date and the value from CSV.cantidad at "i" position referring to the name "Ropa"
prod2.add(new Day(day, month, year), CSVinput.cantidad[i]);
System.out.println(CSVinput.cantidad[i]);//Debug stuff
}
}
//Add everything to the dataset
dataset.addSeries(prod2);
//Return it
return dataset;
}
public static void main(String[] args) throws FileNotFoundException
{
//Custom class to import data from the csv into arrays (TODO: make it dynamic)
CSVinput.ImportData("caca.csv");
/* //More debugg stuff
dateSplit = CSVinput.fecha[1].split("/");
System.out.println("year: " + dateSplit[0] + " month: " + dateSplit[1] + " day: " + dateSplit[2]);
*/
//Create an instance of the previous class
final TimeSeriesChartExample example = new TimeSeriesChartExample("ItWorks!");
example.pack(); //Part from the ApplicationFrame
RefineryUtilities.centerFrameOnScreen(example); //Render the graph at the center of screen
example.setVisible(true); //make it visible
}
}
First, focus on you program's data model:
If your series include a time domain, consider using a TimeSeriesCollection of TimeSeries rather than XYSeries; TimeSeriesChartDemo1, cited here, is a basic example; parse dates as shown here and here; for database access, consider a JDBCXYDataset.
As you read the data for each series, store the series in a List<TimeSeries>, rather than an array; if latency is a problem, do the parsing in the background, as shown here.
The exact details will depend on your application's design, but using the observer pattern will minimize complexity; the basic principle is to update the model (Dataset) and the listening view (JFreeChart) will update itself in response. Using Swing for example, you can control the displayed chart in several ways:
Use your List<TimeSeries> to construct a suitable ListModel<TimeSeries>; for the series menu, make your chosen model a DefaultComboBoxModel<TimeSeries> for a JComboBox or a DefaultListModel<TimeSeries> for a JList.
Add a suitable listener to your menu component; give your XYPlot a TimeSeriesCollection; use addSeries() or removeSeries() to alter the plot as a series is selected; alternatively, use setSeriesVisible() to toggle visibility, as shown here.
For a command-line interface, the interactions are less complex but also less versatile:
Use a List<TimeSeries> to build your TimeSeriesCollection.
Use the TimeSeriesCollection methods to control what the listening XYPlot displays.
Related
Sorting strings via stream
I am doing a coding exercise where I take the the raw data from a csv file and I print it in order of lowest to highest ranked literacy rates. For example: Adult literacy rate, population 15+ years, female (%),United Republic of Tanzania,2015,76.08978 Adult literacy rate, population 15+ years, female (%),Zimbabwe,2015,85.28513 Adult literacy rate, population 15+ years, male (%),Honduras,2014,87.39595 Adult literacy rate, population 15+ years, male (%),Honduras,2015,88.32135 Adult literacy rate, population 15+ years, male (%),Angola,2014,82.15105 Turns into: Niger (2015), female, 11.01572 Mali (2015), female, 22.19578 Guinea (2015), female, 22.87104 Afghanistan (2015), female, 23.87385 Central African Republic (2015), female, 24.35549 My code: import java.io.IOException; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class LiteracyComparison { public static void main(String[] args) throws IOException { List<String> literacy = new ArrayList<>(); try (Scanner scanner = new Scanner(Paths.get("literacy.csv"))) { while(scanner.hasNextLine()){ String row = scanner.nextLine(); String[] line = row.split(","); line[2] = line[2].trim().substring(0, line[2].length() - 5); line[3] = line[3].trim(); line[4] = line[4].trim(); line[5] = line[5].trim(); String l = line[3] + " (" + line[4] + "), " + line[2] + ", " + line[5]; literacy.add(l); } } // right about where I get lost literacy.stream().sorted(); } } Now I have converted the raw data into the correct format, it's just I am lost on how to sort it. I am also wondering if there is a more efficient way to do this via the streams method. Please and thank you.
I took a few liberties while refactoring your code, but the idea is the same. This could be further improved but it is not intended to be a perfect solution, just something to answer your question and put you on the right track. The main idea here is to create a nested class called LiteracyData, which stores the summary you had before as a String. However, we also want to store the literacy rate so we have something to sort by. Then you can use a Java Comparator to define your own method for comparing custom classes, in this case LiteracyData. Finally, tie it all together by calling the sort function on your List, while passing in the custom Comparator as an argument. That will sort your list. You can then print it to view the results. import java.io.IOException; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import java.util.Comparator; public class LiteracyComparison { // Define a class that stores your data public class LiteracyData { private String summary; private float rate; public LiteracyData(String summary, float rate) { super(); this.summary = summary; this.rate = rate; } } // This is a custom Comparator we defined for sorting LiteracyData public class LiteracySorter implements Comparator<LiteracyData> { #Override public int compare(LiteracyData d1, LiteracyData d2) { return Float.compare(d1.rate, d2.rate); } } public void run() { List<LiteracyData> literacy = new ArrayList<>(); try (Scanner scanner = new Scanner(Paths.get("literacy.csv"))) { while(scanner.hasNextLine()){ String row = scanner.nextLine(); String[] line = row.split(","); line[2] = line[2].trim().substring(0, line[2].length() - 5); line[3] = line[3].trim(); line[4] = line[4].trim(); line[5] = line[5].trim(); String l = line[3] + " (" + line[4] + "), " + line[2] + ", " + line[5]; LiteracyData data = new LiteracyData(l, Float.parseFloat(line[5])); literacy.add(data); } } catch (Exception e) { System.out.println(e.getMessage()); } // Sort the list using your custom LiteracyData comparator literacy.sort(new LiteracySorter()); // Iterate through the list and print each item to ensure it is sorted for(LiteracyData data : literacy) { System.out.println(data.summary); } } public static void main(String[] args) throws IOException { LiteracyComparison comparison = new LiteracyComparison(); comparison.run(); } }
Real time on x-axis with adjustable scale on x-axis?
I want to implement a trend graph with real time data coming continuously,for which am having time on x-axis with format "HH:MM:SS". Now my requirement is to have adjustable scale like 10min or 15min etc....And also how could i limit the time values on x-axis ? Please help me. Thanks! import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.data.general.SeriesException; import org.jfree.data.time.Second; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.xy.XYDataset; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RefineryUtilities; public class TimeSeries_AWT extends ApplicationFrame { public TimeSeries_AWT( final String title ) { super( title ); final XYDataset dataset = createDataset( ); final JFreeChart chart = createChart( dataset ); final ChartPanel chartPanel = new ChartPanel( chart ); chartPanel.setPreferredSize( new java.awt.Dimension( 560 , 370 ) ); chartPanel.setMouseZoomable( true , false ); setContentPane( chartPanel ); } private XYDataset createDataset( ) { final TimeSeries series = new TimeSeries( "Random Data" ); Second current = new Second( ); double value = 100.0; for (int i = 0; i < 4000; i++) { try { value = value + Math.random( ) - 0.5; series.add(current, new Double( value ) ); current = ( Second ) current.next( ); } catch(SeriesException e ) { System.err.println("Error adding to series"); } } return new TimeSeriesCollection(series); } private JFreeChart createChart( final XYDataset dataset ) { return ChartFactory.createTimeSeriesChart( "Computing Test", "Seconds", "Value", dataset, false, false, false); } public static void main( final String[ ] args ) { final String title = "Time Series Management"; final TimeSeries_AWT demo = new TimeSeries_AWT( title ); demo.pack( ); RefineryUtilities.positionFrameRandomly( demo ); demo.setVisible( true ); } } If you see output, the time is constant just static not changing dynamically. and while if time updates dynamically,i want the scale or tickunits to be adjusted dynamically at runtime like for example in the output graph the scale time is 5min. but i want that to be controlled at runtime to be anything like 10min,20min,40min etc... And another thing is in the output graph we can see 14 values on x-axis.which changes automatically when the graph is resized.but i want to control how many to be seen on the x-axis means i want to show some particular x time values on x-axis.which should also be configurable at launch of application.
Need an help to sort, Handle a tab seperated text file
Hi i have a text file(tab seperated). I would like to open it, read it and filter the required columns just like we do in excel. Could someone help with a sample code. I am stuck up with the concept on how to proceed further for the below steps. Price has to sorted with DESC order before processing. Always, First two column has to be printed in the output. Other than the first two columns only the required column has to be printed based on the input given. Input will be something like (Mango/purchased/top50). so it should pick only top50 "yet to buy" under "Mango" along with its respective first two columns. Sample input file. itemNumber Price Mango Apple Bannana 112201 purchased need to plan purchased 112202 55 yet to buy yet to buy purchased 112202 67 need to plan purchased purchased 112203 456 need to plan need to plan need to plan 112203 33 need to plan yet to buy need to plan 112204 456 need to plan yet to buy need to plan 112204 yet to buy purchased need to plan 112205 77 yet to buy purchased need to plan 112205 99 yet to buy purchased yet to buy 112206 0 yet to buy purchased yet to buy The code is incomplete. Here i am trying to add the heading of the file to an arraylist and adding the content to an another arraylist. Then trying to compare them using index number. Is this way correct ? import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class main { #SuppressWarnings({ "resource", "unused" }) public static void main(String[] args) throws IOException { ZipFile zipFile = new ZipFile( "filename.tsv.zip"); Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { String fruit = "Mango"; String mappingstatus = "purchased"; // reading a file ZipEntry entry = entries.nextElement(); InputStream stream = zipFile.getInputStream(entry); InputStreamReader read = new InputStreamReader(stream); BufferedReader br = new BufferedReader(read); // creating a new list List<String> heading = new ArrayList<String>(); String[] a = br.readLine().split("\t"); heading = Arrays.asList(a); List<String> content = new ArrayList<String>(); String s; while ((s = br.readLine()) != null) { String[] b = br.readLine().split("\t"); content = Arrays.asList(b); } } } }
Try this class Item implements Comparable<Item> { int itemNumber; int price; String mango; String apple; String bannana; public Item(int itemNumber, int price, String mango, String apple, String bannana) { this.itemNumber = itemNumber; this.price = price; this.mango = mango; this.apple = apple; this.bannana = bannana; } //GETTERS #Override public int compareTo(Item compareItem) { int comparePrice = ((Item) compareItem).getPrice(); //ascending order //return this.price - comparePrice; //descending order return comparePrice - this.price; } } public static void main(String[] args) { List<Item> items = new ArrayList<>(); //populate the items list by creating an Item for every line you read. //Handle null price values Collections.sort(items); //assuming input is some like 'Mango/purchased/top50' String input = "Mango/purchased/top50"; String[] parts = input.split("/"); int max = Integer.parseInt(parts[2].substring(3)); List<Item> result = new ArrayList<>(); for (int i = 0; i < items.size() && result.size() < max; i++) { Item item = items.get(i); if ((parts[0].equals("Mango") && item.getMango().equals(parts[1])) || (parts[0].equals("Apple") && item.getApple().equals(parts[1])) || (parts[0].equals("Bannana") && item.getBannana().equals(parts[1]))) { result.add(item); } } } Complete the commented sections and it must work. More references about sorting here: Sorting
Excel column distribution behavior during loop process, is it possible?
Using Apache POI 3.9, I want to map some values to an Excel template that looks similar to this: Looks pretty easy, at least for the Seller table in which I can map the values from my bean without problems. However, the issue I am facing is related to the Products table because I need to set the data from my bean for each column which makes the logic a little bit complex since during the loop process I'll need to look for the next column letter: e.g. My first product data will be set under B7 then at C7, D7, E7, etc until the loop ends. (Just to know, for this example template I am just showing the "Name" attribute of the product but each one has around 35 attributes in real life, that's why I am not showing the data in rows since the table won't look so friendly to the user in horizontal view). So, my question is: What happen If my products count is more than the total letters of the alphabet, how can I get the right column and cell during the loop process to set my product bean data following Excel column distribution? With "Excel column distribution" I mean the following: e.g. In Excel, when going to the column which contains the last letter of the alphabet "Z" then the columns continue showing AA, AB, AC, etc. Is it possible? This is what I've tried (using dummy data) and this will work until getting into the letter "Z" column: Empty Excel template used in this code snippet can be downloaded at: https://www.dropbox.com/s/eo0s54o9vkqhlbl/template.xls package com.app.test; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellReference; /** * Test class for generating Excel sheet */ public class ExportTest { public static void main(String[] args) throws IOException { CellReference ref; // Load template InputStream fis = ExportTest.class.getResourceAsStream("/template.xls"); Workbook workbook = new HSSFWorkbook(fis); fis.close(); // Constants final String TBL_FIRSTCOLUMN = "B"; // Starting product table column at sheet (in which the first product data will be set) final int MAX_PRODUCTS = 25; // Max. products added to the dummy products list (this will set the last product to the "Z" column) final int TBL_STARTROW = 7; // Starting product table row number at sheet (in which the first product data will be set) final int TBL_ATTR_ROWS = 1; // Number of attribute rows at products table (in this case just "Name") // Generate dummy data with seller information LinkedHashMap<String, String> cellMap = new LinkedHashMap<String, String>(); cellMap.put("B2", "1"); cellMap.put("B3", "Company"); cellMap.put("B4", "US"); // Generate dummy data with product information List<String> products = new ArrayList<String>(); for(int i = 0; i < MAX_PRODUCTS; ++i) { products.add("Chocolate"); } // Declare style for cells CellStyle style = workbook.createCellStyle(); style.setBorderLeft(CellStyle.BORDER_THIN); style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); style.setBorderRight(CellStyle.BORDER_THIN); style.setRightBorderColor(IndexedColors.BLACK.getIndex()); style.setBorderTop(CellStyle.BORDER_THIN); style.setTopBorderColor(IndexedColors.BLACK.getIndex()); style.setBorderBottom(CellStyle.BORDER_THIN); style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // Get template sheet Sheet sheet = workbook.getSheetAt(0); // Set values to "Seller" table for(Map.Entry<String, String> entry : cellMap.entrySet()) { ref = new CellReference(entry.getKey()); sheet.getRow(ref.getRow()).getCell(ref.getCol()).setCellValue(entry.getValue()); } // Set values to "Products" table for(int i = 0; i < products.size(); ++i) { // Get product name String name = products.get(i); String num = String.valueOf(i + 1); // Get char representation of the letter, this will allow me to get // C, D, E...Z columns but then I will get a IllegalArgumentException // if my products count exceed the alphabet letters. At this point I'll // need to follow Excel column distribution behavior. String nextLetter = String.valueOf((char)(TBL_FIRSTCOLUMN.charAt(0) + i)); for(int j = 0; j < TBL_ATTR_ROWS; ++j) { // Get cell reference of B7 then C7, etc ref = new CellReference(nextLetter + (TBL_STARTROW + j)); // Check if row/cell exists, otherwise it will throw NullPointerException when trying to get each one Row row = sheet.getRow(ref.getRow()); if(row == null) { row = sheet.createRow(ref.getRow()); } Cell cell = row.getCell(ref.getCol()); if(cell == null) { cell = row.createCell(ref.getCol()); } // Set value and style to cell cell.setCellValue(name + num); cell.setCellStyle(style); } } // Write workbook to file String path = String.format("%s%s%s", System.getProperty("user.home"), System.getProperty("file.separator"), "exported.xls"); OutputStream out = new FileOutputStream(new File(path)); workbook.write(out); out.close(); } } Then, If the products count exceeds the alphabet letters I will get the following exception: Exception in thread "main" java.lang.IllegalArgumentException: Invalid column index (-11). Allowable column range for BIFF8 is (0..255) or ('A'..'IV') at org.apache.poi.hssf.usermodel.HSSFCell.checkBounds(HSSFCell.java:939) at org.apache.poi.hssf.usermodel.HSSFCell.(HSSFCell.java:153) at org.apache.poi.hssf.usermodel.HSSFRow.createCell(HSSFRow.java:148) at org.apache.poi.hssf.usermodel.HSSFRow.createCell(HSSFRow.java:126) at org.apache.poi.hssf.usermodel.HSSFRow.createCell(HSSFRow.java:39) at com.app.test.ExportTest.main(ExportTest.java:99) (To replicate this try using MAX_PRODUCTS = 26, NOT 27 - alphabet count - since we are starting at B column on Excel sheet). Any help will be appreciated, thanks!
You call a utility method in Apache POI -- CellReference.convertNumToColString to map your column number into an Excel column designation. Takes in a 0-based base-10 column and returns a ALPHA-26 representation. eg column #3 -> D Since you're starting with column "B" (1), add 1 to i first. String nextLetter = String.valueOf(CellReference.convertNumToColString(i + 1));
Predicting data created on-the-fly in WEKA using a premade model file
I want to create a WEKA Java program that reads a group of newly created data that will be fed to a premade model from the GUI version. Here is the program: import java.util.ArrayList; import weka.classifiers.Classifier; import weka.core.Attribute; import weka.core.DenseInstance; import weka.core.Instances; import weka.core.Utils; public class UseModelWithData { public static void main(String[] args) throws Exception { // load model String rootPath = "G:/"; Classifier classifier = (Classifier) weka.core.SerializationHelper.read(rootPath+"j48.model"); // create instances Attribute attr1 = new Attribute("age"); Attribute attr2 = new Attribute("menopause"); Attribute attr3 = new Attribute("tumor-size"); Attribute attr4 = new Attribute("inv-nodes"); Attribute attr5 = new Attribute("node-caps"); Attribute attr6 = new Attribute("deg-malig"); Attribute attr7 = new Attribute("breast"); Attribute attr8 = new Attribute("breast-quad"); Attribute attr9 = new Attribute("irradiat"); Attribute attr10 = new Attribute("Class"); ArrayList<Attribute> attributes = new ArrayList<Attribute>(); attributes.add(attr1); attributes.add(attr2); attributes.add(attr3); attributes.add(attr4); attributes.add(attr5); attributes.add(attr6); attributes.add(attr7); attributes.add(attr8); attributes.add(attr9); attributes.add(attr10); // predict instance class values Instances testing = new Instances("Test dataset", attributes, 0); // add data double[] values = new double[testing.numAttributes()]; values[0] = testing.attribute(0).addStringValue("60-69"); values[1] = testing.attribute(1).addStringValue("ge40"); values[2] = testing.attribute(2).addStringValue("10-14"); values[3] = testing.attribute(3).addStringValue("15-17"); values[4] = testing.attribute(4).addStringValue("yes"); values[5] = testing.attribute(5).addStringValue("2"); values[6] = testing.attribute(6).addStringValue("right"); values[7] = testing.attribute(7).addStringValue("right_up"); values[8] = testing.attribute(0).addStringValue("yes"); values[9] = Utils.missingValue(); // add data to instance testing.add(new DenseInstance(1.0, values)); // instance row to predict int index = 10; // perform prediction double myValue = classifier.classifyInstance(testing.instance(10)); // get the name of class value String prediction = testing.classAttribute().value((int) myValue); System.out.println("The predicted value of the instance [" + Integer.toString(index) + "]: " + prediction); } } My references include: Using a premade WEKA model in Java the WEKA Manual provided in the 3.7.10 version - 17.3 Creating datasets in memory Creating a single instance for classification in WEKA So far the part where I create a new Instance inside the script causes the following error: Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 10, Size: 1 in the line double myValue = classifier.classifyInstance(testing.instance(10)); I just want to use a latest row of instance values to a premade WEKA model. How do I solve this? Resources Program file Arff file j48.model
You have the error because you are trying to access the 11th instance and have only created one. If you always want to access the last instance you might try the following: double myValue = classifier.classifyInstance(testing.lastInstance()); Additionally, I don't believe that you are creating the instances you hope for. After looking at your provided ".arff" file, which I believe you are trying to mimic, I think you should proceed making instances as follows: FastVector atts; FastVector attAge; Instances testing; double[] vals; // 1. set up attributes atts = new FastVector(); //age attAge = new FastVector(); attAge.addElement("10-19"); attAge.addElement("20-29"); attAge.addElement("30-39"); attAge.addElement("40-49"); attAge.addElement("50-59"); attAge.addElement("60-69"); attAge.addElement("70-79"); attAge.addElement("80-89"); attAge.addElement("90-99"); atts.addElement(new Attribute("age", attAge)); // 2. create Instances object testing = new Instances("breast-cancer", atts, 0); // 3. fill with data vals = new double[testing.numAttributes()]; vals[0] = attAge.indexOf("10-19"); testing.add(new DenseInstance(1.0, vals)); // 4. output data System.out.println(testing); Of course I did not create the whole dataset, but the technique would be the same.