Commits

Sergey Astanin committed 6fcfb9a

Make it actually usable. Export draw and default values.

* export data type constructor arguments (for documentation)
* remove IO-related stuff except for printPlot
* hide TextPlot as an implementation detail
* provide default values (empty*) with reasonable widthxheight

Comments (0)

Files changed (2)

 --
 
 module TextPlot
-(TextPlot
-,Plot(Plot)
-,PlotParam(PlotParam)
-,PlotPolar(PlotPolar)
+(
+-- * Types
+Plot(..)
+,emptyPlot
+,PlotParam(..)
+,emptyParamPlot
+,PlotPolar(..)
+,emptyPolarPlot
+,Draw()
+-- * Plot functions
 ,insertF
 ,insertParam
 ,insertPolar
-,Draw
+-- * Output
 ,printPlot
-,export
-,view
+,drawPlot
 ) where
 import Data.List
 import System.IO
 
 type TextPlot = [[Char]]
 
+-- some reasonable default values
+def_width = 60
+def_height = 21
+def_xrange = (0.0, 1.0)
+def_yrange = (0.0, 1.0)
 
 -- | Specifies a set of functions to be graphed in Cartesian coordinates
 data Plot = Plot {xminOf :: Double, -- ^ left x-bound of the graph
-				  xmaxOf :: Double, -- ^ right x-bound of the graph
-				  xDensityOf :: Int, -- ^ number of characters along the x-axis
-				  yminOf :: Double,  -- ^ left y-bound of the graph
-				  ymaxOf :: Double, --  right y-bound of the graph
-				  yDensityOf :: Int, -- ^ number of characters along the y-axis
-				  functionsOf :: [(Double -> Double)] -- ^ a list of functions of the form y = f(x)
-				  }
-				  
+                                  xmaxOf :: Double, -- ^ right x-bound of the graph
+                                  xDensityOf :: Int, -- ^ number of characters along the x-axis
+                                  yminOf :: Double,  -- ^ left y-bound of the graph
+                                  ymaxOf :: Double, --  right y-bound of the graph
+                                  yDensityOf :: Int, -- ^ number of characters along the y-axis
+                                  functionsOf :: [(Double -> Double)] -- ^ a list of functions of the form y = f(x)
+                                  }
+
+-- | A default empty 'Plot'
+emptyPlot :: Plot
+emptyPlot = Plot (fst def_xrange) (snd def_xrange) def_width
+                 (fst def_yrange) (snd def_yrange) def_height []
+
 instance Show Plot where
-	show plot = "Bounds: " ++ xmin ++ " < x < " ++ xmax ++ "\n" ++ 
-				"        " ++ ymin ++ " < y < " ++ ymax ++ "\n" ++ 
-				"X-axis Precision: " ++ xden ++ "\n" ++
-				"Y-axis Precision: " ++ yden ++ "\n" ++
-				"Functions Plotted: " ++ lenf
-				where xmin = show . xminOf $ plot
-				      xmax = show . xmaxOf $ plot
-				      xden = show . xDensityOf $ plot
-				      ymin = show . yminOf $ plot
-				      ymax = show . ymaxOf $ plot
-				      yden = show . yDensityOf $ plot
-				      lenf = show . length . functionsOf $ plot
+        show plot = "Bounds: " ++ xmin ++ " < x < " ++ xmax ++ "\n" ++
+                                "        " ++ ymin ++ " < y < " ++ ymax ++ "\n" ++
+                                "X-axis Precision: " ++ xden ++ "\n" ++
+                                "Y-axis Precision: " ++ yden ++ "\n" ++
+                                "Functions Plotted: " ++ lenf
+                                where xmin = show . xminOf $ plot
+                                      xmax = show . xmaxOf $ plot
+                                      xden = show . xDensityOf $ plot
+                                      ymin = show . yminOf $ plot
+                                      ymax = show . ymaxOf $ plot
+                                      yden = show . yDensityOf $ plot
+                                      lenf = show . length . functionsOf $ plot
 
 
 -- | Specifies a set of parametric functions to be graphed in Cartesian coordinates
 data PlotParam = PlotParam {pxminOf :: Double, -- ^ left x-bound of the graph
-							pxmaxOf :: Double, -- ^ right x-bound of the graph
-							pxDensityOf :: Int, -- ^ number of characters along the x-axis
-							pyminOf :: Double, -- ^ left y-bound of the graph
-							pymaxOf :: Double, --  right y-bound of the graph
-							pyDensityOf :: Int, -- ^ number of characters along the y-axis
-							pfunctionsOf :: [(Double -> (Double,Double),Double,Double,Int)] 
-							} 
+                                                        pxmaxOf :: Double, -- ^ right x-bound of the graph
+                                                        pxDensityOf :: Int, -- ^ number of characters along the x-axis
+                                                        pyminOf :: Double, -- ^ left y-bound of the graph
+                                                        pymaxOf :: Double, --  right y-bound of the graph
+                                                        pyDensityOf :: Int, -- ^ number of characters along the y-axis
+                                                        pfunctionsOf :: [(Double -> (Double,Double),Double,Double,Int)]
+                                                        }
+
+-- | A default empty 'PlotParam'
+emptyParamPlot :: PlotParam
+emptyParamPlot = PlotParam (fst def_xrange) (snd def_xrange) def_width
+                           (fst def_yrange) (snd def_yrange) def_height []
+
 
 instance Show PlotParam where
