diff --git a/example/Main.hs b/example/Main.hs
--- a/example/Main.hs
+++ b/example/Main.hs
@@ -40,6 +40,6 @@
 
 outputResult :: TSNEOutput3D -> IO ()
 outputResult s = do
-    putStrLn $ "iteration: " ++ (show.tsneIteration) s
-    putStrLn $ "cost: " ++ (show.tsneCost) s
+    putStrLn $ "iteration: " ++ (show.tsneIteration3D) s
+    putStrLn $ "cost: " ++ (show.tsneCost3D) s
 
diff --git a/src/Data/Algorithm/TSNE.hs b/src/Data/Algorithm/TSNE.hs
--- a/src/Data/Algorithm/TSNE.hs
+++ b/src/Data/Algorithm/TSNE.hs
@@ -1,8 +1,11 @@
 module Data.Algorithm.TSNE ( 
+        TSNEOptions(..),
         tsne3D,
         forTsne3D,
-        TSNEOptions(..),
-        TSNEOutput3D(..)
+        TSNEOutput3D(..),
+        tsne2D,
+        forTsne2D,
+        TSNEOutput2D(..)
     ) where
 
 import Pipes
@@ -14,8 +17,8 @@
 -- | Generates an infinite stream of 3D tSNE iterations.
 tsne3D :: TSNEOptions -> TSNEInput -> Producer TSNEOutput3D IO ()
 tsne3D opts input = do
-    st <- liftIO $ initState $ length input
-    runTSNE opts input ps st
+    st <- liftIO $ initState3D $ length input
+    runTSNE3D opts input ps st
         where ps = neighbourProbabilities opts input
 
 -- | Executes an IO action for each iteration of the 3D tSNE algorithm.
@@ -24,3 +27,15 @@
     runEffect $ for (tsne3D opts input) $ \o -> do
         lift $ action o    
 
+-- | Generates an infinite stream of 2D tSNE iterations.
+tsne2D :: TSNEOptions -> TSNEInput -> Producer TSNEOutput2D IO ()
+tsne2D opts input = do
+    st <- liftIO $ initState2D $ length input
+    runTSNE2D opts input ps st
+        where ps = neighbourProbabilities opts input
+
+-- | Executes an IO action for each iteration of the 2D tSNE algorithm.
+forTsne2D :: (TSNEOutput2D -> IO ()) -> TSNEOptions -> TSNEInput -> IO ()
+forTsne2D action opts input = do
+    runEffect $ for (tsne2D opts input) $ \o -> do
+        lift $ action o    
diff --git a/src/Data/Algorithm/TSNE/Internals.hs b/src/Data/Algorithm/TSNE/Internals.hs
--- a/src/Data/Algorithm/TSNE/Internals.hs
+++ b/src/Data/Algorithm/TSNE/Internals.hs
@@ -35,13 +35,20 @@
             n = inputSize i
             s = stSolution st    
 
-initState :: Int -> IO TSNEState
-initState n = do
+initState3D :: Int -> IO TSNEState
+initState3D n = do
     s <- initSolution3D n
     return $ TSNEState 0 s (rr 1) (rr 0)
         where
             rr = repeat.repeat
 
+initState2D :: Int -> IO TSNEState
+initState2D n = do
+    s <- initSolution2D n
+    return $ TSNEState 0 s (rr 1) (rr 0)
+        where
+            rr = repeat.repeat
+
 initSolution3D :: Int -> IO [[Double]]
 initSolution3D n = do
     let ns = normalsIO' (0, 1e-4)
@@ -50,12 +57,25 @@
     zs <- ns
     return $ take n <$> [xs,ys,zs]
 
-runTSNE :: TSNEOptions -> TSNEInput -> [[Probability]] -> TSNEState -> Producer TSNEOutput3D IO ()
-runTSNE opts vs ps st = do
+initSolution2D :: Int -> IO [[Double]]
+initSolution2D n = do
+    let ns = normalsIO' (0, 1e-4)
+    xs <- ns
+    ys <- ns
+    return $ take n <$> [xs,ys]
+
+runTSNE3D :: TSNEOptions -> TSNEInput -> [[Probability]] -> TSNEState -> Producer TSNEOutput3D IO ()
+runTSNE3D opts vs ps st = do
+    yield $ output3D ps st
     let st' = force $ stepTSNE opts vs ps st
-    yield $ output3D ps st'
-    runTSNE opts vs ps st'
+    runTSNE3D opts vs ps st'
 
+runTSNE2D :: TSNEOptions -> TSNEInput -> [[Probability]] -> TSNEState -> Producer TSNEOutput2D IO ()
+runTSNE2D opts vs ps st = do
+    yield $ output2D ps st
+    let st' = force $ stepTSNE opts vs ps st
+    runTSNE2D opts vs ps st'
+
 stepTSNE :: TSNEOptions -> TSNEInput -> [[Probability]] -> TSNEState -> TSNEState
 stepTSNE opts vs ps st = TSNEState i' s'' g' d'
     where
@@ -109,6 +129,16 @@
     where
         i = stIteration st
         s = (solution3D . stSolution) st
+        c = cost pss st
+
+solution2D :: [[Double]] -> [Position2D]
+solution2D (xs:ys:_) = zip xs ys
+
+output2D :: [[Double]] -> TSNEState -> TSNEOutput2D
+output2D pss st = TSNEOutput2D i s c
+    where
+        i = stIteration st
+        s = (solution2D . stSolution) st
         c = cost pss st
 
 cost :: [[Double]] -> TSNEState -> Double
diff --git a/src/Data/Algorithm/TSNE/Types.hs b/src/Data/Algorithm/TSNE/Types.hs
--- a/src/Data/Algorithm/TSNE/Types.hs
+++ b/src/Data/Algorithm/TSNE/Types.hs
@@ -18,9 +18,17 @@
 type Position3D = (Double,Double,Double)
 
 data TSNEOutput3D = TSNEOutput3D {
-    tsneIteration :: Int,
+    tsneIteration3D :: Int,
     tsneSolution3D :: [Position3D],
-    tsneCost :: Double
+    tsneCost3D :: Double
+} deriving (Show, Eq)
+
+type Position2D = (Double,Double)
+
+data TSNEOutput2D = TSNEOutput2D {
+    tsneIteration2D :: Int,
+    tsneSolution2D :: [Position2D],
+    tsneCost2D :: Double
 } deriving (Show, Eq)
 
 instance Default TSNEOptions where
diff --git a/tsne.cabal b/tsne.cabal
--- a/tsne.cabal
+++ b/tsne.cabal
@@ -1,5 +1,5 @@
 name:                tsne
-version:             1.0.0.1
+version:             1.1.0
 synopsis:            t-SNE
 description:         Pure Haskell implementation of the t-SNE dimension reduction algorithm.
 homepage:            https://bitbucket.org/robagar/haskell-tsne
