Newer
Older
Zemi01 / src / main / java / info / istlab / Zemi01 / numeric / WelchTtest.java
@motoki miura motoki miura on 21 Jan 2023 11 KB welch_t
package info.istlab.Zemi01.numeric;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;

import info.istlab.Zemi01.Launcher;
import info.istlab.Zemi01.miuramath.Ttest;

/**
 * 正規分布、ガウス分布
 */

public class WelchTtest extends JPanel implements MouseListener, MouseMotionListener, KeyListener {

	private static final long serialVersionUID = -919448575666487391L;
	public static JFrame jf;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		jf = new JFrame("正規分布、ガウス分布");
		jf.getContentPane().add(new WelchTtest());
		jf.pack();
		jf.setVisible(true);
		jf.setLocation(Launcher.centerOfScreen(jf.getSize()));

		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		System.out.println("正規分布、ガウス分布 ");
		System.out.println("つかいかた:(1)右クリックで、点を追加 (2)左ドラッグで、点移動 or グラフ移動 (3) 点の上で右クリックすると、点が消えます。");
	}

	Point2D offset;

	ND[] normdist = new ND[2];
	Dimension dim;
	Point2D pointingPmath;
	Point2D pressP;
	static int psize = 10;

	public Dimension getPreferredSize() {
		return dim;
	}

	public WelchTtest() {
		offset = new Point2D.Double(0, 100);

		dim = new Dimension(500, 400);
		addMouseListener(this);
		addMouseMotionListener(this);
		addKeyListener(this);
		this.setFocusable(true);
		this.requestFocusInWindow();

		normdist[0] = new ND(Color.blue, 0, 0);
		normdist[1] = new ND(Color.green, 20, -30);

		setBackground(Color.white);
		setForeground(Color.black);

		updateNormDist();

	}

	public void paint(Graphics g) {
		paintComponent(g);
	}

	public void paintComponent(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.setRenderingHints(rh);

		// g2d.setBackground(Color.white);
		// g2d.setColor(Color.black);
		g2d.clearRect(0, 0, getWidth(), getHeight());

		paintGrid(g2d);

		if (pointingPmath != null) {
			g2d.setColor(Color.red);
			paintPoint(g2d, pointingPmath);
		}

		for (ND nd : normdist) {
			nd.paintND(g2d, this);
		}

		if (p2 < 0.05) {
			g2d.setColor(Color.cyan);
		} else {
			g2d.setColor(Color.YELLOW);
		}
		for (int i = -2; i < 3; i++)
			for (int j = -2; j < 3; j++) {
				// g2d.drawRect(10, 50, 100, 10);
				g2d.drawString("t (" + String.format("%4.2f", df2) + ") = " + String.format("%5.3f", welch_t),
						(int) (-getWidth() / 2 + 30 - offset.getX() + i),
						(int) (-getHeight() / 2 + 320 - offset.getY()) + j);
				g2d.drawString("p = " + String.format("%5.3f", p2),
						(int) (-getWidth() / 2 + 30 - offset.getX() + i),
						(int) (-getHeight() / 2 + 345 - offset.getY()) + j);
			}
		if (p2 < 0.05) {
			g2d.setColor(Color.blue);
		} else {
			g2d.setColor(Color.red);
		}
		// g2d.drawRect(10, 50, 100, 10);
		g2d.drawString("t (" + String.format("%4.2f", df2) + ") = " + String.format("%5.3f", welch_t),
				(int) (-getWidth() / 2 + 30 - offset.getX()),
				(int) (-getHeight() / 2 + 320 - offset.getY()));
		g2d.drawString("p = " + String.format("%5.3f", p2),
				(int) (-getWidth() / 2 + 30 - offset.getX()),
				(int) (-getHeight() / 2 + 345 - offset.getY()));
	}

	private void updateNormDist() {
		for (ND nd : normdist) {
			nd.updateNormDist();
		}
		updateTdist();
	}

	double welch_t;
	double df2;
	double p2;

	private void updateTdist() {
		welch_t = Ttest.welch_t(normdist[1].data(), normdist[0].data());
		df2 = Ttest.welch_degree_of_freedom(normdist[1].data(), normdist[0].data());
		p2 = Ttest.tdist(welch_t, df2, 2);
		// System.out.println("p2 = "+p2);
	}

	public void paintPoint(Graphics2D g2d, Point2D p) {
		g2d.setColor(Color.red);
		g2d.fillOval((int) (p.getX() - WelchTtest.psize / 2),
				(int) (-(p.getY() + WelchTtest.psize / 2)), WelchTtest.psize, WelchTtest.psize);
		// g2d.drawString(String.valueOf(num), (int)p.getX()+10, (int)p.getY());
	}

	public void paintGrid(Graphics2D g2d) {
		g2d.setColor(new Color(230, 230, 230));

		g2d.translate(getWidth() / 2 + offset.getX(), getHeight() / 2 + offset.getY());
		// System.out.println(g2d.getTransform().getTranslateX()+"
		// "+g2d.getTransform().getTranslateY());

		for (int i = 0; i < getWidth(); i += 20) {
			g2d.drawLine(i, -getHeight(), i, getHeight());
			g2d.drawLine(-i, -getHeight(), -i, getHeight());
		}
		for (int i = 0; i < getHeight(); i += 20) {
			g2d.drawLine(-getWidth(), i, getWidth(), i);
			g2d.drawLine(-getWidth(), -i, getWidth(), -i);
		}
		g2d.setColor(Color.black);
		g2d.drawLine(0, getHeight() * 3, 0, -getHeight() * 3);
		g2d.drawLine(-getWidth() * 3, 0, getWidth() * 3, 0);

		// g2d.translate(-(getWidth()/2+offset.getX()), -(getHeight()/2+offset.getY()));
	}

	public Point2D scr2math(Point2D p) {
		double x = p.getX();
		double y = p.getY();
		x = x - offset.getX() - getWidth() / 2;
		y = y - offset.getY() - getHeight() / 2;
		y = -y;
		// System.out.println("scr2math "+x+", "+y);
		return new Point2D.Double(x, y);
	}

	public Point2D math2scr(Point2D p) {
		return new Point2D.Double(p.getX(), -p.getY());
	}

	public void mouseClicked(MouseEvent e) {
		if (e.getButton() == 3) {
			Point2D pointing = findPointing(e.getPoint());
			if (pointing == null)
				normdist[0].points.add(scr2math(e.getPoint()));
			else {
				if (normdist[0].points.size() > 2)
					normdist[0].points.remove(pointing);
			}
			updateNormDist();
			repaint();
		}
	}

	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public Point2D findPointing(Point2D mp) {
		// Point2D nearest = null;
		Point2D mPmath = scr2math(mp);
		Point2D nP = null;
		for (ND n : normdist) {
			nP = n.nearestPoint(mPmath);
			if (nP != null)
				break;
		}
		return nP;
		// pointingPmath = nP;

		// for (Point2D p : points) {
		// if (mPmath.distance(p) < 8) {
		// nearest = p;
		// }
		// }
		// return nearest;
	}

	public void mousePressed(MouseEvent e) {
		mouseMoved(e);
	}

	public void mouseReleased(MouseEvent e) {
		pointingPmath = null;
		repaint();
	}

	public void mouseDragged(MouseEvent e) {
		if (pointingPmath != null) {
			pointingPmath.setLocation(scr2math(e.getPoint()));
			updateNormDist();
			repaint();
		} else {
			// e.translatePoint((int)offset.getX(), (int)offset.getY());
			offset.setLocation(offset.getX() + (e.getPoint().getX() - pressP.getX()),
					offset.getY() + (e.getPoint().getY() - pressP.getY()));
			pressP = e.getPoint();
			updateNormDist();
			repaint();
		}
	}

	public void mouseMoved(MouseEvent e) {
		scr2math(e.getPoint());
		pressP = e.getPoint();
		Point2D pressPmath = scr2math(pressP);
		Point2D nP = null;
		for (ND n : normdist) {
			nP = n.nearestPoint(pressPmath);
			if (nP != null)
				break;
		}
		pointingPmath = nP;
		updateNormDist();
		repaint();
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyPressed(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
			System.out.println(e.getKeyCode());

			normdist[0] = new ND(Color.blue, 0, 0);
			normdist[1] = new ND(Color.green, 20, -30);
			updateNormDist();
			repaint();
		}

	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub

	}

}