-	show plot = "Bounds: " ++ xmin ++ " < x < " ++ xmax ++ "\n" ++ 
-				"        " ++ ymin ++ " < y < " ++ ymax ++ "\n" ++ 
-				"X-axis Precision: " ++ xden ++ "\n" ++
-				"Y-axis Precision: " ++ yden ++ "\n" ++
-				"Functions Plotted: " ++ lenf
-				where xmin = show . pxminOf $ plot
-				      xmax = show . pxmaxOf $ plot
-				      xden = show . pxDensityOf $ plot
-				      ymin = show . pyminOf $ plot
-				      ymax = show . pymaxOf $ plot
-				      yden = show . pyDensityOf $ plot
-				      lenf = show . length . pfunctionsOf $ plot
-	
+        show plot = "Bounds: " ++ xmin ++ " < x < " ++ xmax ++ "\n" ++
+                                "        " ++ ymin ++ " < y < " ++ ymax ++ "\n" ++
+                                "X-axis Precision: " ++ xden ++ "\n" ++
+                                "Y-axis Precision: " ++ yden ++ "\n" ++
+                                "Functions Plotted: " ++ lenf
+                                where xmin = show . pxminOf $ plot
+                                      xmax = show . pxmaxOf $ plot
+                                      xden = show . pxDensityOf $ plot
+                                      ymin = show . pyminOf $ plot
+                                      ymax = show . pymaxOf $ plot
+                                      yden = show . pyDensityOf $ plot
+                                      lenf = show . length . pfunctionsOf $ plot
+
 
 -- | Specifies a set of functions to be graphed in polar coordinates
 data PlotPolar = PlotPolar {plxminOf :: Double, -- ^ left x-bound of the graph
-							plxmaxOf :: Double, -- ^ right x-bound of the graph
-							plxDensityOf :: Int, -- ^ number of characters along the x-axis
-							plyminOf :: Double, -- ^ left y-bound of the graph
-							plymaxOf :: Double, --  right y-bound of the graph
-							plyDensityOf :: Int, -- ^ number of characters along the y-axis
-							plfunctionsOf :: [(Double -> Double,Double,Double,Int)] -- ^ a list of functions of the form r = f(theta)
-							} 
+                                                        plxmaxOf :: Double, -- ^ right x-bound of the graph
+                                                        plxDensityOf :: Int, -- ^ number of characters along the x-axis
+                                                        plyminOf :: Double, -- ^ left y-bound of the graph
+                                                        plymaxOf :: Double, --  right y-bound of the graph
+                                                        plyDensityOf :: Int, -- ^ number of characters along the y-axis
+                                                        plfunctionsOf :: [(Double -> Double,Double,Double,Int)] -- ^ a list of functions of the form r = f(theta)
+                                                        }
+
+-- | A default empty 'PlotPolar'
+emptyPolarPlot :: PlotPolar
+emptyPolarPlot = PlotPolar (fst def_xrange) (snd def_xrange) def_width
+                           (fst def_yrange) (snd def_yrange) def_height []
 
 instance Show PlotPolar where
-	show plot = "Bounds: " ++ xmin ++ " < x < " ++ xmax ++ "\n" ++ 
-				"        " ++ ymin ++ " < y < " ++ ymax ++ "\n" ++ 
-				"X-axis Precision: " ++ xden ++ "\n" ++
-				"Y-axis Precision: " ++ yden ++ "\n" ++
-				"Functions Plotted: " ++ lenf
-				where xmin = show . plxminOf $ plot
-				      xmax = show . plxmaxOf $ plot
-				      xden = show . plxDensityOf $ plot
-				      ymin = show . plyminOf $ plot
-				      ymax = show . plymaxOf $ plot
-				      yden = show . plyDensityOf $ plot
-				      lenf = show . length . plfunctionsOf $ plot
+        show plot = "Bounds: " ++ xmin ++ " < x < " ++ xmax ++ "\n" ++
+                                "        " ++ ymin ++ " < y < " ++ ymax ++ "\n" ++
+                                "X-axis Precision: " ++ xden ++ "\n" ++
+                                "Y-axis Precision: " ++ yden ++ "\n" ++
+                                "Functions Plotted: " ++ lenf
+                                where xmin = show . plxminOf $ plot
+                                      xmax = show . plxmaxOf $ plot
+                                      xden = show . plxDensityOf $ plot
+                                      ymin = show . plyminOf $ plot
+                                      ymax = show . plymaxOf $ plot
+                                      yden = show . plyDensityOf $ plot
+                                      lenf = show . length . plfunctionsOf $ plot
 
 -- | adds a function to a @Plot@
 insertF :: (Double -> Double) -> Plot -> Plot
 insertPolar :: ((Double -> Double),Double,Double,Int) -> PlotPolar -> PlotPolar
 insertPolar f plot = plot {plfunctionsOf = f:(plfunctionsOf plot)}
 
