【发布时间】:2016-05-15 19:54:03
【问题描述】:
我决定浏览 Haskell 中的 d3js 库,但它没有通过 Stackage 安装。
$ stack install d3js
Run from outside a project, using implicit global project config
Using resolver: lts-5.2 from implicit global project's config file: /home/john/.stack/global-project/stack.yaml
While constructing the BuildPlan the following exceptions were encountered:
-- Failure when adding dependencies:
base: needed (>=4.6 && <4.7), 4.8.2.0 found (latest applicable is 4.6.0.1)
needed for package d3js-0.1.0.0
相反,我更感兴趣的是查看d3js-haskell 的来源。如果我可以安装该库,这可能是最简单的示例之一:条形图。
import Control.Monad
import qualified Data.Text as T
import D3JS
test :: Int -> IO ()
test n = T.writeFile "generated.js" $ reify (box "#div1" (300,300) >>= bars n 300 (Data1D [100,20,80,60,120]))
即使是这个简单的例子,我也有很多问题。 reify 是如何工作的?我不得不在字典中查找这个词:
把(抽象的)看作是物质的或具体的东西
你知道吗?
Reify 是一个试图在抽象和真实之间架起一座桥梁的词。恰如其分地,它源自一个“真实”的祖先词——拉丁名词res,意思是“事物”。 “reify”和相关的名词“reification”都在 19 世纪中叶首次出现在英语中,尽管“reification”要早几年,一些词典认为“reify”是名词的回形。在一般使用中,这些词是指以实际或物质的方式考虑或呈现抽象概念的行为,或通过具体示例来判断某事的行为。
如上所述,d3.js 库中的 reify 函数将表示 d3.js 对象的 Haskell 实体转换为实际的 d3.js 代码。我们有具体化对象的例子吗?我们可以罚款一个:
reify (box "#div1" (300,300) >>= bars n 300 (Data1D [100,20,80,60,120]))
括号中的对象是一个可具体化的对象。源代码之旅既有启发性又令人沮丧:
-- |Instances of Reifiable can generate a JavaScript code fragment.
class Reifiable a where
reify :: a -> Text
这是取自d3js/Type.hs 有没有具体化对象的例子?来看看d3js/reify.hs:
instance Reifiable Data1D where
reify (Data1D ps) = surround $ T.intercalate "," $ map show' ps
instance Reifiable Data2D where
reify (Data2D ps) = surround $ T.intercalate "," $ map (\(x,y) -> T.concat ["[",show' x,",",show' y,"]"]) ps
instance Reifiable (JSFunc params r) where
reify (JSFunc name params) = T.concat [name,"(",T.intercalate "," $ map reify params,")"]
instance Reifiable JSParam where
reify (ParamVar name) = name
reify (PText t) = T.concat ["\"",t,"\""]
reify (PDouble d) = show' d
reify (PInt d) = show' d
reify (PFunc (FuncTxt t)) = t
reify (PFunc (FuncExp f)) = T.concat["function(d,i){return ",reify f,";}"]
reify (PFunc' f) = reify f
reify (PArray vs) = T.concat ["[",T.intercalate "," $ map reify vs,"]"]
reify (PChainValue v) = reify v
这些是可具体化类型的示例,但这些并没有告诉我们在 haskell-d3js 中图表是如何构造的?
-- | box parent (w,h) makes an SVG container in a parent element with dimension w x h.
box :: Selector -> (Double,Double) -> St (Var' Selection)
box parent (w,h) = do
assign
$ ((d3Root
>>> select parent
>>> func "append" [PText "svg"]
>>> width w
>>> height h
>>> style "background" "#eef") :: Chain () Selection)
bars :: Int -> Double -> Data1D -> Var' Selection -> St ()
bars n width ps (Var' elem) = do
let bar_w = width / (fromIntegral n)
v <- assign $ Val' (mkRectData bar_w ps)
execute $
(Val elem :: Chain () Selection)
>>> addRect v
>>> fill' "red"
这些示例应该有效。看起来我们致力于红条(我什至还没有看到图表)。
让我以源代码中的一些令人沮丧的脚注结束。这是来自chart.hs
-- This modules provides high-level functions for drawing common charts, such as bar charts and scatter plots.
-- Those functions also exemplify how to compose primitive functions to achieve complex drawing.
-- This module will be expanded in the near future.
【问题讨论】:
标签: haskell d3.js data-visualization