View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.samples;
23  
24  import java.awt.BasicStroke;
25  import java.awt.Color;
26  import java.awt.Component;
27  import java.awt.Font;
28  import java.awt.GridBagConstraints;
29  import java.awt.GridBagLayout;
30  import java.awt.Insets;
31  import java.util.ArrayList;
32  import java.util.List;
33  
34  import javax.swing.BorderFactory;
35  import javax.swing.BoxLayout;
36  import javax.swing.JComponent;
37  import javax.swing.JLabel;
38  import javax.swing.JPanel;
39  import javax.swing.JScrollPane;
40  
41  import org.hipparchus.distribution.IntegerDistribution;
42  import org.hipparchus.distribution.discrete.BinomialDistribution;
43  import org.hipparchus.distribution.discrete.GeometricDistribution;
44  import org.hipparchus.distribution.discrete.HypergeometricDistribution;
45  import org.hipparchus.distribution.discrete.PascalDistribution;
46  import org.hipparchus.distribution.discrete.PoissonDistribution;
47  import org.hipparchus.distribution.discrete.UniformIntegerDistribution;
48  import org.hipparchus.distribution.discrete.ZipfDistribution;
49  import org.hipparchus.exception.MathRuntimeException;
50  import org.hipparchus.samples.ExampleUtils.ExampleFrame;
51  
52  import com.xeiam.xchart.Chart;
53  import com.xeiam.xchart.ChartBuilder;
54  import com.xeiam.xchart.Series;
55  import com.xeiam.xchart.SeriesMarker;
56  import com.xeiam.xchart.StyleManager.ChartType;
57  import com.xeiam.xchart.StyleManager.LegendPosition;
58  import com.xeiam.xchart.XChartPanel;
59  
60  /**
61   * Displays pdf/cdf for integer distributions.
62   */
63  //CHECKSTYLE: stop HideUtilityClassConstructor
64  public class IntegerDistributionComparison {
65  
66      /** Arial font. */
67      private static final String ARIAL = "Arial";
68  
69      /** p=0.2. */
70      private static final String P02 = "p=0.2";
71  
72      /** p=0.3. */
73      private static final String P03 = "p=0.3";
74  
75      /** p=0.5. */
76      private static final String P05 = "p=0.5";
77  
78      /** p=0.7. */
79      private static final String P07 = "p=0.7";
80  
81      /** p=0.75. */
82      private static final String P075 = "p=0.75";
83  
84      /** p=0.8. */
85      private static final String P08 = "p=0.8";
86  
87      /** Empty constructor.
88       * <p>
89       * This constructor is not strictly necessary, but it prevents spurious
90       * javadoc warnings with JDK 18 and later.
91       * </p>
92       * @since 3.0
93       */
94      public IntegerDistributionComparison() { // NOPMD - unnecessary constructor added intentionally to make javadoc happy
95          // nothing to do
96      }
97  
98      /** Add a PDF series.
99       * @param chart chart to which series must be added
100      * @param distribution integer distribution to draw
101      * @param desc description
102      * @param lowerBound lower bound
103      * @param upperBound upper bound
104      */
105     public static void addPDFSeries(Chart chart, IntegerDistribution distribution, String desc, int lowerBound, int upperBound) {
106         // generates Log data
107         List<Number> xData = new ArrayList<Number>();
108         List<Number> yData = new ArrayList<Number>();
109         for (int x = lowerBound; x <= upperBound; x += 1) {
110             try {
111                 double probability = distribution.probability(x);
112                 if (! Double.isInfinite(probability) && ! Double.isNaN(probability)) {
113                     xData.add(x);
114                     yData.add(probability);
115                 }
116             } catch (MathRuntimeException e) {
117                 // ignore
118                 // some distributions may reject certain values depending on the parameter settings
119             }
120         }
121 
122         Series series = chart.addSeries(desc, xData, yData);
123         series.setMarker(SeriesMarker.NONE);
124         series.setLineStyle(new BasicStroke(1.2f));
125     }
126 
127     /** Add a CDF series.
128      * @param chart chart to which series must be added
129      * @param distribution integer distribution to draw
130      * @param desc description
131      * @param lowerBound lower bound
132      * @param upperBound upper bound
133      */
134     public static void addCDFSeries(Chart chart, IntegerDistribution distribution, String desc,
135                                     int lowerBound, int upperBound) {
136         // generates Log data
137         List<Number> xData = new ArrayList<Number>();
138         List<Number> yData = new ArrayList<Number>();
139         for (int x = lowerBound; x <= upperBound; x += 1) {
140           double density = distribution.cumulativeProbability(x);
141           if (! Double.isInfinite(density) && ! Double.isNaN(density)) {
142               xData.add(x);
143               yData.add(density);
144           }
145         }
146 
147         Series series = chart.addSeries(desc, xData, yData);
148         series.setMarker(SeriesMarker.NONE);
149         series.setLineStyle(new BasicStroke(1.2f));
150     }
151 
152     /** Create a chart.
153      * @param title chart title
154      * @param minX minimum abscissa
155      * @param maxX maximum abscissa
156      * @param position position of the legend
157      * @return created chart
158      */
159     public static Chart createChart(String title, int minX, int maxX, LegendPosition position) {
160         Chart chart = new ChartBuilder().width(235).height(200).build();
161 
162         // Customize Chart
163         chart.setChartTitle(title);
164         chart.getStyleManager().setChartTitleVisible(true);
165         chart.getStyleManager().setChartTitleFont(new Font(ARIAL, Font.PLAIN, 10));
166         chart.getStyleManager().setLegendPosition(position);
167         chart.getStyleManager().setLegendVisible(true);
168         chart.getStyleManager().setLegendFont(new Font(ARIAL, Font.PLAIN, 10));
169         chart.getStyleManager().setLegendPadding(6);
170         chart.getStyleManager().setLegendSeriesLineLength(6);
171         chart.getStyleManager().setAxisTickLabelsFont(new Font(ARIAL, Font.PLAIN, 9));
172 
173         chart.getStyleManager().setXAxisMin(minX);
174         chart.getStyleManager().setXAxisMax(maxX);
175         chart.getStyleManager().setChartBackgroundColor(Color.white);
176         chart.getStyleManager().setChartPadding(4);
177 
178         chart.getStyleManager().setChartType(ChartType.Line);
179         return chart;
180     }
181 
182     /** Create a component.
183      * @param distributionName name of the distribution
184      * @param minX minimum abscissa
185      * @param maxX maximum abscissa
186      * @param seriesText descriptions of the series
187      * @param series series
188      * @return create component
189      */
190     public static JComponent createComponent(String distributionName, int minX, int maxX, String[] seriesText,
191                                              IntegerDistribution... series) {
192         JComponent container = new JPanel();
193         container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
194 
195         container.add(new JLabel(distributionName));
196 
197         Chart chart = createChart("PDF", minX, maxX, LegendPosition.InsideNE);
198         int i = 0;
199         for (IntegerDistribution d : series) {
200             addPDFSeries(chart, d, seriesText[i++], minX, maxX);
201         }
202         container.add(new XChartPanel(chart));
203 
204         chart = createChart("CDF", minX, maxX, LegendPosition.InsideSE);
205         i = 0;
206         for (IntegerDistribution d : series) {
207             addCDFSeries(chart, d, seriesText[i++], minX, maxX);
208         }
209         container.add(new XChartPanel(chart));
210 
211         container.setBorder(BorderFactory.createLineBorder(Color.black, 1));
212         return container;
213     }
214 
215     /** Main frame for displaying distributions. */
216     @SuppressWarnings("serial")
217     public static class Display extends ExampleFrame {
218 
219         /** Container. */
220         private JComponent container;
221 
222         /** Simple constructor.
223          */
224         public Display() {
225             setTitle("Hipparchus: Integer distributions overview");
226             setSize(1320, 920);
227 
228             container = new JPanel();
229             container.setLayout(new GridBagLayout());
230 
231             GridBagConstraints c = new GridBagConstraints();
232             c.fill = GridBagConstraints.VERTICAL;
233             c.gridx = 0;
234             c.gridy = 0;
235             c.insets = new Insets(2, 2, 2, 2);
236 
237             JComponent comp = null;
238 
239             comp = createComponent("Binomial", 0, 40,
240                                    new String[] { "p=0.5,n=20", "p=0.7,n=20", "p=0.5,n=40" },
241                                    new BinomialDistribution(20, 0.5),
242                                    new BinomialDistribution(20, 0.7),
243                                    new BinomialDistribution(40, 0.5));
244             container.add(comp, c);
245 
246             c.gridx++;
247             comp = createComponent("Geometric", 0, 10,
248                                    new String[] { P02, P05, P08 },
249                                    new GeometricDistribution(0.2),
250                                    new GeometricDistribution(0.5),
251                                    new GeometricDistribution(0.8));
252             container.add(comp, c);
253 
254             c.gridx++;
255             comp = createComponent("Hypergeometric", 0, 10,
256                                    new String[] { P03, P05, P075 },
257                                    new HypergeometricDistribution(100, 6, 20),
258                                    new HypergeometricDistribution(100, 10, 20),
259                                    new HypergeometricDistribution(100, 15, 20));
260             container.add(comp, c);
261 
262             c.gridx++;
263             comp = createComponent("Pascal", 0, 50,
264                                    new String[] { P03, P05, P07 },
265                                    new PascalDistribution(10, 0.3),
266                                    new PascalDistribution(10, 0.5),
267                                    new PascalDistribution(10, 0.7));
268             container.add(comp, c);
269 
270             c.gridy++;
271             c.gridx = 0;
272             comp = createComponent("Poisson", 0, 20,
273                                    new String[] { "λ=1", "λ=4", "λ=10" },
274                                    new PoissonDistribution(1),
275                                    new PoissonDistribution(4),
276                                    new PoissonDistribution(10));
277             container.add(comp, c);
278 
279             c.gridx++;
280             comp = createComponent("Uniform", 0, 30,
281                                    new String[] { "l=1,u=10", "l=5,u=20", "l=1,u=25" },
282                                    new UniformIntegerDistribution(1, 10),
283                                    new UniformIntegerDistribution(5, 20),
284                                    new UniformIntegerDistribution(1, 25));
285             container.add(comp, c);
286 
287             c.gridx++;
288             comp = createComponent("Zipf", 0, 15,
289                                    new String[] { "n=10,e=0.5", "n=10,e=1", "n=10,e=2", "n=10,e=5" },
290                                    new ZipfDistribution(10, 0.5),
291                                    new ZipfDistribution(10, 1),
292                                    new ZipfDistribution(10, 2),
293                                    new ZipfDistribution(10, 5));
294             container.add(comp, c);
295 
296             JScrollPane scrollPane = new JScrollPane(container);
297             add(scrollPane);
298 
299         }
300 
301         /** {@inheritDoc} */
302         @Override
303         public Component getMainPanel() {
304             return container;
305         }
306 
307     }
308 
309     /** Program entry point.
310      * @param args program arguments (unused here)
311      */
312     public static void main(String[] args) {
313         ExampleUtils.showExampleFrame(new Display());
314     }
315 
316 }