class ND {
	ArrayList<Point2D> points;
	Color color;
	int offsetx = 0;
	int offsety = 0;

	public ND(Color c, int _offsetx, int _offsety) {
		color = c;
		offsetx = _offsetx;
		offsety = _offsety;
		points = new ArrayList<Point2D>();

		Random rand = new Random();
		for (int i = 0; i < 7; i++) {
			int randx = rand.nextInt(-40 + offsetx, 40 + offsetx);
			int randy = rand.nextInt(-10 + offsety, offsety);
			points.add(new Point2D.Double(randx, randy));
		}
		updateNormDist();
	}

	double[] ddat;

	public double[] data() {
		return ddat;
	}

	// 平均と分散
	double xavg = 0;
	double xvarp = 1;

	/**
	 * ガウス関数、ただし、μとσ^2は、xavg, xvarp から計算する
	 * 
	 * @param x
	 * @return
	 */
	public double gauss_function(double x) {
		double d1 = 1.0 / Math.sqrt(2 * Math.PI * xvarp);
		double d2 = Math.exp(-Math.pow(x - xavg, 2) / (2 * xvarp));
		double ret = d1 * d2 * 10000;
		// System.out.println(ret);
		return ret;
	}

	/**
	 * 点のx座標から、ガウス関数のパラメータ μとσ^2は、xavg, xvarp を更新する
	 */
	public void updateNormDist() {
		ddat = new double[points.size()];
		int i = 0;
		for (Point2D p : points) {
			ddat[i] = p.getX();
			i++;
		}
		// 平均値を更新する
		xavg = Ttest.avg(ddat);
		// 標準偏差を更新する
		xvarp = Ttest.varp(ddat);
		// System.out.println("μ " + xavg + " σ^2 " + xvarp);
	}