--- | 
-class Draw a where 
-	draw :: a -> TextPlot
+-- | Anything that can be plotted.
+class Draw a where
+        draw :: a -> TextPlot
 
 instance Draw Plot where
-	draw plot = transpose . subDraw $ (xminOf plot) 
-		where row = replicate (yDensityOf plot) ' '
-		      xmax = xmaxOf plot
-		      xIncr = (xmaxOf plot - xminOf plot) / (fromIntegral (xDensityOf plot) - 1)
-		      yIncr = (ymaxOf plot - yminOf plot) / (fromIntegral (yDensityOf plot) - 1)
-		      fs = [ (\x -> round $ (f x - yminOf plot) / yIncr) | f <- functionsOf plot]
-		      subDraw x
-		      	| x > xmax = []
-		      	| otherwise = reverse (replaces (map (\f -> f x) fs) '*' row) : subDraw (x + xIncr)
+        draw plot = transpose . subDraw $ (xminOf plot)
+                where row = replicate (yDensityOf plot) ' '
+                      xmax = xmaxOf plot
+                      xIncr = (xmaxOf plot - xminOf plot) / (fromIntegral (xDensityOf plot) - 1)
+                      yIncr = (ymaxOf plot - yminOf plot) / (fromIntegral (yDensityOf plot) - 1)
+                      fs = [ (\x -> round $ (f x - yminOf plot) / yIncr) | f <- functionsOf plot]
+                      subDraw x
+                        | x > xmax = []
+                        | otherwise = reverse (replaces (map (\f -> f x) fs) '*' row) : subDraw (x + xIncr)
 
 instance Draw PlotParam where
-	draw plot = transpose . subDraw 0 $ points
-		where row = replicate (pyDensityOf plot) ' '
-		      xIncr  = (pxmaxOf plot - pxminOf plot) / (fromIntegral (pxDensityOf plot) - 1)
-		      yIncr  = (pymaxOf plot - pyminOf plot) / (fromIntegral (pyDensityOf plot) - 1)
-		      points = concat $ map each (pfunctionsOf plot)
-				where each (f,tmin,tmax,tden) = [adjust (f t) | t <- [tmin,(tmin + tIncr)..tmax]]
-					where adjust (x,y) = (round $ (x - pxminOf plot) / xIncr, round $ (y - pyminOf plot) / yIncr)
-					      tIncr = (tmax - tmin) / (fromIntegral tden - 1)
-		      subDraw x fs
-		      	| x >= pxDensityOf plot = []
-		      	| otherwise = reverse (replaces (fst $ rowPoints) '*' row) : subDraw (x + 1) (snd $ rowPoints)
-				where rowPoints = foldl (\(toUse,rest) (a,b) -> if a == x then (b:toUse,rest) else (toUse,(a,b):rest)) ([],[]) fs
+        draw plot = transpose . subDraw 0 $ points
+                where row = replicate (pyDensityOf plot) ' '
+                      xIncr  = (pxmaxOf plot - pxminOf plot) / (fromIntegral (pxDensityOf plot) - 1)
+                      yIncr  = (pymaxOf plot - pyminOf plot) / (fromIntegral (pyDensityOf plot) - 1)
+                      points = concat $ map each (pfunctionsOf plot)
+                                where each (f,tmin,tmax,tden) = [adjust (f t) | t <- [tmin,(tmin + tIncr)..tmax]]
+                                        where adjust (x,y) = (round $ (x - pxminOf plot) / xIncr, round $ (y - pyminOf plot) / yIncr)
+                                              tIncr = (tmax - tmin) / (fromIntegral tden - 1)
+                      subDraw x fs
+                        | x >= pxDensityOf plot = []
+                        | otherwise = reverse (replaces (fst $ rowPoints) '*' row) : subDraw (x + 1) (snd $ rowPoints)
+                                where rowPoints = foldl (\(toUse,rest) (a,b) -> if a == x then (b:toUse,rest) else (toUse,(a,b):rest)) ([],[]) fs
 
 
 instance Draw PlotPolar where
