GoogleChart 0.1 → 0.2
raw patch · 2 files changed
+157/−23 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Graphics.Google.Chart: AlignCenter :: AxisAlignment
+ Graphics.Google.Chart: AlignLeft :: AxisAlignment
+ Graphics.Google.Chart: AlignRight :: AxisAlignment
+ Graphics.Google.Chart: AxisBottom :: AxisType
+ Graphics.Google.Chart: AxisLeft :: AxisType
+ Graphics.Google.Chart: AxisRight :: AxisType
+ Graphics.Google.Chart: AxisTop :: AxisType
+ Graphics.Google.Chart: class Chart c => AxisLabelChart c
+ Graphics.Google.Chart: data AxisAlignment
+ Graphics.Google.Chart: data AxisType
+ Graphics.Google.Chart: data VennDiagram
+ Graphics.Google.Chart: instance AxisLabelChart BarChart
+ Graphics.Google.Chart: instance AxisLabelChart LineChart
+ Graphics.Google.Chart: instance Chart VennDiagram
+ Graphics.Google.Chart: instance LegendChart VennDiagram
+ Graphics.Google.Chart: newVennDiagram :: VennDiagram
+ Graphics.Google.Chart: setAxisLabelPositions :: AxisLabelChart c => [[Int]] -> c -> c
+ Graphics.Google.Chart: setAxisLabels :: AxisLabelChart c => [[String]] -> c -> c
+ Graphics.Google.Chart: setAxisRanges :: AxisLabelChart c => [(Int, Int)] -> c -> c
+ Graphics.Google.Chart: setAxisStyles :: AxisLabelChart c => [(String, Int, AxisAlignment)] -> c -> c
+ Graphics.Google.Chart: setAxisTypes :: AxisLabelChart c => [AxisType] -> c -> c
+ Graphics.Google.Chart: setDataColors :: Chart c => [String] -> c -> c
- Graphics.Google.Chart: chartURL :: (Chart c) => c -> String
+ Graphics.Google.Chart: chartURL :: Chart c => c -> String
- Graphics.Google.Chart: class (Chart c) => LegendChart c
+ Graphics.Google.Chart: class Chart c => LegendChart c
- Graphics.Google.Chart: encodeDataText :: [[Int]] -> ChartData
+ Graphics.Google.Chart: encodeDataText :: RealFrac a => [[a]] -> ChartData
- Graphics.Google.Chart: setData :: (Chart c) => ChartData -> c -> c
+ Graphics.Google.Chart: setData :: Chart c => ChartData -> c -> c
- Graphics.Google.Chart: setLegend :: (LegendChart c) => [String] -> c -> c
+ Graphics.Google.Chart: setLegend :: LegendChart c => [String] -> c -> c
- Graphics.Google.Chart: setSize :: (Chart c) => Int -> Int -> c -> c
+ Graphics.Google.Chart: setSize :: Chart c => Int -> Int -> c -> c
- Graphics.Google.Chart: setTitle :: (Chart c) => String -> c -> c
+ Graphics.Google.Chart: setTitle :: Chart c => String -> c -> c
- Graphics.Google.Chart: setTitleOpts :: (Chart c) => String -> Int -> c -> c
+ Graphics.Google.Chart: setTitleOpts :: Chart c => String -> Int -> c -> c
Files
- GoogleChart.cabal +1/−1
- Graphics/Google/Chart.hs +156/−22
GoogleChart.cabal view
@@ -1,6 +1,6 @@ Cabal-Version: >= 1.2 Name: GoogleChart-Version: 0.1+Version: 0.2 Synopsis: Generate web-based charts using the Google Chart API Category: Graphics License: BSD3
Graphics/Google/Chart.hs view
@@ -25,6 +25,17 @@ This produces: <http://chart.apis.google.com/chart?chs=400x257&chtt=My+Chart&chd=s%3aBCDEFGHIJKLMNOPQRSTU&chdl=1+to+20&cht=lc> +Remaining features to implement:++- lxy line charts++- chbh bar charts++- scatter plots++- background\/fill colors++- all style attributes -} module Graphics.Google.Chart (@@ -35,11 +46,22 @@ setSize, setTitle, setTitleOpts, setData, -- ** Chart data -- | There are multiple options for encoding chart data. See- -- <http://code.google.com/apis/chart/#chart_data> for more details.+ -- <http://code.google.com/apis/chart/#chart_data> for more details on+ -- the tradeoffs of the different encoding options. ChartData, encodeDataSimple, encodeDataText, encodeDataExtended, + setDataColors,+ -- * Chart features+ -- ** Legends LegendChart, setLegend,+ -- ** Axis labels+ -- | The order of elements in the lists passed to these functions matter:+ -- If the first 'AxisType' passed to 'setAxisTypes' is 'AxisBottom', then+ -- the first set of labels passed to 'setAxisLabels' refers to that bottom+ -- axis.+ AxisLabelChart, setAxisTypes, AxisType(..), setAxisLabels,+ setAxisLabelPositions, setAxisRanges, AxisAlignment(..), setAxisStyles, -- * Specific chart types -- ** Line charts@@ -49,21 +71,27 @@ PieChart, newPieChart, PieStyle(..), setLabels, -- ** Bar charts- BarChart, newBarChart, Orientation(..), BarStyle(..)+ BarChart, newBarChart, Orientation(..), BarStyle(..),++ -- ** Venn diagrams+ VennDiagram, newVennDiagram ) where import Data.Char (chr, ord) import Data.List (intercalate) import Numeric (showHex) --- | Bar-+-- | URL-encode a string. urlEnc str = concatMap enc str where- enc c | c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' = [c]- | c >= '0' && c <= '9' = [c]- | c == '-' || c == '_' || c == '.' || c == '~' = [c]- | c == ' ' = "+"+ enc c | c >= 'A' && c <= 'Z' = [c]+ | c >= 'a' && c <= 'z' = [c]+ | c >= '0' && c <= '9' = [c]+ | c `elem` safe = [c]+ | c == ' ' = "+" | otherwise = '%':(showHex (ord c) "")+ -- Argh, different resources differ on which characters need escaping.+ -- This is likely wrong.+ safe = "$-_.!*'(),|:" -- All charts are internally represented as a list of (key,value) pairs. -- We could switch this to Data.Map if it matters.@@ -104,10 +132,10 @@ -- |All the encoding methods produce 'ChartData', which is usable by 'setData'. newtype ChartData = ChartData String deriving Show --- |Encode data using the \"simple\" encoding. This produces minimal URLs but--- doesn't have as much resolution. Input values must be in the range @0 <= x--- <= 61@. Values outside the valid input range will be considered missing--- data.+-- |Encode data using the \"simple\" encoding, which maps each input value+-- to a single letter in the URL. This produces minimal URLs but doesn't have+-- as lot of resolution. Input values must be in the range @0 <= x <= 61@.+-- Values outside the valid input range will be considered missing data. encodeDataSimple :: [[Int]] -> ChartData encodeDataSimple datas = ChartData $ "s:" ++ intercalate "," (map (map enc) datas) where@@ -116,26 +144,117 @@ | i >= 52 && i <= 61 = chr (ord '0' + (i - 52)) | otherwise = '_' --- |Encode data using the \"text\" encoding. XXX unimplemented.-encodeDataText :: [[Int]] -> ChartData-encodeDataText = undefined+-- |Encode data using the \"text\" encoding, which maps each input value to+-- its string representation (e.g. \"3.4\") in the URL. This has more+-- resolution than simple encoding but produces larger URLs. Input values must+-- be in the range @0 <= x <= 100@. Values outside the valid input range will+-- be considered missing data. Values with more than one decimal place of+-- resolution will be rounded.+encodeDataText :: RealFrac a => [[a]] -> ChartData+-- I chose RealFrac because it's necessary for floor; what is appropriate here?+-- The input must effectively be fixed-point.+encodeDataText datas =+ ChartData $ "t:" ++ intercalate "|" (map encData datas) where+ encData = intercalate "," . map encDatum+ encDatum i | i >= 0 && i <= 100 = showDecimal i+ | otherwise = "-1"+ showDecimal :: RealFrac a => a -> String+ showDecimal i = show (fromIntegral (round (i * 10.0)) / 10.0) --- |Encode data using the \"extended\" encoding. XXX unimplemented.+-- |Encode data using the \"extended\" encoding, which maps each input value+-- to a two-character pair in base 64. This has more resolution than text+-- encoding and is more compact. Input values must be in the range @0 <= x <=+-- 4095@. Values outside the valid input range will be considered missing+-- data. encodeDataExtended :: [[Int]] -> ChartData-encodeDataExtended = undefined+encodeDataExtended datas =+ ChartData $ "e:" ++ intercalate "," (map (concatMap encDatum) datas) where+ encDatum i | i >= 0 && i < 4096 = let (a, b) = i `quotRem` 64 in+ [encChar a, encChar b]+ | otherwise = "__"+ encChar i | i >= 0 && i <= 25 = chr (ord 'A' + i)+ | i >= 26 && i <= 51 = chr (ord 'a' + (i - 26))+ | i >= 52 && i <= 61 = chr (ord '0' + (i - 52))+ | i == 62 = '-'+ | i == 63 = '.' +-- |Set data set colors. The nth color specified here colors the nth data+-- set in the 'ChartData' passed to 'setData'. See+-- <http://code.google.com/apis/chart/#line_bar_pie_colors> for more+-- information.+setDataColors :: Chart c => [String] -> c -> c+setDataColors colors = setParam "chco" (intercalate "," colors)+ -- |LegendChart represents charts that can display legends with 'setLegend'.-class Chart c => LegendChart c where- -- |Set the legend for the corresponding data sets. The colors are taken- -- from the data set colors.- setLegend :: [String] -> c -> c- setLegend strs = setParam "chdl" (intercalate "|" strs)+class Chart c => LegendChart c+-- |Set the legend for the corresponding data sets. The colors are taken+-- from the data set colors.+setLegend :: LegendChart c => [String] -> c -> c+setLegend strs = setParam "chdl" (intercalate "|" strs) +-- |AxisLabelChart represents charts that can display axis labels.+class Chart c => AxisLabelChart c++-- |Where to display an axis.+data AxisType = AxisBottom | AxisTop | AxisLeft | AxisRight++-- |Set which axes to display. Repeating an 'AxisType' produces multiple+-- sets of labels on that axis.+setAxisTypes :: AxisLabelChart c => [AxisType] -> c -> c+setAxisTypes axes = setParam "chxt" (intercalate "," (map axisChar axes)) where+ axisChar AxisBottom = "x"+ axisChar AxisTop = "t"+ axisChar AxisLeft = "y"+ axisChar AxisRight = "r"++-- |Set axis labels. The nth list of strings in the argument sets the labels+-- for the nth axis specified with 'setAxisTypes'. An empty list of strings+-- skips labelling the corresponding axis.+setAxisLabels :: AxisLabelChart c => [[String]] -> c -> c+setAxisLabels axislabels =+ setParam "chxl" (intercalate "|" (zipWith axisLabel [0..] axislabels)) where+ axisLabel :: Int -> [String] -> String+ axisLabel _ [] = ""+ axisLabel index labels = show index ++ ":|" ++ intercalate "|" labels++-- |Set axis label positions. The nth list of Ints in the argument sets the+-- positions for the nth axis specified with 'setAxisTypes'. An empty list+-- skips setting position for the corresponding axis.+setAxisLabelPositions :: AxisLabelChart c => [[Int]] -> c -> c+setAxisLabelPositions positions =+ setParam "chxp" (intercalate "|" (zipWith axisPosn [0..] positions)) where+ axisPosn _ [] = ""+ axisPosn index xs = intercalate "," (map show (index:xs))++-- |Set axis ranges. The nth pair of Ints in the argument sets the range+-- for the nth axis specified with 'setAxisTypes'.+setAxisRanges :: AxisLabelChart c => [(Int,Int)] -> c -> c+setAxisRanges ranges =+ setParam "chxr" (intercalate "|" (zipWith axisRange [0..] ranges)) where+ axisRange index (min,max) = intercalate "," (map show [index,min,max])++-- |Text alignment for labels on an axis.+data AxisAlignment = AlignLeft | AlignCenter | AlignRight++-- |Set axis styles. The nth element in the argument sets the style for the+-- nth axis specified with 'setAxisTypes'. Each style is a tuple of+-- (color, font size, text alignment).+setAxisStyles :: AxisLabelChart c => [(String,Int,AxisAlignment)] -> c -> c+setAxisStyles styles =+ setParam "chxs" (intercalate "|" (zipWith axisStyle [0..] styles)) where+ axisStyle index (color, size, align) =+ intercalate "," [show index, color, show size, alignString align]+ alignString AlignLeft = "-1"+ alignString AlignCenter = "0"+ alignString AlignRight = "1"++ newtype LineChart = LineChart Params instance Chart LineChart where params (LineChart p) = p fromParams = LineChart instance LegendChart LineChart+instance AxisLabelChart LineChart newLineChart :: LineChart newLineChart = fromParams [("cht","lc")]@@ -149,6 +268,7 @@ newPieChart Pie2D = fromParams [("cht","p")] newPieChart Pie3D = fromParams [("cht","p3")] +-- |Set labels for the different data points on the chart. -- Specify missing values by passing an empty string. setLabels :: [String] -> PieChart -> PieChart setLabels labels = setParam "chl" $ intercalate "|" labels@@ -158,6 +278,7 @@ params (BarChart p) = p fromParams = BarChart instance LegendChart BarChart+instance AxisLabelChart BarChart data Orientation = Horizontal | Vertical data BarStyle = Stacked | Grouped newBarChart :: Orientation -> BarStyle -> BarChart@@ -167,3 +288,16 @@ oLetter Vertical = 'v' sLetter Stacked = 's' sLetter Grouped = 'g'++-- |Venn diagram data is specified in a particular format. There should be+-- exactly seven data values, which represent, in order:+-- circle A size, circle B size, circle C size,+-- A\/B overlap, A\/C overlap, B\/C overlap,+-- A\/B\/C overlap.+newtype VennDiagram = VennDiagram Params+instance Chart VennDiagram where+ params (VennDiagram p) = p+ fromParams = VennDiagram+instance LegendChart VennDiagram+newVennDiagram :: VennDiagram+newVennDiagram = fromParams [("cht", "v")]