	public void paintND(Graphics2D g2d, WelchTtest wtest) {

		g2d.setColor(Color.black);
		for (Point2D p : points) {
			paintPoint(g2d, p);
		}

		Point2D prep = null;
		g2d.setColor(color);
		for (double x = -wtest.getWidth() / 2 - wtest.offset.getX(); x < wtest.getWidth() / 2
				- wtest.offset.getX(); x += 1.0) {
			Point2D p1 = wtest.math2scr(new Point2D.Double(x, gauss_function(x)));
			if (prep == null)
				prep = p1;
			g2d.drawLine((int) p1.getX(), (int) p1.getY(), (int) prep.getX(), (int) prep.getY());
			prep = p1;
		}
		if (offsetx > 10) {
			g2d.drawString("μ = " + String.format("%6.4f", xavg), (int) (wtest.getWidth() / 5 - wtest.offset.getX()),
					(int) (-wtest.getHeight() / 2 + 20 - wtest.offset.getY()));
			g2d.drawString("σ = " + String.format("%6.4f", Math.sqrt(xvarp)),
					(int) (wtest.getWidth() / 5 - wtest.offset.getX()),
					(int) (-wtest.getHeight() / 2 + 38 - wtest.offset.getY()));
			g2d.drawString("σ^2 = " + String.format("%6.4f", xvarp), (int) (wtest.getWidth() / 5 - wtest.offset.getX()),
					(int) (-wtest.getHeight() / 2 + 56 - wtest.offset.getY()));

		} else {
			g2d.drawString("μ = " + String.format("%6.4f", xavg), (int) (-wtest.getWidth() / 2 + 10 - wtest.offset.getX()),
					(int) (-wtest.getHeight() / 2 + 20 - wtest.offset.getY()));
			g2d.drawString("σ = " + String.format("%6.4f", Math.sqrt(xvarp)),
					(int) (-wtest.getWidth() / 2 + 10 - wtest.offset.getX()),
					(int) (-wtest.getHeight() / 2 + 38 - wtest.offset.getY()));
			g2d.drawString("σ^2 = " + String.format("%6.4f", xvarp), (int) (-wtest.getWidth() / 2 + 10 - wtest.offset.getX()),
					(int) (-wtest.getHeight() / 2 + 56 - wtest.offset.getY()));
		}

	}

	public void paintPoint(Graphics2D g2d, Point2D p) {
		g2d.fillOval((int) (p.getX() - WelchTtest.psize / 2),
				(int) (-(p.getY() + WelchTtest.psize / 2)), WelchTtest.psize, WelchTtest.psize);
		// g2d.drawString(String.valueOf(num), (int)p.getX()+10, (int)p.getY());
	}

	public Point2D nearestPoint(Point2D pressPmath) {
		Point2D nearest = null;
		for (Point2D p : points) {
			if (pressPmath.distance(p) < 8) {
				nearest = p;
			}
		}
		return nearest;
	}

}