Giter VIP home page Giter VIP logo

elm-visualization's People

Contributors

anton-4 avatar deciob avatar dependabot-preview[bot] avatar dependabot[bot] avatar edennis avatar ericgj avatar etaque avatar ffigiel avatar folkertdev avatar fuja0815 avatar gampleman avatar ianmackenzie avatar jfmengels avatar lucamug avatar razzeee avatar sturgman avatar woylie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elm-visualization's Issues

Reverse order of arguments for Scale construction

Currently, when constructing scales, the arguments are domain and then range. This is somewhat intuitive, but in practice the range is often known statically, whereas the domain is computed from the data.

So currently you can see code like this:

width : Float
width = 800

makeXScale : (Float, Float) -> ContinuousScale
makeXScale domain = 
  Scale.linear domain (0, width)

makeColorScale : (Float, Float) -> SequentialScale Color
makeColorScale domain =
  Scale.sequential domain Scale.viridisInterpolator

whereas if the arguments were reversed, the code would simplify to:

width : Float
width = 800

makeXScale : (Float, Float) -> ContinuousScale
makeXScale =  Scale.linear (0, width)

makeColorScale : (Float, Float) -> SequentialScale Color
makeColorScale = Scale.sequential Scale.viridisInterpolator

Thoughts?

Force.tick produces "NaN"s for x and y fields in Entity

Hello,
I use Force.tick for an animated application of force.

I have a use case where a Entity, after a Force.tick call, comes back with "NaN" values for the x and y fields.

Here is the data. The logs happened immediatly before I call Force.tick and immediatly after I call it. I pretty-printed them for easier comprehension:

Input Force.tick: 

Entities:
  (x,                  y                 ) |(vx, vy)
-------------------------------------------|--------
 ((526.5759052118638,  293.3027712572425), |(0,  0))
 ((386.3512835644626,  415.9671753206878), |(0,  0))
 ((429.3073689756422,  189.14562685359772),|(0,  0))
 ((518.5317355646032,  355.4308242590064), |(0,  0))
 ((139.23370668342812, 246.1536023094656), |(0,  0))
----------------------------------------------------        
    
Simulation-State:
    { alpha = 1
    , alphaDecay = 0.02276277904418933
    , alphaTarget = 0
    , forces = 
        [ Links 1 
            [{ bias = 0.5, distance = 150, source = "3", strength = 0.5, target = "4" }
            ,{ bias = 0.5, distance = 150, source = "2", strength = 0.5, target = "4" }
            ,{ bias = 0.5, distance = 150, source = "1", strength = 0.5, target = "3" }
            ,{ bias = 0.5, distance = 150, source = "1", strength = 0.5, target = "2" }
            ,{ bias = 0.5, distance = 150, source = "0", strength = 0.5, target = "0" } -- source and target are the same here, but that is a valid state in my case!
            ]
        , ManyBody 0.9 
            ( Dict.fromList             
                [("0",-500)
                ,("1",-500)
                ,("2",-500)
                ,("3",-500)
                ,("4",-500)
                ]
            )
        ,Center 400 300
        ]
    , minAlpha = 0.001
    , velocityDecay = 0.6 
    }    
            

=====================================================
Output Force.tick:            
                                            
  (x,                  y                 ) |(vx, vy)
-------------------------------------------|--------
 ((527.2044879394728,  293.5724313492498), |(0,  0))
 ((386.14888774606607, 416.9074137596222), |(0,  0))
 ((430.6045558668222,  189.20225383801645),|(0,  0))
 ((520.0468122000351,  354.82321315627416),|(0,  0))
 ((NaN,                NaN),               |(0,  0))
----------------------------------------------------

Notice that the edge in question is a self-reference, so thi smight be the reason for this behavior? I can work around for it now, but maybe this points to a bigger issue?

Size graph to parent element

I'm working on a responsive design, and I'd really like to have the graph's width adjust based on the view port. I'm currently not aware of a way to get a DOM element's width in Elm, and the scales appear to require a hard width to render correctly.

Do you have any ideas or workarounds for this?

Axis ticks color

There's a common D3 axis trick to set the ticks hight to a negative value to obtain a grid.
We can use that trick here as well, but the lines are drawn with stroke "#000" resulting in strong black lines.

A quick improvement would be to change the stroke value to "currentColor".

Ref: https://css-tricks.com/currentcolor/

Um, it's awesome!!!!

No issue, just wanted to say thank you for bringing D3 to Elm!

