Elm logo
elm
examples

elm-visualization

/

examples

/

Polar Plot

Edit on Ellie

Polar Plot

A polar plot of sin(2x)cos(2x).

module PolarPlot exposing (main)


import Path
import Scale exposing (ContinuousScale)
import Shape
import Statistics
import TypedSvg exposing (circle, g, line, style, svg, text_)
import TypedSvg.Attributes exposing (class, dy, textAnchor, transform, viewBox)
import TypedSvg.Attributes.InPx exposing (fontSize, r, x, x2, y)
import TypedSvg.Core exposing (Svg, text)
import TypedSvg.Types exposing (AnchorAlignment(..), Transform(..), em)


w : Float
w =
    900


h : Float
h =
    450


padding : Float
padding =
    30


mainRadius : Float
mainRadius =
    Basics.min w h / 2 - padding


radiusScale : ContinuousScale Float
radiusScale =
    Scale.linear ( 0, mainRadius ) ( 0, 0.5 )


fn : Float -> Float
fn t =
    sin (2 * t) * cos (2 * t)


data : List (Maybe ( Float, Float ))
data =
    Statistics.range 0 (2 * pi) 0.01
        |> List.map (\t -> Just ( -t + pi / 2, Scale.convert radiusScale (fn t) ))


spoke : Float -> Svg msg
spoke angle =
    g [ transform [ Rotate -angle 0 0 ] ]
        [ line [ x2 mainRadius ] []
        , text_
            [ x (mainRadius + 6)
            , dy (em 0.35)
            , textAnchor
                (if angle < 270 && angle > 90 then
                    AnchorEnd

                 else
                    AnchorInherit
                )
            , transform
                (if angle < 270 && angle > 90 then
                    [ Rotate 180 (mainRadius + 6) 0 ]

                 else
                    []
                )
            ]
            [ text (String.fromFloat angle ++ "°") ]
        ]


radialAxis : Float -> Svg msg
radialAxis radius =
    g []
        [ circle [ r <| Scale.convert radiusScale radius ] []
        , text_ [ y <| Scale.convert radiusScale radius * -1 - 4, transform [ Rotate 15 0 0 ], textAnchor AnchorMiddle ]
            [ radius |> Scale.tickFormat radiusScale 5 |> text ]
        ]


css : String
css =
    """
    .frame {
      fill: none;
      stroke: #000;
    }

    .axis text {
      font: 10px sans-serif;
    }

    .axis line,
    .axis circle {
      fill: none;
      stroke: #777;
      stroke-dasharray: 1,4;
    }

    .axis :last-of-type circle {
      stroke: #333;
      stroke-dasharray: none;
    }

    .line {
      fill: none;
      stroke: red;
      stroke-width: 1.5px;
    }

    .label {
      font-family:  sans-serif;
    }
  """


main : Svg msg
main =
    svg [ viewBox 0 0 w h ]
        [ style [] [ text css ]
        , g [ class [ "label" ], transform [ Translate (padding * 2) (h / 2) ] ]
            [ text_ [ fontSize 20 ] [ text "sin(2x)cos(2x)" ]
            , text_ [ fontSize 12, y 20 ] [ text "A polar plot." ]
            ]
        , g [ transform [ Translate (w / 2 + mainRadius) (h / 2) ] ]
            [ Scale.ticks radiusScale 5
                |> List.drop 1
                |> List.map radialAxis
                |> g [ class [ "r", "axis" ] ]
            , Statistics.range 0 360 30
                |> List.map spoke
                |> g [ class [ "a", "axis" ] ]
            , Path.element (Shape.lineRadial Shape.linearCurve data) [ class [ "line" ] ]
            ]
        ]