From 99988382379d55d23fad3c3e852dc67a0418ad53 Mon Sep 17 00:00:00 2001
From: Tom Schindler <tom.schindler@student.uni-halle.de>
Date: Wed, 26 Jun 2024 20:39:19 +0200
Subject: [PATCH] Vorbereitung Parallele Koordinaten

---
 public/main.js              |   2 +-
 src/Main.elm                |   2 +
 src/ParallelCoordinates.elm | 449 ++++++++++++++++++++++++++++++++++++
 3 files changed, 452 insertions(+), 1 deletion(-)
 create mode 100644 src/ParallelCoordinates.elm

diff --git a/public/main.js b/public/main.js
index a59ab94..c4597f8 100644
--- a/public/main.js
+++ b/public/main.js
@@ -8848,7 +8848,7 @@ var $author$project$Scatterplot$scatterplot = function (model) {
 				_List_Nil,
 				_List_fromArray(
 					[
-						$elm_community$typed_svg$TypedSvg$Core$text('\n            .point circle { stroke: rgba(0, 0, 0,0.4); fill: rgba(255, 255, 255,0.3); }\n            .point text { display: none; }\n            .point:hover circle { stroke: rgba(0, 0, 0,1.0); fill: rgb(118, 214, 78); }\n            .point:hover text { display: inline; }\n          ')
+						$elm_community$typed_svg$TypedSvg$Core$text('\r\n            .point circle { stroke: rgba(0, 0, 0,0.4); fill: rgba(255, 255, 255,0.3); }\r\n            .point text { display: none; }\r\n            .point:hover circle { stroke: rgba(0, 0, 0,1.0); fill: rgb(118, 214, 78); }\r\n            .point:hover text { display: inline; }\r\n          ')
 					])),
 				A2(
 				$elm_community$typed_svg$TypedSvg$g,
diff --git a/src/Main.elm b/src/Main.elm
index ddb4c6c..1fdf593 100644
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -1,5 +1,7 @@
 module Main exposing (..)
 
+--import ParallelCoordinates exposing (ParallelPlotOption)
+
 import Browser
 import Csv.Decode as Decode exposing (Decoder)
 import Html exposing (Html, div)
diff --git a/src/ParallelCoordinates.elm b/src/ParallelCoordinates.elm
new file mode 100644
index 0000000..deb57eb
--- /dev/null
+++ b/src/ParallelCoordinates.elm
@@ -0,0 +1,449 @@
+module ParallelCoordinates exposing (..)
+
+import Axis exposing (..)
+import Browser
+import Color
+import Debug exposing (toString)
+import Html exposing (Html, a, b, br, button, text)
+import Html.Attributes
+import Html.Events exposing (on, onClick)
+import List exposing (concatMap)
+import List.Extra
+import Maybe exposing (map)
+import Path
+import Scale exposing (ContinuousScale)
+import Shape
+import SmartPhoneType exposing (Smartphone)
+import Statistics
+import TypedSvg exposing (circle, g, line, polygon, rect, style, svg, text_)
+import TypedSvg.Attributes exposing (class, fill, fontSize, stroke, strokeWidth, textAnchor, transform, viewBox, width, x1, x2, y1, y2)
+import TypedSvg.Attributes.InPx exposing (cx, cy, r, x, y)
+import TypedSvg.Core exposing (Svg)
+import TypedSvg.Types exposing (AnchorAlignment(..), Length(..), Paint(..), Transform(..), px)
+
+
+
+{-
+   type alias ParallelPlotOption =
+       { attribute1 : String
+       , attribute2 : String
+       , att1List : List (Maybe Float)
+       , att2List : List (Maybe Float)
+       }
+
+
+   w : Float
+   w =
+       900
+
+
+   h : Float
+   h =
+       450
+
+
+   padding : Float
+   padding =
+       50
+
+
+   tickCount : Int
+   tickCount =
+       3
+
+
+   defaultExtent : ( number, number1 )
+   defaultExtent =
+       ( 0, 200000 )
+
+
+   parallelCoodinatesPlot : MultiDimData -> Svg msg
+   parallelCoodinatesPlot multidimData =
+       let
+           dimLen =
+               List.length multidimData.data - 1
+
+           yValues =
+               multidimData.data
+                   |> List.map
+                       (\dimData ->
+                           dimData |> List.map .value
+                       )
+
+           dimStrings =
+               multidimData.dimDescription
+
+           yScaleLocals =
+               List.indexedMap Tuple.pair (List.map yScale yValues)
+
+           xScaleLocal =
+               xScale (List.map toFloat (List.range 0 dimLen))
+
+           yaxis =
+               List.map2 (createYAxis xScaleLocal) yScaleLocals dimStrings
+
+           yValue1 =
+               Maybe.withDefault [] <| List.head yValues
+
+           yValue2 =
+               Maybe.withDefault [] <| List.head <| List.drop 1 yValues
+
+           yValue3 =
+               Maybe.withDefault [] <| List.head <| List.drop 2 yValues
+
+           yValue4 =
+               Maybe.withDefault [] <| List.head <| List.drop 3 yValues
+
+           yScale1 =
+               Tuple.second <| Maybe.withDefault ( 0, Scale.linear ( padding, w - padding ) ( 0, 0 ) ) (List.head yScaleLocals)
+
+           yScale2 =
+               Tuple.second <| Maybe.withDefault ( 0, Scale.linear ( padding, w - padding ) ( 0, 0 ) ) (List.head <| List.drop 1 yScaleLocals)
+
+           yScale3 =
+               Tuple.second <| Maybe.withDefault ( 0, Scale.linear ( padding, w - padding ) ( 0, 0 ) ) (List.head <| List.drop 2 yScaleLocals)
+
+           yScale4 =
+               Tuple.second <| Maybe.withDefault ( 0, Scale.linear ( padding, w - padding ) ( 0, 0 ) ) (List.head <| List.drop 3 yScaleLocals)
+
+           paths =
+               List.map4 pathGenerator yValue1 yValue2 yValue3 yValue4
+
+           pathGenerator : Float -> Float -> Float -> Float -> Path.Path
+           pathGenerator y1 y2 y3 y4 =
+               let
+                   p1 =
+                       ( Scale.convert xScaleLocal 0, Scale.convert yScale1 y1 + 20 )
+
+                   p2 =
+                       ( Scale.convert xScaleLocal 1, Scale.convert yScale2 y2 + 20 )
+
+                   p3 =
+                       ( Scale.convert xScaleLocal 2, Scale.convert yScale3 y3 + 20 )
+
+                   p4 =
+                       ( Scale.convert xScaleLocal 3, Scale.convert yScale4 y4 + 20 )
+               in
+               [ Just p1, Just p2, Just p3, Just p4 ] |> Shape.line Shape.linearCurve
+
+           lines =
+               List.map createLine paths
+       in
+       svg
+           [ viewBox 0 0 (w + 30) (h + 30)
+           , TypedSvg.Attributes.width <| TypedSvg.Types.Percent 100
+           , TypedSvg.Attributes.height <| TypedSvg.Types.Percent 100
+           ]
+           ([ style [] [ TypedSvg.Core.text """
+               .axis text { display: none; }
+               .axis:hover text { display: inline; }
+             """ ]
+            , g [] []
+            ]
+               ++ yaxis
+               ++ lines
+           )
+
+
+   createLine : Path.Path -> Svg msg
+   createLine path =
+       g []
+           [ Path.element path
+               [ stroke <| Paint <| Color.black
+               , strokeWidth <| Px 1
+               , fill PaintNone
+               ]
+           ]
+
+
+   createYAxis : ContinuousScale Float -> ( Int, ContinuousScale Float ) -> String -> Svg msg
+   createYAxis scaleX scaleY text =
+       let
+           index =
+               Tuple.first scaleY |> toFloat
+       in
+       g [ transform [ Translate (Scale.convert scaleX index) 20 ] ]
+           [ g [ class [ "axis" ] ] [ yAxis (Tuple.second scaleY) ]
+           , text_
+               [ y -10, textAnchor AnchorMiddle, fontSize <| Px 14 ]
+               [ Html.text text ]
+           ]
+
+
+   yAxis : ContinuousScale Float -> Svg msg
+   yAxis scale =
+       Axis.left [] scale
+
+
+   xScale : List Float -> ContinuousScale Float
+   xScale values =
+       Scale.linear ( padding, w - padding ) (wideExtent values)
+
+
+   yScale : List Float -> ContinuousScale Float
+   yScale values =
+       Scale.linear ( h, 0 ) (wideExtent values)
+
+
+   wideExtent : List Float -> ( Float, Float )
+   wideExtent values =
+       Maybe.withDefault defaultExtent (Statistics.extent values)
+
+
+   filterCarData :
+       List Car
+       -> CarType
+       -> List CarData
+   filterCarData my_cars carType =
+       let
+           carDataList =
+               List.filterMap mapToCarData my_cars
+
+           carsInType =
+               List.filter (carInCarType carType) carDataList
+       in
+       carsInType
+
+
+   mapToCarData : Car -> Maybe CarData
+   mapToCarData car =
+       map6
+           (\cityMPG retailPrice name dealerCost carLen carType ->
+               { vehicle = name
+               , cityMPG = toFloat cityMPG
+               , retailPrice = toFloat retailPrice
+               , dealerCost = toFloat dealerCost
+               , carLen = toFloat carLen
+               , carType = carType
+               }
+           )
+           car.cityMPG
+           car.retailPrice
+           (Just car.vehicleName)
+           car.dealerCost
+           car.carLen
+           (Just car.carType)
+
+
+   carInCarType : CarType -> CarData -> Bool
+   carInCarType carType carData =
+       if carData.carType == carType then
+           True
+
+       else
+           False
+
+
+   transfromCarDataToMultiDimData : List ( String, List ( Float, String ) ) -> MultiDimData
+   transfromCarDataToMultiDimData dimList =
+       let
+           dimDescription =
+               List.map Tuple.first (List.map ffks dimList)
+
+           data =
+               List.map Tuple.second (List.map ffks dimList)
+       in
+       MultiDimData dimDescription data
+
+
+   ffks : ( String, List ( Float, String ) ) -> ( String, List MultiDimPoint )
+   ffks data =
+       let
+           multiDimPointList =
+               List.map transformToMultiDimPoint (Tuple.second data)
+       in
+       ( Tuple.first data, multiDimPointList )
+
+
+   transformToMultiDimPoint : ( Float, String ) -> MultiDimPoint
+   transformToMultiDimPoint data =
+       MultiDimPoint (Tuple.second data) (Tuple.first data)
+
+
+   cityMPGValue : CarData -> ( Float, String )
+   cityMPGValue car =
+       ( car.cityMPG, car.vehicle )
+
+
+   retailPriceValue : CarData -> ( Float, String )
+   retailPriceValue car =
+       ( car.retailPrice, car.vehicle )
+
+
+   dealerCostValue : CarData -> ( Float, String )
+   dealerCostValue car =
+       ( car.dealerCost, car.vehicle )
+
+
+   carLenValue : CarData -> ( Float, String )
+   carLenValue car =
+       ( car.carLen, car.vehicle )
+
+
+   pointNameValue : CarData -> String
+   pointNameValue =
+       .vehicle
+
+
+   getIndex : String -> Model -> Int
+   getIndex str model =
+       let
+           rangeList =
+               List.range 0 <| List.length model.reihenfolge - 1
+
+           findIndex : Int -> Maybe Int
+           findIndex index =
+               if List.Extra.getAt index model.reihenfolge == Just str then
+                   Just index
+
+               else
+                   Nothing
+
+           i =
+               List.filterMap findIndex rangeList
+       in
+       Maybe.withDefault 0 (List.head i)
+
+
+   view : Model -> Html Msg
+   view model =
+       let
+           carType =
+               model.carType
+
+           filteredCarsData =
+               filterCarData cars carType
+
+           numberCarsInType =
+               List.length filteredCarsData
+
+           cityMPGValues =
+               List.map cityMPGValue filteredCarsData
+
+           retailPriceValues =
+               List.map retailPriceValue filteredCarsData
+
+           dealerCostValues =
+               List.map dealerCostValue filteredCarsData
+
+           carLenValues =
+               List.map carLenValue filteredCarsData
+
+           iCityMPG =
+               getIndex "cityMPG"
+
+           dimList =
+               List.map Tuple.second
+                   (List.sortBy Tuple.first
+                       [ ( getIndex "cityMPG" model, ( "cityMPG", cityMPGValues ) )
+                       , ( getIndex "retailPrice" model, ( "retailPrice", retailPriceValues ) )
+                       , ( getIndex "dealerCost" model, ( "dealerCost", dealerCostValues ) )
+                       , ( getIndex "carLen" model, ( "carLen", carLenValues ) )
+                       ]
+                   )
+
+           multiDimData =
+               transfromCarDataToMultiDimData dimList
+       in
+       Html.div []
+           [ Html.p [ fontSize <| Px 5 ]
+               [ Html.text
+                   ("CarType: "
+                       ++ toString carType
+                       ++ " | Cars in Typ: "
+                       ++ String.fromInt numberCarsInType
+                   )
+               ]
+           , b [] [ text "Car Type: " ]
+           , button [ onClick SetSmall_Sporty_Compact_Large_Sedan ] [ text "SSCLS" ]
+           , button [ onClick SetSports_Car ] [ text "Sport Car" ]
+           , button [ onClick SetSUV ] [ text "SUV" ]
+           , button [ onClick SetWagon ] [ text "Wagon" ]
+           , button [ onClick SetMinivan ] [ text "Minivan" ]
+           , button [ onClick SetPickup ] [ text "Pickup" ]
+           , br [] []
+           , button [ onClick (Down "cityMPG") ] [ text "Down cityMPG" ]
+           , button [ onClick (Up "cityMPG") ] [ text "Up cityMPG" ]
+           , br [] []
+           , button [ onClick (Down "retailPrice") ] [ text "Down retailPrice" ]
+           , button [ onClick (Up "retailPrice") ] [ text "Up retailPrice" ]
+           , br [] []
+           , button [ onClick (Down "dealerCost") ] [ text "Down dealerCost" ]
+           , button [ onClick (Up "dealerCost") ] [ text "Up dealerCost" ]
+           , br [] []
+           , button [ onClick (Down "carLen") ] [ text "Down carLen" ]
+           , button [ onClick (Up "carLen") ] [ text "Up carLen" ]
+           , br [] []
+           , br [] []
+           , parallelCoodinatesPlot multiDimData
+           ]
+
+
+   type alias MultiDimPoint =
+       { pointName : String, value : Float }
+
+
+   type alias MultiDimData =
+       { dimDescription : List String
+       , data : List (List MultiDimPoint)
+       }
+
+
+   type Msg
+       = SetSmall_Sporty_Compact_Large_Sedan
+       | SetSports_Car
+       | SetSUV
+       | SetWagon
+       | SetMinivan
+       | SetPickup
+       | Up String
+       | Down String
+
+
+   type alias Model =
+       { carType : CarType
+       , reihenfolge : List String
+       }
+
+
+   update : Msg -> Model -> Model
+   update msg model =
+       case msg of
+           SetSmall_Sporty_Compact_Large_Sedan ->
+               { model | carType = Small_Sporty_Compact_Large_Sedan }
+
+           SetSports_Car ->
+               { model | carType = Sports_Car }
+
+           SetSUV ->
+               { model | carType = SUV }
+
+           SetWagon ->
+               { model | carType = Wagon }
+
+           SetMinivan ->
+               { model | carType = Minivan }
+
+           SetPickup ->
+               { model | carType = Pickup }
+
+           Up str ->
+               { model
+                   | reihenfolge =
+                       if getIndex str model < (List.length model.reihenfolge - 1) then
+                           List.Extra.swapAt (getIndex str model) (getIndex str model + 1) model.reihenfolge
+
+                       else
+                           model.reihenfolge
+               }
+
+           Down str ->
+               { model
+                   | reihenfolge =
+                       if getIndex str model > 0 then
+                           List.Extra.swapAt (getIndex str model) (getIndex str model - 1) model.reihenfolge
+
+                       else
+                           model.reihenfolge
+               }
+-}
-- 
GitLab