Amazing, super, wow.

Better than D3. (For what I'm doing!)

This + TypedSVG is super powerful.

Rock on,

Adam

Upgrade to new one-true-path-experiment major version

Hello Jakub,
@folkertdev just released a new version of one-true-path-experiment, with fixes for path and floating number coordinates parsing. Unfortunately the path parser fix imply a major version bump for it, so elm-visualization can't match it. Would you mind bumping this version dep? (I can make a PR to prepare this).
Have a nice day,
Emilien

Meta: Breaking changes for v2.0

The plan is to aggregate major breaking changes that would be worthwhile to make, so that a major release can be coordinated.

  • Change Visualization.List.range from number -> number -> number -> List number to Float -> Float -> Float -> List Float. This would enable much simpler and more correct code (partially this is due to compiler bugs, but not entirely).

  • Fix the bad type signatures for quantize scales to enable them to be compatible with Axis. See #5.

  • Reconsider argument order for Scales. See #7.

  • Consider removing Path module in favor of a third party library, see https://github.com/folkertdev/one-true-path-experiment. This would potentially make animation significantly easier, if animation libraries also migrate to this shared common core.

  • Open up the Curve data type by changing it to a type alias for List (Float, Float)

  • Remove module prefixes. So Visualization.Shape would become Shape. Not entirely sure what to do with Visualization.List yet. One option is to make this module private as it mostly contains utility functions used elsewhere. Another is to simply rename it to something like ListUtilities.

Clamp ContinuousTimeScale ticks to round(er) values

I'm implementing a zoomable time axis (from seconds up to months, ) and ContinuousTimeScale works almost perfectly out of the box but for certain zoom levels the resulting ticks could be improved.

As the ideal result seems quite case specific I was wondering if it would make sense to add the ability to pass custom tickIntervals through to the Scale? Essentially what I would want is to modify this https://github.com/gampleman/elm-visualization/blob/master/src/Visualization/Scale/Time.elm#L51 but due to most of the machinery being private modifying it without forking the whole library seems a no go.

Elm v0.19 support

I'm sure this is already on the radar, but I thought I'd make a ticket so we can all focus our attention. I will look into helping with this and possibly adding a PR if no-one beats me to it.

Brush mousedown/touchstart not getting correct position in scaled SVG

Not sure if I'm not doing something right, but I have a 1d (X) brush that works perfectly only when the outer width exactly matches the viewBox width. When it is scaled up (the actual width > viewBox width), the left side of the brush overlay gets shifted to the right, and by a factor of the x position in the SVG so that towards the left side it's almost correct, but as you move right, it gets further and further offset. Likewise when it is scaled down (actual width < viewBox width), the left side of the overlay gets shifted to the left. Otherwise, other manipulation of the brush (moving, stretching, dragging etc.) works fine, it's just the initial positioning of the brush that's off.

Unless I'm doing something wrong, I suspect something in the event decoders is not working right. Perhaps decodeSVGTransformMatrix is not finding and therefore adjusting by the viewBox dimensions? Maybe be related to #92 ? My understanding of this corner of the DOM is pretty sketchy, so I'm not clear how you are getting to the viewBox which is in an ancestor node, from the top-level brush g which I'd think is the currentTarget ? Does baseVal somehow magically get you the viewBox of its ancestor nodes?

Thanks for any suggestions. elm-visualization rocks.

decodeSVGTransformMatrix : Decoder (Maybe Matrix2x3)
decodeSVGTransformMatrix =
    D.oneOf
        [ D.map3
            (\viewBox width height ->
                Just ( ( viewBox.width / width, 0, 0 ), ( 0, viewBox.height / height, 0 ) )
            )
            (D.at [ "currentTarget", "viewBox", "baseVal" ] decodeRect)
            (D.at [ "currentTarget", "width", "baseVal", "value" ] D.float)
            (D.at [ "currentTarget", "height", "baseVal", "value" ] D.float)
        , D.succeed Nothing
        ]

Performance testing

I would like to figure out a way to track performance so that subsequent commits don't backslide the performance gains (at least inadvertently) from micro optimizations like #36. For example reverting the changes made in that PR would be totally reasonable in a code cleanup PR that a reviewer (who doesn't remember why they were made) wouldn't blink twice about.

Originally posted by @gampleman in #36

Setup CI

It would be nice if there was a CI to double check that the tests pass and the code compiles. Bonus if we can get image diffing on the examples.

Upgrade elm-community/list-extra

