When i create test for Google Or-Tools and send my distance matrix, solution the solution is always null.
When i use default distance matrix from here https://developers.google.com/optimization/routing/vrp
but when i use my custom distanceMatrix array Assigment solution is always null.
Where is mistake?
Full test class
import com.google.ortools.constraintsolver.*;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.logging.Logger;
#RunWith(SpringRunner.class)
#SpringBootTest
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OrToolsTests {
private static final Logger logger = Logger.getLogger(OrToolsTests.class.getName());
static {
System.loadLibrary("jniortools");
}
#Test
public void b_googleOrTools() throws Exception {
// Instantiate the data problem.
final DataModel data = new DataModel();
// Create Routing Index Manager
RoutingIndexManager manager =
new RoutingIndexManager(data.data.length, data.vehicleNumber, data.depot);
// Create Routing Model.
RoutingModel routing = new RoutingModel(manager);
// Create and register a transit callback.
final int transitCallbackIndex =
routing.registerTransitCallback((long fromIndex, long toIndex) -> {
// Convert from routing variable Index to user NodeIndex.
int fromNode = manager.indexToNode(fromIndex);
int toNode = manager.indexToNode(toIndex);
return data.data[fromNode][toNode];
});
// Define cost of each arc.
routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
// Add Distance constraint.
routing.addDimension(transitCallbackIndex, 0, 3000,
true, // start cumul to zero
"Distance");
RoutingDimension distanceDimension = routing.getMutableDimension("Distance");
distanceDimension.setGlobalSpanCostCoefficient(100);
// Setting first solution heuristic.
RoutingSearchParameters searchParameters =
main.defaultRoutingSearchParameters()
.toBuilder()
.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC)
.build();
// Solve the problem.
Assignment solution = routing.solveWithParameters(searchParameters);
// Print solution on console.
printSolution(data, routing, manager, solution);
}
private void printSolution(
DataModel data, RoutingModel routing, RoutingIndexManager manager, Assignment solution) {
// Inspect solution.
long maxRouteDistance = 0;
for (int i = 0; i < data.vehicleNumber; ++i) {
long index = routing.start(i);
logger.info("Route for Vehicle " + i + ":");
long routeDistance = 0;
String route = "";
while (!routing.isEnd(index)) {
route += manager.indexToNode(index) + " -> ";
long previousIndex = index;
index = solution.value(routing.nextVar(index));
routeDistance += routing.getArcCostForVehicle(previousIndex, index, i);
}
logger.info(route + manager.indexToNode(index));
logger.info("Distance of the route: " + routeDistance + "m");
maxRouteDistance = Math.max(routeDistance, maxRouteDistance);
}
logger.info("Maximum of the route distances: " + maxRouteDistance + "m");
}
class DataModel {
public final long[][] data = {
{0, 58305, 41338, 16599, 22834, 36364, 24979, 9797, 22023, 5880, 21282, 39248},
{58147, 0, 82634, 49102, 39605, 93558, 72909, 49687, 67379, 55889, 76274, 22047},
{41663, 81167, 0, 47046, 58798, 56366, 18071, 41586, 60532, 36117, 49432, 74933},
{15666, 49990, 53000, 0, 7358, 51077, 30428, 13558, 34534, 13408, 33793, 30933},
{22151, 39552, 59486, 7391, 0, 57563, 36914, 20043, 41019, 19893, 40278, 24535},
{36164, 93036, 56237, 51331, 57566, 0, 37419, 44529, 44381, 41822, 17567, 73980},
{25224, 72585, 18046, 30880, 37115, 37483, 0, 25147, 44093, 19678, 30549, 53529},
{9218, 49544, 41424, 13485, 19719, 44630, 25065, 0, 28086, 5966, 27345, 30488},
{22816, 72597, 60379, 34430, 40665, 44423, 44020, 27629, 0, 24921, 27138, 57079},
{6858, 56163, 36826, 14458, 20693, 42270, 20467, 6781, 25726, 0, 24985, 37107},
{22678, 75998, 49002, 34292, 40527, 17284, 30184, 27490, 27342, 24783, 0, 56941},
{38986, 22165, 76018, 29941, 24347, 74398, 53749, 30526, 57854, 36728, 57113, 0}};
public final int vehicleNumber = 4;
public final int depot = 0;
}
}
From what I understand, you add a dimension with a max cumul of 3000, while the distance matrix has a lot of inter-node distances above 10k.
The 3000 value in #addDimension represents the vehicle maximum travel distance. Since the values in your distance matrix are higher, or-tools is not able to find a solution.
To fix this you have to change the 3000 value so that it is higher than the highest value in your distance matrix. For example
change
// Add Distance constraint.
routing.addDimension(transitCallbackIndex, 0, 3000,
true, // start cumul to zero
"Distance");
to
// Add Distance constraint.
routing.addDimension(transitCallbackIndex, 0, 100000,
true, // start cumul to zero
"Distance");
and your code will work.
Related
I am writing a Java program by using the Binance JAVA API to retrieve the 1-minute interval candelsticks of a trading pair. Using this Java class, I want to calculate the EMA (Exponential Moving Average) of the past 10 days.
The Binance JAVA API websocket implementation gets the latest depth events, which also contains the current closing price that I use to update the EMA calculation by calling the EMA#update method.
However, I notice that the EMA showing on the Binance's graph, does not correspond to the ones I get from my code. Also, I notice that the values need some time to 'settle' before giving (somewhat) same values compared to those shown on Binance.
On TradingView I found a formula to calculate the EMA (that shows the same EMA value as on Binance), but that is different than the one used in the EMA class. However, even when using this formula, the values are very different than the one on Binance.
Could someone help me figure out what the issue is and how to obtain the same values?
UPDATE 1: code provided
import java.util.*;
import java.util.stream.Collectors;
import com.binance.api.client.BinanceApiClientFactory;
import com.binance.api.client.BinanceApiRestClient;
import com.binance.api.client.BinanceApiWebSocketClient;
import com.binance.api.client.domain.market.Candlestick;
import com.binance.api.client.domain.market.CandlestickInterval;
import core.util.text.DecimalFormat;
import core.util.text.StringUtil;
public class test_003
{
private Map<Long, Candlestick> candlesticksCache = new TreeMap<>();
private EMA EMA_10;
private EMA EMA_20;
public static void main(String[] pArgs)
{
new test_003();
}
private test_003()
{
Locale.setDefault(Locale.US);
candlesticksCacheExample("ADAUSDT", CandlestickInterval.ONE_MINUTE);
}
private void candlesticksCacheExample(String symbol, CandlestickInterval interval)
{
initializeCandlestickCache(symbol, interval);
startCandlestickEventStreaming(symbol, interval);
}
private void initializeCandlestickCache(String symbol, CandlestickInterval interval)
{
BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance();
BinanceApiRestClient client = factory.newRestClient();
List<Candlestick> candlestickBars_10 = client.getCandlestickBars(symbol.toUpperCase(), interval, Integer.valueOf(11), null, null);
List<Candlestick> candlestickBars_20 = client.getCandlestickBars(symbol.toUpperCase(), interval, Integer.valueOf(21), null, null);
List<Double> closingPriceList_10 = candlestickBars_10.stream().map(c -> Double.valueOf(c.getClose())).collect(Collectors.toList());
List<Double> closingPriceList_20 = candlestickBars_20.stream().map(c -> Double.valueOf(c.getClose())).collect(Collectors.toList());
EMA_10 = new EMA(closingPriceList_10, Integer.valueOf(10));
EMA_20 = new EMA(closingPriceList_20, Integer.valueOf(20));
}
private void startCandlestickEventStreaming(String symbol, CandlestickInterval interval)
{
BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance();
BinanceApiWebSocketClient client = factory.newWebSocketClient();
client.onCandlestickEvent(symbol.toLowerCase(), interval, response -> {
Long openTime = response.getOpenTime();
Candlestick updateCandlestick = candlesticksCache.get(openTime);
if (updateCandlestick == null)
{
// new candlestick
updateCandlestick = new Candlestick();
}
// update candlestick with the stream data
updateCandlestick.setOpenTime(response.getOpenTime());
updateCandlestick.setOpen(response.getOpen());
updateCandlestick.setLow(response.getLow());
updateCandlestick.setHigh(response.getHigh());
updateCandlestick.setClose(response.getClose());
updateCandlestick.setCloseTime(response.getCloseTime());
updateCandlestick.setVolume(response.getVolume());
updateCandlestick.setNumberOfTrades(response.getNumberOfTrades());
updateCandlestick.setQuoteAssetVolume(response.getQuoteAssetVolume());
updateCandlestick.setTakerBuyQuoteAssetVolume(response.getTakerBuyQuoteAssetVolume());
updateCandlestick.setTakerBuyBaseAssetVolume(response.getTakerBuyQuoteAssetVolume());
// Store the updated candlestick in the cache
candlesticksCache.put(openTime, updateCandlestick);
double closingPrice = Double.valueOf(updateCandlestick.getClose());
EMA_10.update(closingPrice);
EMA_20.update(closingPrice);
System.out.println(StringUtil.replacePlaceholders("Closing price: %1 | EMA(10): %2 - EMA(20): %3", response.getClose(),
DecimalFormat.format(EMA_10.get(), "#.#####"),
DecimalFormat.format(EMA_20.get(), "#.#####")));
});
}
public class EMA
{
private double currentEMA;
private final int period;
private final double multiplier;
private final List<Double> EMAhistory;
private final boolean historyNeeded;
private String fileName;
public EMA(List<Double> closingPrices, int period)
{
this(closingPrices, period, false);
}
public EMA(List<Double> closingPrices, int period, boolean historyNeeded)
{
currentEMA = 0;
this.period = period;
this.historyNeeded = historyNeeded;
this.multiplier = 2.0 / (double) (period + 1);
this.EMAhistory = new ArrayList<>();
init(closingPrices);
}
public double get()
{
return currentEMA;
}
public double getTemp(double newPrice)
{
return (newPrice - currentEMA) * multiplier + currentEMA;
}
public void init(List<Double> closingPrices)
{
if (period > closingPrices.size()) return;
//Initial SMA
for (int i = 0; i < period; i++)
{
currentEMA += closingPrices.get(i);
}
currentEMA = currentEMA / (double) period;
if (historyNeeded) EMAhistory.add(currentEMA);
//Dont use latest unclosed candle;
for (int i = period; i < closingPrices.size() - 1; i++)
{
update(closingPrices.get(i));
}
}
public void update(double newPrice)
{
// EMA = (Close - EMA(previousBar)) * multiplier + EMA(previousBar)
currentEMA = (newPrice - currentEMA) * multiplier + currentEMA;
if (historyNeeded) EMAhistory.add(currentEMA);
}
public int check(double newPrice)
{
return 0;
}
public String getExplanation()
{
return null;
}
public List<Double> getEMAhistory()
{
return EMAhistory;
}
public int getPeriod()
{
return period;
}
}
}
UPDATE 2
The problem is that onCandlestickEvent is not just called when a candle is completed, but actually multiple times per minute (every 2 seconds or so). The data that you are receiving in the response spans the time from when the candle is opened until the event time of the response, whether the candle is completed or not.
To see what I mean, you could replace the System.out() statement in your startCandlestickEventStreaming method with the following:
System.out.println(response.getOpenTime() + ";" +
response.getEventTime() + ";" +
response.getCloseTime());
You will see that the close time of the candle actually lies in the future.
In order to update your EMA correctly, you will have to wait until the candle has actually been completed. You could store the open time of the tentative candle in a member variable, check if it has changed since the last time onCandlestickEvent was called, and then update your EMA with the final close value of the candle:
client.onCandlestickEvent(symbol.toLowerCase(), interval, response -> {
Long openTime = response.getOpenTime();
Candlestick updateCandlestick = candlesticksCache.get(openTime);
if (updateCandlestick == null)
{
// new candlestick
updateCandlestick = new Candlestick();
}
// update candlestick with the stream data
...
// Store the updated candlestick in the cache
candlesticksCache.put(openTime, updateCandlestick);
if (openTime > m_LastOpenTime)
{
// need to get the close of the PREVIOUS candle
Candlestick previousCandle = candlesticksCache.get(m_LastOpenTime);
double closingPrice = Double.valueOf(previousCandle.getClose());
EMA_10.update(closingPrice);
EMA_20.update(closingPrice);
System.out.println(StringUtil.replacePlaceholders("Closing price: %1 | EMA(10): %2 - EMA(20): %3", response.getClose(),
DecimalFormat.format(EMA_10.get(), "#.#####"),
DecimalFormat.format(EMA_20.get(), "#.#####")));
m_LastOpenTime = openTime;
}
});
You'll probably get an exception on the first response, because there are no candles on the stack yet and we don't have a m_LastOpenTime. You could get the current server time before calling client.onCandlestickEvent():
private void startCandlestickEventStreaming(String symbol, CandlestickInterval interval)
{
BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance();
BinanceApiWebSocketClient client = factory.newWebSocketClient();
BinanceApiRestClient restClient = factory.newRestClient();
m_LastOpenTime = restClient.getServerTime();
client.onCandlestickEvent(symbol.toLowerCase(), interval, response -> {
...
}
}
I noticed there's actually a much simpler way than my other answer. I'm leaving that one up, however, because it could still be relevant for dealing with a dodgy connection where you can't necessarily rely on always getting the final candlestick with your response.
The response.getBarFinal()) method allows for testing whether the response you have received is the final candlestick or if it is just an intermediate one. If you change your code as follows, your EMA will only get updated with the final close value of the candle as it should be:
if (response.getBarFinal())
{
double closingPrice = Double.valueOf(updateCandlestick.getClose());
EMA_10.update(closingPrice);
EMA_20.update(closingPrice);
System.out.println(StringUtil.replacePlaceholders("Closing price: %1 | EMA(10): %2 - EMA(20): %3", response.getClose(),
DecimalFormat.format(EMA_10.get(), "#.#####"),
DecimalFormat.format(EMA_20.get(), "#.#####")));
}
so im writing an assignment for class. I have gotten stuck in my attempts to write a function to select a random element. The array that I am trying to access is stored in an interface file. I have one main file that implements the interface, and then multiple files extending the main file.
I am to write and test out how to select a random element from that interface file. The file contains many different arrays but for testing purposes, I will be selecting the lastName[]. How the function is written below is throwing an out of bounds error, but I don't know how to go about correcting it.
This is the test file:
import java.util.Random;
public class MemberTest {
public static void main(String[] args) {
Random rnd = new Random();
int rndNum = rnd.nextInt();
Member m = new Member();
Student s = new Student();
Staff ss = new Staff();
Faculty f = new Faculty();
Employee e = new Employee();
Names n = new Member();
System.out.println(n.lastName[rndNum]);
System.out.println(m.toString(true));
}
}
This is the file that implements Names.java
public class Member implements Comparable<Member>, Names{
public Member() {}
// randomly fill in all data member.
public void generate() {}
public String toString() {
return toString(false);
}
public String toString(boolean ok) {
return String.format("%s%3d-%2d-%4d %15s, %-15s", ok? "Mem " : "", ID / 1000000, ID / 10000
% 100, ID % 10000, lastName, firstName );
}
//public int compareTo(Member) {}
public int compareTo(Member m) {
return ID - m.ID;
}
public String htmlRow() {
return String.format("<TR>%s</TR>", htmlColumns());
}
public String htmlColumns() {
return String.format("<TD>%3d-%2d-%4d</TD> <TD>%15s,</TD> <TD>%-15s</TD>", ID / 1000000, ID / 10000
% 100, ID % 10000, lastName, firstName );
}
protected String firstName[], lastName[];
protected int ID;
}
This is the interface file:
public interface Names {
// Fields in interface are always and implicitly public, static and final.
// All methods in interface are implicitly public and abstract.
public static final String lastName [] = {
"Abdalla", "Andres", "Anzai", "Armstrong", "Arvig", "Ash", "Baca", "Badine",
"Baehr", "Bair", "Baligad", "Barlow", "Barrett", "Becker", "Bell",
"Benbow", "Biggs", "Blevins", "Blood", "Bohan", "Bond", "Bonner",
"Bosch", "Bryson", "Buechele", "Bullis", "Burk", "Burns", "Byron",
"Calderon", "Careuthers", "Carr", "Carson", "Carter", "Castle", "Chan",
"Charney", "Christenson", "Cisneros", "Cliton", "Coldewey", "Coodey",
"Cook", "Cooper", "Coy", "Currie", "Curtis", "Dirkse", "Dirscoll",
"Dodrill", "Ehlert", "Elias", "Elliott", "Enterline", "Ericsson",
"Fernandez", "Fisher", "Flory", "Freese", "Fruzza", "Fu", "Fuhrman", "Gage",
"Garcia", "Garmon", "Giffith", "Gill", "Gillen", "Glascock", "Gomez",
"Goraya", "Greer", "Hansen", "Hartley", "Hawkins", "Hemme", "Hensley",
"Hentges", "Herron", "Hightower", "Hines", "Holloway", "Holmes",
"Issac", "Jackson", "Jagodin", "Jiang", "Johnson", "Jordan", "Jouda", "Joven",
"Kalpesh", "Katz", "Kaur", "Kegley", "Kimsey", "King", "Kohn", "Kone",
"LaCasse", "Lackey", "Lathrop", "Le", "Levy", "Lynos", "Maas", "Mackall",
"Madsen", "Magee", "Maldonado", "McDaneld", "McMillian", "McNeill",
"Meadors", "Medina", "Metz", "Millikin", "Minner", "Mondragon", "Monge", "Moore",
"Moreno", "Murkland", "Musick", "Myers", "Neal", "Ngo", "Nolan", "Nunez",
"O'Neil", "Oropeza", "Owen", "Patel", "Pfister", "Philips", "Picato",
"Porras", "Porter", "Pratt", "Pryor", "Ragle", "Rai", "Raja", "Rill",
"Roberts", "Roddy", "Rose", "Roux", "Rubio", "Ruiz", "Saito", "Samidin",
"Sampson", "Sanchez", "Scanlan", "Schmidt", "Schoberg", "Sheppard",
"Simmons", "Sison", "Smith", "Snow", "Soto", "Sozinho", "Stevens",
"Stidham", "Strange", "Sy", "Tamayo", "Taylor", "Thomas", "Tran", "Vincent",
"Walker", "Wandke", "Ward", "Warner", "Waugh", "Webb", "Wells", "White",
"Wilson", "Winther", "Wuertz", "Yong" };
I suspect the problem here are these lines in the test code:
Random rnd = new Random();
int rndNum = rnd.nextInt();
...
System.out.println(n.lastName[rndNum]);
Now rnd doesn't really take care of what value it is bounded with or what is the maximum range here. You would need to bound it.
So, right now rnd.nextInt() can yield 100, 1000, 10000...
This is what you need to control
what you can do is, re-write the following line as:
int rndNum = rnd.nextInt();
as
int rndNum = rnd.nextInt()%lastName.length;
NOTE: I haven't gone through the whole code, but the first issue I see. Try it out and let know if there are still issues.
As #Himanshu says, if you dont have the control of the max value of your random, its easy that your code fails with ArrayIndexOutOfBoundsException
try to change the line who gets the integer: int rndNum = rnd.nextInt(); to int rndNum = rnd.nextInt(Names.lastName.length); and should work without problems.
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.
I am naming all of these one by one. Is there a method that takes less space?
public class Matt{
PImage matt,
imgLS1, imgLS2, imgLS3, imgRS1, imgRS2, imgRS3,
imgLSB1, imgLSB2, imgLSB3, imgRSB1, imgRSB2, imgRSB3,
imgLW1, imgLW2, imgLW3, imgRW1, imgRW2, imgRW3,
imgLWB1, imgLWB2, imgLWB3, imgRWB1, imgRWB2, imgRWB3;
public Matt(){
imgLS1 = loadImage("./Images/Matt/MattLS1.png");
imgLS2 = loadImage("./Images/Matt/MattLS2.png");
imgLS3 = loadImage("./Images/Matt/MattLS3.png");
imgRS1 = loadImage("./Images/Matt/MattRS1.png");
imgRS2 = loadImage("./Images/Matt/MattRS2.png");
imgRS3 = loadImage("./Images/Matt/MattRS3.png");
imgLSB1 = loadImage("./Images/Matt/MattLSB1.png");
imgLSB2 = loadImage("./Images/Matt/MattLSB2.png");
imgLSB3 = loadImage("./Images/Matt/MattLSB3.png");
imgRSB1 = loadImage("./Images/Matt/MattRSB1.png");
imgRSB2 = loadImage("./Images/Matt/MattRSB2.png");
imgRSB3 = loadImage("./Images/Matt/MattRSB3.png");
imgLW1 = loadImage("./Images/Matt/MattLW1.png");
imgLW2 = loadImage("./Images/Matt/MattLW2.png");
imgLW3 = loadImage("./Images/Matt/MattLW3.png");
imgRW1 = loadImage("./Images/Matt/MattRW1.png");
imgRW2 = loadImage("./Images/Matt/MattRW2.png");
imgRW3 = loadImage("./Images/Matt/MattRW3.png");
imgLWB1 = loadImage("./Images/Matt/MattLWB1.png");
imgLWB2 = loadImage("./Images/Matt/MattLWB2.png");
imgLWB3 = loadImage("./Images/Matt/MattLWB3.png");
imgRWB1 = loadImage("./Images/Matt/MattRWB1.png");
imgRWB2 = loadImage("./Images/Matt/MattRWB2.png");
imgRWB3 = loadImage("./Images/Matt/MattRWB3.png");
}
}
Put your images in a Map<String,PImage>, organizing the map by image suffix. As far as accessing the images is concerned, this approach may be slightly less convenient/efficient than using variables directly, but it will save you a lot of space:
static final String[] suffixes = new String[] {"LS1", "LS2", "LS3", ..., "RWB3"};
Map<String,PImage> images = new HashMap<String,PImage>();
public Matt() {
for (String suffix : suffixes) {
PImage image = loadImage("./Images/Matt/Matt"+suffix+".png");
images.put(suffix, image);
}
}
Since the "LS", etc., seem to have semantic meaning, I'd suggest a variation of the solution by #dasblinkenlight that uses an enum:
final int N_FILES = 3; // files/position -- could also be a variable
enum Position {
LS, RS, LSB, RSB, LW, RW, LWB, LRB
}
Map<Position, String[]> files = new EnumMap<>(Position.class);
for (Position pos : Position.values()) {
String[] posFiles = new String[N_FILES];
files.put(pos, posFiles);
for (int i = 1; i <= N_FILES; ++i) {
posFiles[i-1] = "./Images/Matt/Matt" + pos.name() + i + ".png";
}
}
Then you can access any element with code like this:
Position p = RS; // or any other value
int index = 0; // 0..(N_FILES-1), corresponding to suffixes 1..N_FILES
String fileName = files.get(p)[i];
How do you call the microphone built into a computer to turn on when a user visits a site? I've heard that there a number of different ways to do so, but I'd like some advice on the best way.
To provide a meta-level view, I'm planning on having the mic pick up noise and display it as a graphic equalizer (of sorts) but not record it.
Code is appreciated!
Here is an example of a Java applet that reads from a microphone.
For my flash microphone i use this class
import org.bytearray.micrecorder.MicRecorder;
import org.bytearray.micrecorder.encoder.WaveEncoder;
import org.bytearray.micrecorder.events.RecordingEvent;
(just google it to get the code)
and its as easy as calling this
recorder = new MicRecorder(new WaveEncoder(),null,75,16);
recorder.addEventListener(RecordingEvent.RECORDING, onRecording)
recorder.addEventListener(Event.COMPLETE, onRecordComplete)
then you can do something like this to visualize the change in microphone noise. you of course have to make your own .fla movie clip that will display the "sound" in however you want to visualize it
public function onRecording(e:RecordingEvent)
{
var al:Number = recorder.microphone.activityLevel;
TweenMax.to(soundMeter, .1, {scaleX:al * .01, onUpdate:onActivitylevelUpdate});//, onUpdateParams:[al]})
}
public function onActivitylevelUpdate()
{
xpos = speedX;
ypos = centerY + Math.sin(angle) * amplitude
angle += speedAngle;
graphics.lineTo(xpos,ypos)
}
You want to look at the Microphone class to pick up sound off the mic, and at the computeSpectrum() method to calculate frequency values for the equalizer.
Here's an example of what you're trying to do, from the adobe samples:
package {
import flash.display.Sprite;
import flash.display.Graphics;
import flash.events.Event;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundMixer;
import flash.net.URLRequest;
import flash.utils.ByteArray;
import flash.text.TextField;
public class SoundMixer_computeSpectrumExample extends Sprite {
public function SoundMixer_computeSpectrumExample() {
var snd:Sound = new Sound();
var req:URLRequest = new URLRequest("Song1.mp3");
snd.load(req);
var channel:SoundChannel;
channel = snd.play();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
channel.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
}
private function onEnterFrame(event:Event):void {
var bytes:ByteArray = new ByteArray();
const PLOT_HEIGHT:int = 200;
const CHANNEL_LENGTH:int = 256;
SoundMixer.computeSpectrum(bytes, false, 0);
var g:Graphics = this.graphics;
g.clear();
g.lineStyle(0, 0x6600CC);
g.beginFill(0x6600CC);
g.moveTo(0, PLOT_HEIGHT);
var n:Number = 0;
for (var i:int = 0; i < CHANNEL_LENGTH; i++) {
n = (bytes.readFloat() * PLOT_HEIGHT);
g.lineTo(i * 2, PLOT_HEIGHT - n);
}
g.lineTo(CHANNEL_LENGTH * 2, PLOT_HEIGHT);
g.endFill();
g.lineStyle(0, 0xCC0066);
g.beginFill(0xCC0066, 0.5);
g.moveTo(CHANNEL_LENGTH * 2, PLOT_HEIGHT);
for (i = CHANNEL_LENGTH; i > 0; i--) {
n = (bytes.readFloat() * PLOT_HEIGHT);
g.lineTo(i * 2, PLOT_HEIGHT - n);
}
g.lineTo(0, PLOT_HEIGHT);
g.endFill();
}
private function onPlaybackComplete(event:Event):void {
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}}