/* Copyright (C) 2013 [email protected] This file is part of ComputationalEconomy. ComputationalEconomy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ComputationalEconomy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with ComputationalEconomy. If not, see <http://www.gnu.org/licenses/>. */ package io.github.uwol.compecon.dashboard.panel; import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; import java.util.Map; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.ValueMarker; import org.jfree.chart.plot.XYPlot; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.xy.DefaultHighLowDataset; import org.jfree.data.xy.IntervalXYDataset; import org.jfree.data.xy.XYDataset; import io.github.uwol.compecon.economy.materia.GoodType; import io.github.uwol.compecon.economy.sectors.financial.Currency; import io.github.uwol.compecon.engine.applicationcontext.ApplicationContext; import io.github.uwol.compecon.engine.statistics.ModelRegistry.IncomeSource; import io.github.uwol.compecon.engine.statistics.NotificationListenerModel.ModelListener; import io.github.uwol.compecon.engine.statistics.PeriodDataDistributionModel.SummaryStatisticalData; import io.github.uwol.compecon.engine.statistics.PricesModel; import io.github.uwol.compecon.engine.statistics.PricesModel.PriceModel; import io.github.uwol.compecon.math.ConvexFunction.ConvexFunctionTerminationCause; public class HouseholdsPanel extends AbstractChartsPanel implements ModelListener { private static final long serialVersionUID = 1L; public class HouseholdsPanelForCurrency extends JPanel implements ModelListener { private static final long serialVersionUID = 1L; protected final Currency currency; protected JFreeChart incomeDistributionChart; protected JPanel marketDepthPanel; protected JPanel priceTimeSeriesPanel; public HouseholdsPanelForCurrency(final Currency currency) { this.currency = currency; setLayout(new GridLayout(0, 3)); this.add(createUtilityPanel(currency)); // this.add(createUtilityFunctionMechanicsPanel(currency)); this.add(createIncomeConsumptionSavingPanel(currency)); this.add(createConsumptionSavingRatePanel(currency)); this.add(createWageDividendPanel(currency)); this.add(createIncomeSourcePanel(currency)); incomeDistributionChart = createIncomeDistributionPanel(currency); this.add(new ChartPanel(incomeDistributionChart)); this.add(createLorenzCurvePanel(currency)); this.add(createHouseholdBalanceSheetPanel(currency)); this.add(createLabourHourSupplyPanel(currency)); this.add(createPricingBehaviourMechanicsPanel(currency, GoodType.LABOURHOUR)); ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.incomeDistributionModel.registerListener(this); // no registration with the price and market depth model, as they // call listeners synchronously notifyListener(); } @Override public synchronized void notifyListener() { if (isShowing()) { /* * income distribution chart */ final XYPlot plot = ((XYPlot) incomeDistributionChart.getPlot()); plot.setDataset(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.incomeDistributionModel .getHistogramDataset()); plot.clearDomainMarkers(); final SummaryStatisticalData summaryStatisticalData = ApplicationContext.getInstance() .getModelRegistry().getNationalEconomyModel(currency).householdsModel.incomeDistributionModel .getSummaryStatisticalData(); if (summaryStatisticalData.originalValues != null && summaryStatisticalData.originalValues.length > 0) { addValueMarker(incomeDistributionChart, summaryStatisticalData.originalValues[summaryStatisticalData.xWith10PercentY], "10 %"); addValueMarker(incomeDistributionChart, summaryStatisticalData.originalValues[summaryStatisticalData.xWith20PercentY], "20 %"); addValueMarker(incomeDistributionChart, summaryStatisticalData.originalValues[summaryStatisticalData.xWith30PercentY], "30 %"); addValueMarker(incomeDistributionChart, summaryStatisticalData.originalValues[summaryStatisticalData.xWith40PercentY], "40 %"); addValueMarker(incomeDistributionChart, summaryStatisticalData.originalValues[summaryStatisticalData.xWith50PercentY], "50 %"); addValueMarker(incomeDistributionChart, summaryStatisticalData.originalValues[summaryStatisticalData.xWith60PercentY], "60 %"); addValueMarker(incomeDistributionChart, summaryStatisticalData.originalValues[summaryStatisticalData.xWith70PercentY], "70 %"); addValueMarker(incomeDistributionChart, summaryStatisticalData.originalValues[summaryStatisticalData.xWith80PercentY], "80 %"); addValueMarker(incomeDistributionChart, summaryStatisticalData.originalValues[summaryStatisticalData.xWith90PercentY], "90 %"); } // prices panel if (priceTimeSeriesPanel != null) { this.remove(priceTimeSeriesPanel); } priceTimeSeriesPanel = createPriceTimeSeriesChartPanel(currency); this.add(priceTimeSeriesPanel); // market depth panel if (marketDepthPanel != null) { this.remove(marketDepthPanel); } marketDepthPanel = createMarketDepthPanel(currency); this.add(marketDepthPanel); validate(); repaint(); } } } protected JTabbedPane jTabbedPaneCurrency = new JTabbedPane(); public HouseholdsPanel() { setLayout(new BorderLayout()); for (final Currency currency : Currency.values()) { final HouseholdsPanelForCurrency panelForCurrency = new HouseholdsPanelForCurrency(currency); jTabbedPaneCurrency.addTab(currency.getIso4217Code(), panelForCurrency); panelForCurrency.setBackground(Color.lightGray); } jTabbedPaneCurrency.addChangeListener(new ChangeListener() { @Override public void stateChanged(final ChangeEvent e) { if (e.getSource() instanceof JTabbedPane) { final JTabbedPane pane = (JTabbedPane) e.getSource(); final HouseholdsPanelForCurrency selectedComponent = (HouseholdsPanelForCurrency) pane .getSelectedComponent(); selectedComponent.notifyListener(); } } }); add(jTabbedPaneCurrency, BorderLayout.CENTER); } protected void addValueMarker(final JFreeChart chart, final double position, final String label) { final ValueMarker marker = new ValueMarker(position); marker.setPaint(Color.black); marker.setLabel(label); final XYPlot plot = (XYPlot) chart.getPlot(); plot.addDomainMarker(marker); } protected ChartPanel createConsumptionSavingRatePanel(final Currency currency) { final TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection(); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.consumptionRateModel.getTimeSeries()); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.savingRateModel.getTimeSeries()); final JFreeChart chart = ChartFactory.createTimeSeriesChart("Consumption & Saving Rate", "Date", "Consumption & Saving Rate", timeSeriesCollection, true, true, false); configureChart(chart); return new ChartPanel(chart); } protected ChartPanel createIncomeConsumptionSavingPanel(final Currency currency) { final TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection(); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.incomeModel.getTimeSeries()); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.consumptionModel.getTimeSeries()); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.savingModel.getTimeSeries()); final JFreeChart chart = ChartFactory.createTimeSeriesChart("Consumption & Saving", "Date", "Consumption & Saving", timeSeriesCollection, true, true, false); configureChart(chart); return new ChartPanel(chart); } protected JFreeChart createIncomeDistributionPanel(final Currency currency) { final IntervalXYDataset dataset = ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.incomeDistributionModel.getHistogramDataset(); final JFreeChart incomeDistributionChart = ChartFactory.createHistogram("Income Distribution", "Income", "% Households at Income", dataset, PlotOrientation.VERTICAL, true, false, false); return incomeDistributionChart; } protected ChartPanel createIncomeSourcePanel(final Currency currency) { final TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection(); for (final IncomeSource incomeSource : ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.incomeSourceModel.getIndexTypes()) { timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.incomeSourceModel.getTimeSeries(incomeSource)); } final JFreeChart chart = ChartFactory.createTimeSeriesChart("Income Source", "Date", "Income Source", timeSeriesCollection, true, true, false); configureChart(chart); return new ChartPanel(chart); } protected ChartPanel createLabourHourSupplyPanel(final Currency currency) { final TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection(); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.labourHourCapacityModel.getTimeSeries()); timeSeriesCollection .addSeries(ApplicationContext.getInstance().getModelRegistry().getNationalEconomyModel(currency) .getPricingBehaviourModel(GoodType.LABOURHOUR).offerModel.getTimeSeries()); timeSeriesCollection .addSeries(ApplicationContext.getInstance().getModelRegistry().getNationalEconomyModel(currency) .getPricingBehaviourModel(GoodType.LABOURHOUR).soldModel.getTimeSeries()); final JFreeChart chart = ChartFactory.createTimeSeriesChart(GoodType.LABOURHOUR.toString() + " Supply", "Date", "Capacity & Output", timeSeriesCollection, true, true, false); configureChart(chart); return new ChartPanel(chart); } protected ChartPanel createLorenzCurvePanel(final Currency currency) { final XYDataset dataset = ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.incomeDistributionModel.getLorenzCurveDataset(); final JFreeChart lorenzCurveChart = ChartFactory.createXYLineChart("Lorenz Curve", "% of Households", "% of Income", dataset, PlotOrientation.VERTICAL, true, true, false); return new ChartPanel(lorenzCurveChart); } protected ChartPanel createMarketDepthPanel(final Currency currency) { final XYDataset dataset = ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).marketDepthModel.getMarketDepthDataset(currency, GoodType.LABOURHOUR); final JFreeChart chart = ChartFactory.createXYStepAreaChart(GoodType.LABOURHOUR + " Market Depth", "Price", "Volume", dataset, PlotOrientation.VERTICAL, true, true, false); return new ChartPanel(chart); } protected ChartPanel createPriceTimeSeriesChartPanel(final Currency currency) { final JFreeChart priceChart = ChartFactory.createCandlestickChart(GoodType.LABOURHOUR + " Prices", "Time", "Price in " + currency.getIso4217Code(), getDefaultHighLowDataset(currency), false); final ChartPanel chartPanel = new ChartPanel(priceChart); chartPanel.setDomainZoomable(true); chartPanel.setPreferredSize(new java.awt.Dimension(800, 400)); return chartPanel; } protected ChartPanel createUtilityFunctionMechanicsPanel(final Currency currency) { final TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection(); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.budgetModel.getTimeSeries()); for (final ConvexFunctionTerminationCause terminationCause : ConvexFunctionTerminationCause.values()) { timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.convexFunctionTerminationCauseModels .get(terminationCause).getTimeSeries()); } // budget is correct here final JFreeChart chart = ChartFactory.createTimeSeriesChart("Utility Function Mechanics", "Date", "Budget Spent", timeSeriesCollection, true, true, false); configureChart(chart); return new ChartPanel(chart); } protected ChartPanel createUtilityPanel(final Currency currency) { final TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection(); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.utilityModel.utilityOutputModel.getTimeSeries()); for (final GoodType inputGoodType : ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.utilityModel.utilityInputModels.keySet()) { timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.utilityModel.utilityInputModels .get(inputGoodType).getTimeSeries()); } final JFreeChart chart = ChartFactory.createTimeSeriesChart("Households Utility", "Date", "Utility", timeSeriesCollection, true, true, false); configureChart(chart); return new ChartPanel(chart); } protected ChartPanel createWageDividendPanel(final Currency currency) { final TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection(); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.wageModel.getTimeSeries()); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.dividendModel.getTimeSeries()); timeSeriesCollection.addSeries(ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).householdsModel.governmentTransfersModel.getTimeSeries()); final JFreeChart chart = ChartFactory.createTimeSeriesChart("Wage, Dividend & Transfers", "Date", "Wage, Dividend & Transfers", timeSeriesCollection, true, true, false); configureChart(chart); return new ChartPanel(chart); } protected DefaultHighLowDataset getDefaultHighLowDataset(final Currency currency) { final PricesModel pricesModel = ApplicationContext.getInstance().getModelRegistry() .getNationalEconomyModel(currency).pricesModel; final Map<GoodType, PriceModel> priceModelsForGoodType = pricesModel.getPriceModelsForGoodTypes(); final PriceModel priceModel = priceModelsForGoodType.get(GoodType.LABOURHOUR); if (priceModel != null) { return new DefaultHighLowDataset("", priceModel.getDate(), priceModel.getHigh(), priceModel.getLow(), priceModel.getOpen(), priceModel.getClose(), priceModel.getVolume()); } return null; } @Override public void notifyListener() { if (isShowing()) { final HouseholdsPanelForCurrency householdPanel = (HouseholdsPanelForCurrency) jTabbedPaneCurrency .getSelectedComponent(); householdPanel.notifyListener(); } } }