This package uses elm-community/list-extra v6.Meaning that it cannot be used with project using elm-community/list-extra v7 (our case). Please upgrade.

2.2 Plan

For a long time I've made modules with (hopefully) a relatively coherent API that tackle some sort of problem. Usually I've omitted some of the slightly less used parts to save some time and get stuff out of the door.

But I believe it's time to make a release that fills out those blanks to make a more comprehensive library.

So here is the checklist what I would like to see done:

  • Force (#117)
    • collision force πŸ”
    • x force
    • y force
    • radial force πŸ”
  • Interpolation
    • LAB and HCL color interpolators (#76)
    • Cubehelix and XYZ color interpolators
  • Scale (#85)
  • Scale.Color
    • Eh, this could use a whole lot... #61
  • Shape - I think this is fairly complete for now
  • Statistics
  • Transition
    • Add all the common easing functions #77
  • Zoom
    • Add documentation and example on how to use in an interactive SVG. There are some subtleties like weird event handling and tricky coordinate conversions that should be easier to setup. πŸ”
    • Add functions to manipulate the zoom programmatically.
  • Examples
    • Rework some of the more complex examples to be a bit more didactical. Probably the stacked charts are a bit confusing.
    • Get rid of the SampleData module and just inline the data definitions (#90).
    • Write a bit more introductory text to outline what techniques the example is there to show.
    • Implement categories for the sample website #95
    • Implement a "Open on Ellie" link #95
    • Figure out how to effectively redirect from the old docs site to the new. Ideally if we can remove the compiled assets from the repo, this would be best.
  • Docs
    • Fix any typos or broken images
    • Link up Interpolation and Sequential scales.
    • Uppercase README.md to make it work with edp on case sensitive operating systems (@gampleman)
  • Project
    • Migrate CI to GitHub actions.
    • Fix tests to not fail due to random perturbations in Floating point numbers #73 @Anton-4
    • Update to elm-geometry v3 (if ready sooner, can be released as 2.1.2)

Probably drop:

  • Fisheye scale πŸ”
  • Think about timelines for transitions πŸ”
  • Document various contributing minutiae so that the project can be maintained without me if necessary

(:mag: means that this feature will also need an example demonstrating how to use it).

This is a fairly ambitions plan and I would appreciate some help. Typically a lot of the design of these apis should simply follow the patterns already established in the module (remember, this will be a MINOR release, so no breaking changes allowed). As such this will be mostly about implementation, docs and examples. (Of course if while working on these you think you discovered a better API design, please open an issue or get in touch on Slack. Just because we won't ship it in this release doesn't mean we won't improve it at all. But I do like to batch breaking changes so the library mostly provides a stable target with only very rare upgrade costs).

So if you would like to contribute one of these, please let me know. Thanks!

3.0 Notes AKA ideas that require breaking changes

Note: None of this is going to happen any time soon. The last breaking change we made was forced by a new version of Elm. But it is a good idea to keep a wish list of things to change in the future.

  • sequential scale can easily support axes, but don't at the moment
  • Loosen type signature of invertExtent to support threshold scales.
  • Use partial application for scales to simplify type signatures.
  • Switch from record to list style for band/point configs.
  • Change architecture of Force to allow for nicer custom forces as well as better dead code elimination
  • #144
  • #65
  • Surely Shape.stack can be made more intuitive.

See also #10.

QuantizeScale not RenderableScale?

I get an error calling Axis.axis with a QuantizeScale. It looks like the types don't line up for ticks and tickFormat . Am I missing something?

QuantizeScale a

{ domain : (Float, Float)
, range : (a, List a)
, convert : (Float, Float) -> (a, List a) -> Float -> a
, invertExtent : (Float, Float) -> (a, List a) -> a -> Maybe (Float, Float)
, ticks : (Float, Float) -> (a, List a) -> Int -> List Float
, tickFormat : (Float, Float) -> (a, List a) -> Int -> Float -> String
, nice : (Float, Float) -> Int -> (Float, Float)
, rangeExtent : (Float, Float) -> (a, List a) -> (a, a) 
}

RenderableScale

{ a | 
    ticks : domain -> Int -> List value
  , domain : domain
  , tickFormat : domain -> Int -> value -> String
  , convert : domain -> range -> value -> Float
  , range : range
  , rangeExtent : domain -> range -> (Float, Float) 
}

Question for non-standard force layout model

Hello

I am trying to make a force layout simulation that displays the graph in a tree like way. By "tree-like", I mean I want the resulting layout to look something like a hierarchical layout where parent nodes will be displayed above child nodes, left child nodes are placed to the left of their sibling nodes, etc. These aren't hard constraints, but I want the layout to trend towards local placements close to this:

          parent
        /        \
leftChild    rightChild

I don't want to use Sugiyama because it is complicated to turn that into an incremental algorithm (nodes in my visualization will be continually added and removed).

My main idea right now is to coarsen the graph by treating some of the local 3-node subgraphs (parent, leftChild, rightChild) as single nodes, and applying a force simulation on that simplified graph. Maybe even treating 2-node subgraphs of (parent, leftChild) as single nodes would be enough.

Is there a more elegant/simple approach?

Thank you

Differentiate between scroll and pinch-to-zoom

Hi, thank you for all the great work! I use this package for zooming and panning in a user interface, and it works wonderfully.

The only issue I have is that the onWheel event handles both the scrolling and the pinch-to-zoom gestures, whereas it would be preferable if scrolling were still possible, as it is for example in the zoom-and-pan interfaces of Sketch and Metro.io.

According to this article, the solution could be to add (D.field "ctrlKey" D.bool) to the decoder in the onWheel function:

When you perform a pinch-zoom gesture, Firefox and Chrome produce a wheel event with a deltaY: Β±scale, ctrlKey: true.

If ctrlKey is False, the message could be a NoOp and the preventDefault in the event listener could be removed to allow scrolling.

Break out Scale type

One of things that always bugs me are the types in the Scale module. They:

  • Are very complicated.
  • Possibly unique, in the sense that no other Elm library (afaik) uses types in quite the same way.
  • The documentation even instructs the user to not pay too much attention to the types. This is clearly not idiomatic to Elm.
  • The documentation needs to point out which functions can be used with which types.
  • The errors could be better
  • The library uses type aliases to hide how the types work.

The reason they were designed that way is that I wanted to have a generic Scale type, that could be operated on regardless of what kind of scale there was, yet not all scales support all operations. I knew I definitely didn't want runtime failures (i.e. unnecessary Maybes), hence this design.

One option is trying to figure out some phantom types to simplify this, but I have tried this before and not made much progress.

The other option is to abandon the generic Scale type and simply have a module and type for each kind of scale (i.e. there would be Scale.Continuous, Scale.Sequential, etc). This would make the types straightforward and the internal logic equally so. Each of these would need an adaptor function for Axes (which we already kind of have for band scales). All the above disadvantages would go away, however there are some downsides:

  • No more generic programming. Is this a problem? Do people use Scales generically or is this a concern literally just for Axes?
  • Right now dead code elimination works very efficiently - you ship code only for scales you use. It would be likely that if you used Axes, you would need to ship some code for all scales that supported Axes. There is not a huge amount of code behind every Scale type, so this might be acceptable.
  • There would be no central Scale module, so there is less of a sensible place to introduce the concept as a whole.

Anyway, this issue is just putting down some thoughts. I have not committed to this, I am seeking feedback on these options, so please feel free to offer your opinion.

ManyBody crashes if two nodes have exactly the same coordinates

to replicate the error, replace in the example the lines

        graph =
            Graph.mapContexts initializeNode miserablesGraph

by

        graph =
            Graph.mapContexts initializeNode miserablesGraph
                |> Graph.update 1 (Maybe.map (updateNode ( 123, 123 )))
                |> Graph.update 2 (Maybe.map (updateNode ( 123, 123 )))

Better version of Interpolation.list

We could make add and delete options to be a -> Interpolator (Maybe a), with Nothing indicating their absence in the resulting list.

We should also make the list ordered by default where order would be interpolated properly.

ListCombiner is kind of dumb, we should just accept a List (Interpolator a) -> Interpolator (List a) function

Finally, we could make all the options (except id) actually optional, since

{ add = \v -> Interpolation.step Nothing [ Just v ]
, remove = \v -> Interpolation.step (Just v) Nothing
, change = \a b -> Interpolation.step a [ b ]
, combine = Interpolation.inParallel
}

would be pretty decent defaults.

Potentially we could make id optional as well and just treat everything as additions and removals without it, but that sort of seems fairly suboptimal. Or have a way to use == to figure out reorder-ing at least...

Examples improvements?

My intuition is that elm-visualization may be a library that is slightly tricky to use for a beginner for the following reasons:

  1. It requires you to do your own rendering and hence assumes knowledge/skill in SVG programming.
  2. There are no high level functions* (i.e. there is no renderBarChart : List (Float, Float) -> Svg msg) and so you are left to figure out how to glue the functions together on your own.

I attempted to solve (2) by providing a gallery of various examples, so that learners can see some sample code on how to achieve various things.

However, I would like to know:

  • Is this effective?
  • Can the examples be improved to be more didactic?
  • Are common use cases sufficiently covered? Or are we missing some really important use cases?
  • I suspect that there are some examples that should be deleted/merged into one (I'm chiefly looking at all the pie examples).
  • Is the intent clear? Or do people perceive the examples more as a marketing strategy?

So, if you are a user of elm-visualization, please add your experiences. I'll try to come up with a plan of attack later based on feedback.


  • Well except for Axis, which are a bit like that.

Vertical axis labels

Hi and thanks for providing elm-visualization!

It would be great to be able to rotate the labels on the axes.
As a concrete use case, I'm trying to build a bar chart based on the bar chart example (https://code.gampleman.eu/elm-visualization/BarChart/).

Currently, the labels overlap when they're too long, which makes them unreadable.
elm-visualization-overlapping labels

I've tried to rotate the columns individually in SVG by using the rotate(90) transformation in the browser. However, there are two problems with this approach.

  1. The labels are misaligned
  2. There doesn't seem to be a way to do this using the visualization API.

screen shot 2018-06-25 at 1 10 48 pm

I've also tried to apply the rotation transformation to the .tick class in the example. However, then the translation of individual columns doesn't work anymore. Furthermore, this approach applies the transformation to the x and y axis. Finally, the problem with alignment would remain.

screen shot 2018-06-25 at 1 15 50 pm

As a third approach I've limited the size of the labels. In this case some labels turn out to be duplicates, which leads to errors in the rendering:

screen shot 2018-06-25 at 1 19 01 pm

I'd really appreciate any help on this issue.

Cheers,
Peter

Small Improvement to Documentation

Thank you very much for writing this library, it appears to be both practically useful as well as a good education in how to think about charts.

Can I suggest that you have a look at the documentation for Scale? It isn't very clear which of the parameters to the ContinuousScale function is the domain and which is the range. There is a clue in the Scale.time function, where the Posix values must be the domain, but for instance, Scale.linear has the signature Scale.linear: (Float, Float) -> (Float, Float) -> ContinuousScale Float, which is more opaque.

Perhaps an example like:

makeContinuousX : (Float, Float) -> (Float, Float) -> ContinuousScale Float
makeContinuousX domain range =
  Scale.linear domain range

-- Create a scale that maps inputs between 0 and 1 to a range of 100 pixels
makeContinuousX (0,100) (0,1)

Or whatever. I'm sure you'll have a better idea than me!

Stacked bar chart with mouseover

So I'm trying to get my bar chart to display a mouseover, which in it self is not a problem.

Modification of your official stacked bar chart example, notice the String parameter embedded in the second param and the title (from typed svg) call:

column : BandScale String -> ( String, List ( Float, Float, String ) ) -> Svg msg
column xScale ( xAxisLabel, values ) =
    let
        block color ( upperY, lowerY, str ) =
            rect
                [ x <| Scale.convert xScale xAxisLabel
                , y <| lowerY
                , width <| Scale.bandwidth xScale
                , height <| (abs <| upperY - lowerY)
                , fill (Fill color)
                ]
                [ title [] [ text str ] ]
    in
    g [ class [ "column" ] ] (List.map2 block colors values)

But how do I get the data I want to display in the tooltips?

column is called like this in your example

List.map (column xScale) (List.map2 (\a b-> ( a, b )) xAxisLabels scaledValues)

So I changed

scaledValues =
            List.map (List.map (\( y1, y2 ) -> ( Scale.convert yScale y1, Scale.convert yScale y2, "this will get displayed" ))) transposedValues

but how do i get the transposedValues or values to still have the original values?

I suspect Stackresult needs to be changed to not only generate yLower and yUpper but also an original value to handle this gracefully?

ForceDirectedGraph example: node does not follow mouse on drag.

Clicking on a circle results the circle to be displaced with some offset from the mouse.
This offset gets larger as the drag coordinates get larger.
So at (x:0, y:0) the circle is located at the position of the mouse, for larger coordinates this is no longer the case. This offset getting larger implies the drag coordinates are erroneously multiplied by some factor.

I looked around somewhat but could not find the cause of this bug.

image
image
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.