-	draw plot = transpose . subDraw 0 $ points
-		where row = replicate (plyDensityOf plot) ' '
-		      xIncr  = (plxmaxOf plot - plxminOf plot) / (fromIntegral (plxDensityOf plot) - 1)
-		      yIncr  = (plymaxOf plot - plyminOf plot) / (fromIntegral (plyDensityOf plot) - 1)
-		      points = concat $ map each (plfunctionsOf plot)
-				where each (f,tmin,tmax,tden) = [adjust (t,(f t)) | t <- [tmin,(tmin + tIncr)..tmax]]
-					where adjust (th,r) = (round $ (x - plxminOf plot) / xIncr, round $ (y - plyminOf plot) / yIncr)
-							where x = r*cos th
-							      y = r*sin th
-					      tIncr = (tmax - tmin) / (fromIntegral tden - 1)
-		      subDraw x fs
-		      	| x >= plxDensityOf plot = []
-		      	| otherwise = reverse (replaces (fst $ rowPoints) '*' row) : subDraw (x + 1) (snd $ rowPoints)
-				where rowPoints = foldl (\(toUse,rest) (a,b) -> if a == x then (b:toUse,rest) else (toUse,(a,b):rest)) ([],[]) fs
-
--- | prints a @TextPlot@ to the terminal
-printPlot :: TextPlot -> IO()
-printPlot = mapM_ putStrLn 
-
--- | writes a @TextPlot@ to a specified file name
-export ::  String -> TextPlot -> IO()
-export name (first:rest) = do
-	writeFile name first
-	mapM_ (appendFile name . ("\n" ++)) rest
-
--- | prints the a @TextPlot@ from a file to the terminal
-view :: String -> IO()
-view name = do 
-	contents <- readFile name 
-	putStrLn contents
-
---example functions
-bob = Plot 0 10 100 0 10 100 [(\x -> 3*sin(x/2) + 3),(\x -> x^5 / 16)]
-
+        draw plot = transpose . subDraw 0 $ points
+                where row = replicate (plyDensityOf plot) ' '
+                      xIncr  = (plxmaxOf plot - plxminOf plot) / (fromIntegral (plxDensityOf plot) - 1)
+                      yIncr  = (plymaxOf plot - plyminOf plot) / (fromIntegral (plyDensityOf plot) - 1)
+                      points = concat $ map each (plfunctionsOf plot)
+                                where each (f,tmin,tmax,tden) = [adjust (t,(f t)) | t <- [tmin,(tmin + tIncr)..tmax]]
+                                        where adjust (th,r) = (round $ (x - plxminOf plot) / xIncr, round $ (y - plyminOf plot) / yIncr)
+                                                        where x = r*cos th
+                                                              y = r*sin th
+                                              tIncr = (tmax - tmin) / (fromIntegral tden - 1)
+                      subDraw x fs
+                        | x >= plxDensityOf plot = []
+                        | otherwise = reverse (replaces (fst $ rowPoints) '*' row) : subDraw (x + 1) (snd $ rowPoints)
+                                where rowPoints = foldl (\(toUse,rest) (a,b) -> if a == x then (b:toUse,rest) else (toUse,(a,b):rest)) ([],[]) fs
+
+-- | prints a plot
+printPlot :: Draw plot => plot -> IO()
+printPlot = putStr . drawPlot
+
+-- | converts a plot to a multiline 'String'
+drawPlot :: Draw plot => plot -> String
+drawPlot = unlines . draw
 
 --Utilities
 replace :: Int -> a -> [a] -> [a]
 replace n char xs = if 0 <= n && n <= length xs - 1 then (take n xs) ++ [char] ++ back else xs
-	where back = reverse . take (length xs - 1 - n) . reverse $ xs
+        where back = reverse . take (length xs - 1 - n) . reverse $ xs
 
 replaces :: [Int] -> a -> [a] -> [a]
 replaces indices char original = subReplaces indices original
-	where subReplaces (n:ns) xs = subReplaces ns $ replace n char xs
-	      subReplaces [] xs = xs
+        where subReplaces (n:ns) xs = subReplaces ns $ replace n char xs
+              subReplaces [] xs = xs
 
 replace2D :: Int -> Int -> a -> [[a]] -> [[a]]
-replace2D x y char xs = replace x (replace y char $ xs !! x) xs
+replace2D x y char xs = replace x (replace y char $ xs !! x) xs
 Name:                textPlot
-Version:             0.1
+Version:             0.2
 Synopsis:            Graphs functions as lines of text
 Description:         Graphs standard, parametric, and polar functions and plots them into text files or prints them. One creates a standard, polar, or parametric plot with boundaries, dimensions and possible functions. One may add functions to any plot.
 Category:            Charts
 Cabal-Version:       >= 1.2
 
 library
+  GHC-options:     -Wall
   Exposed-Modules: TextPlot
-  Build-Depends:   base >= 2.0 && < 5
+  Build-Depends:   base >= 2.0 && < 5