juliaanimators / javis.jl Goto Github PK
View Code? Open in Web Editor NEWJulia Animations and Visualizations
Home Page: https://juliaanimators.github.io/Javis.jl/stable/
License: MIT License
Julia Animations and Visualizations
Home Page: https://juliaanimators.github.io/Javis.jl/stable/
License: MIT License
Currently Javis processes a set of actions over a certain set of frames. However for certain applications it might be preferable to give the user control over rendering loop if he wants to write into several files in parallel and it might help with consistent frame rates for live streaming too.
A Javis would be called and return after preparing/rendering a single/(fixed number of) frame. It would preferable if it also kept all the framebuffers etc allocated not unlike Integrator Interface from the DiffEq eco system. ( https://diffeq.sciml.ai/release-5.0/basics/integrator.html )
I think it would be nice to let something be drawn like a polygon line by line or let it appear from the background by blending in.
Blending in can be change in opacity or line thickness.
In some projects maintainers have a different future goal than the users. We should state our goals somewhere probably in the documentation.
Need to add a tutorial on LaTeX.
We messed something up by a bit as we allow not defining the frames when one wants to use the same frames as the action before.
As both frames
and id
are Symbols it is not possible to write
Action(1:100, ground)
Action(:id, (args...)-> 1)
one needs to write
Action(1:100, ground)
Action(:same, :id, (args...)-> 1)
which is a bit odd and the error message is also not extremely nice. So we want to check if the symbol specified is :same
and if not check whether the next argument is also a symbol. If that is the case like in
Action(1:100, ground)
Action(:typo, :id, (args...)-> 1)
we throw an error.
In this case:
Action(1:100, ground)
Action(:id, (args...)-> 1)
we interpret it as:
Action(1:100, ground)
Action(:same, :id, (args...)-> 1)
Regarding #22 where we discuss an easier way of defining frames.
Actually we might want to just define them as animations:
See https://jkrumbiegel.github.io/Animations.jl/stable/
What do you think about:
Action(anim, (args...)->line(O, Point(10,20), :stroke))
where anim is:
Animation(1, Translation(O), sineio(), 30, Translation(Point(20, 50))
but this might be a bit confusing so we should define short hands for it like
Action([1, Translation(O), sineio(), 30, Translation(Point(20, 50)], (args...)->line(O, Point(10,20), :stroke))
or
Action(1:30, sineio, (args...)->line(O, Point(10,20), :stroke), Translation(O, Point(20, 50))
to define a simple animation.
Additionally I'm wondering whether the Translation
should be in front of the function as this is the order of execution.
Is your feature request related to a problem? Please explain.
Currently the color information is lost when morphing and the only action that works is stroke but not fill.
Describe the solution you'd like
A better way to morph around with all those features 😄
After a discussion between @Wikunia and I, we realized that though Graphs would be amazing to implement, it is beyond the scope of the release of the first version of Javis. Some notes from our conversation before I forget:
- Graphs are extremely difficult to visualize but yeah we should have something that works on small graphs
- I think it's preferred to not define our own graph structure though. Have a look at: https://github.com/JuliaGraphs/LightGraphs.jl instead and think only about how one can visualize them
- Maybe https://juliagraphs.org/LightGraphs.jl/stable/plotting/ is interesting
- The difficulty comes from deciding the layout such that there are not that many overlapping edges etc
- We might want to start with a way to let the user fully specify the layout instead of an automatic version (@Wikunia , could you explain this thought a bit more before we forget the conversation? Thanks!)
Right now, this issue will not be worked on but we hope to someday.
During the stream something weird/unexpected (okay let's call it a bug non-feature) happened.
using Javis, Luxor
function ground(args...)
background("white")
sethue("blue")
end
function circ(p=O, color=nothing)
sethue(color)
circle(p, 25, :fill)
return Transformation(p, 0.0)
end
function path!(points, pos, color)
sethue(color)
push!(points, pos)
circle.(points, 2, :fill)
end
function dance()
p1 = Point(100,0)
p2 = Point(100,80)
from_rot = 0.0
to_rot = 2π
path_of_blue = Point[]
path_of_red = Point[]
video = Video(500, 500)
javis(video, [
BackgroundAction(1:50, ground, Translation(Point(50, 50), Point(50, 50))),
Action(1:50, :red_ball, (args...)->circ(p1, "red"), Rotation(from_rot, to_rot)),
Action(1:50, (video, args...)->path!(path_of_red, pos(:red_ball), "red")),
], tempdirectory="test/current/images", deletetemp=true, creategif=true, pathname="test/current/dancing.gif")
end
creates:
instead of drawing the path of the red ball correctly. This happens because the transformation from the layer of the red ball is converted into the global coordinate system without considering the translation of the BackgroundAction
.
With v0.1.0 being released in a the next days we should have an issue for ideas for a potential logo.
Manim has a python -m manim --livestream
option and even options for Twitch python -m manim --livestream --to-twitch --with-key [streamkey]
which allow to write the live rendered content to Twitch in real time.
It would be cool to be able to the same from Javis. This functionality might be better suited for a package on top of Javis.
As far as i understand ffmpeg provides that functionality.
General improvement suggestions for the README:
I somehow missed this in one of my PRs 😕
See: https://github.com/Wikunia/Javis.jl/blob/master/src/Javis.jl#L274-L288
This is a bit out of #43
Currently it's only possible do define an Animation like between frame 1:100 draw a line and then we can define and maybe get the position of the line back to do something with it.
It might make sense in same cases to define an Action like this:
Action(1:70, draw_line, SubAction(10, appear), SubAction(50, Translate(50, 50)), SubAction(10, disappear)
Where a SubAction
gets a number of frames and a function so here it would appear for 10 frames then translate the line for 50 frames and then disappear in the last 10 frames.
Does that make sense @TheCedarPrince ?
So I can't use javis which is calling ffmpeg.
I had to install it and set my path. 99% of users won't know how to do it.
Perhaps binarybuilder.jl can help?
I want to help but I may not get to it soon enough.
One big tutorial an all those things. I try to make something fun and maybe use the result of Tutorial one for this.
Would be nice to have a way to convert from a circle to a square like described here:
https://www.youtube.com/watch?v=ABB1qqbesPM
and https://github.com/JuliaGraphics/Luxor.jl/blob/1cdcb74fdfffde264c3f8dfacb84a84e0085f154/docs/src/simplegraphics.md
but for every path to every other path such that
x^2 + y^2 = r^2
can be transformed into a circle somehow 😂
That might look ridiculous but there is only one way to figure it out.
Just some links:
How this can be done in d3.js:
https://github.com/veltman/flubber
https://www.youtube.com/watch?v=PLc1y-gim_0
Due to some miscommunication between Slack, GitHub, and code commits, I am going to solidify the documentation about how to document functions in this codebase.
Going to add best practices we follow to contributing.md
and possibly going to make some additional documentation files if the need arises.
@Wikunia aside from specifying that we will completely document exported functions and minimally document internal functions, is there anything else you can think of to add or clarify?
The documentation for Javis is sparse right now and is not terribly clear in most places. Let's fix that up! I'll be implementing BlueStyle in most of the areas as best is applicable.
o
As mentioned in #72 we might want to support a wider range of subactions like this syntax for rotating:
function circ(p=O, color="black")
sethue(color)
rotate(2π)
circle(p, 25, :fill)
return p
end
video = Video(500, 500)
javis(video, [
Action(1:70, ground; in_global_layer=true),
Action(:same, :red_ball, (args...)->circ(O, "red"); subactions=[
SubAction(:same, animate_transition())
])
])
which can currently be achieved with:
function circ(p=O, color="black")
sethue(color)
circle(p, 25, :fill)
return p
end
video = Video(500, 500)
javis(video, [
Action(1:70, ground; in_global_layer=true),
Action(:same, :red_ball, (args...)->circ(O, "red"), Rotation(0, 2π)),
])
We need to add Javis to the General Julia Registry for the initial release! Do you know what all is involved with getting it added to the registry @Wikunia ?
Currently the defaults for tempdirectory
, deletetemp
, ... are all not the best 😄
I think tempdirectory
should be https://docs.julialang.org/en/v1/base/file/#Base.Filesystem.tempdir or maybe mktempdir
pathname = javid_randomstring.gif
I would remove creategif
and just create a gif
if pathname is not empty. This makes it easy to later set pathname
to filename.mp4
to create a video and possibly we can also remove deletetemp
. 😉
The bug label is coming from this error message:
IOError: could not spawn `rm -rf .`: no such file or directory (ENOENT)
mentioned in slack when using deletetemp
As we are finishing up the Grid lines initial PR, we are already thinking about how to improve it! This is somewhat lower priority currently but will be worked on consistently.
Here were some thoughts @Wikunia and I were thinking about implementing next:
- Have a lighter grid (setline(0.5) or something) and bigger lines every 5 or so steps.
- Have numbers and titles for the axis
- The thing about extensibility using Val for example (see #18)
I also thought of a couple that I was exploring:
If anyone else has any thoughts, feel free to drop a comment/thought! For reference, here is what the current grid lines animation look like:
I have the feeling that defining frames for an Action is probably a tedious task for a full video or a more complex animation.
We should think about different ways like:
:all
for all frames:same
same as the one beforeRel(10:20)
relative to the start of the one before so starting 10 frames after the one before and then going for 11 frames.Currently the user may write:
function circ(p=O, color=nothing)
color !== nothing && sethue(color)
circle(p, 25, :fill)
return Transformation(p, 0.0)
end
but actually might want to return a Point
and without an angle
.
So the user wants to write
function circ(p=O, color=nothing)
color !== nothing && sethue(color)
circle(p, 25, :fill)
return p
end
I actually fail to think about a usage for returning an angle
😄
Maybe create an svg from LaTex and then parse the svg to Luxor.
We would like to have an easy way to define vectors and draw/animate them.
Animation needs:
scaling, moving, rotatating
Definition probably origin
and target
where the origin is O
by default.
I assign you @TheCedarPrince as discussed via Slack
Is your feature request related to a problem? Please explain.
I was experimenting with BackgroundAction
syntax and I was thinking it might be a good idea to extend SubAction
syntax to BackgroundAction
's. Especially for the functions draw_grid
and zero_lines
.
If that is the case, it might make sense to have BackgroundAction
only have access to functions like draw_grid
and zero_lines
and not as a general Action
.
Describe the solution you'd like
What I would love to see as a user interface would be something like this:
BackgroundAction(1:180, ground), subactions = [
SubAction(1:60, draw_grid()),
SubAction(1:60, zero_lines())
]
Also, I am not sure if this should be a separate issue, but I would like to see the grid lines persist after their initial animation such that I could draw on top of them later.
Describe alternatives you've considered
Currently, this would be the way to invoke this functionality:
BackgroundAction(1:180, ground),
Action(1:60, draw_grid()),
Action(1:60, zero_lines()),
It might be nice to provide templates for issues and PRs (definitely for issues) before releasing v0.1.0 as we expect to get some issues in from other users.
This should give information about
For PRs maybe link to contributing.md or maybe GitHub does that. I'm not sure what might be good to put in there.
I have tried to run the test but it failed. Here is what I have done:
git clone https://github.com/Wikunia/Javis.jl
cd Julia.jl
julia
]
dev .
[alotaima@sudomaze ~/Projects/tmp]$ git clone https://github.com/Wikunia/Javis.jl
Cloning into 'Javis.jl'...
remote: Enumerating objects: 154, done.
remote: Counting objects: 100% (154/154), done.
remote: Compressing objects: 100% (102/102), done.
remote: Total 154 (delta 60), reused 115 (delta 36), pack-reused 0
Receiving objects: 100% (154/154), 138.89 KiB | 1.76 MiB/s, done.
Resolving deltas: 100% (60/60), done.
[alotaima@sudomaze ~/Projects/tmp]$ cd Javis.jl/
(On branch master) [alotaima@sudomaze ~/Projects/tmp/Javis.jl]$ julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.4.2 (2020-05-23)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
(@v1.4) pkg> dev .
[ Info: Resolving package identifier `.` as a directory at `~/Projects/tmp/Javis.jl`.
Path `.` exists and looks like the correct package. Using existing path.
Resolving package versions...
ERROR: Unsatisfiable requirements detected for package Luxor [ae8d54c2]:
Luxor [ae8d54c2] log:
├─possible versions are: [0.11.0-0.11.2, 0.12.0, 1.0.0, 1.1.0-1.1.5, 1.2.0, 1.3.0, 1.4.0, 1.5.0, 1.6.0, 1.7.0, 1.8.0, 1.9.0, 1.10.0, 1.11.0, 1.12.0, 2.0.0, 2.1.0] or uninstalled
└─restricted to versions 2.2.0-2 by Javis [78b212ba] — no versions left
└─Javis [78b212ba] log:
├─possible versions are: 0.1.0 or uninstalled
└─Javis [78b212ba] is fixed to version 0.1.0
Julia version:
(On branch master) [alotaima@sudomaze ~/Projects/tmp/Javis.jl]$ julia --version
julia version 1.4.2
I'm not sure whether this should be it's own issue it's somehow related to #64
Let's assume I draw this brain and then I want to rotate the brain. How can I do this?
This seems to be a big probably which is currently in my head.
A different example might make this clearer;
I want to draw a graph with nodes and edges and animate some stuff and then I want to scale it down and move it to a corner of the animation just to still show it and draw something else.
We somehow need to be able to combine actions into a layer than can be accessed later. I neither know a good interface for it nor how to implement it so this is just one idea:
Action(1:100, draw_node(1); subactions=[SubAction(1:20, appear(:fade)], layer=:graph)
Action(1:100, draw_node(2); subactions=[SubAction(1:20, appear(:fade)], layer=:graph)
Action(101:200, layer(:graph), Translate(200, 0)
And it would pick the latest version of that layer then which I think makes sense. Any other ideas just for the user interface @TheCedarPrince ?
for printing text on screen like a line.
text("text", font=DEFAULT_FONT)
Creating a tutorial on how to use actions in Javis.
Currently we support: a UnitRange
, Rel
or a Symbol
or nothing at all.
It might be easier to have a struct Frames
which stores it in UnitRange
and create convert methods for the others.
This way it might be simpler to support the same for SubAction
.
Hey @Wikunia ,
This is an idea I have been thinking about for a bit and I wanted to write it down before I forgot. I am not sure how difficult the idea would be to implement or if it would be wise to implement it in another repository but I think common animations made using Javis
should be offered as templates. This thought spawned off from animation of an 10-20 Electrode EEG Array I made:
The code to make this, though easy to make, took several hours to make and over a hundred lines of code. I would love to provide a method that Javis
could provide which enables a user to load a template that we have curated. Perhaps in the form of something like this Action(:same, :eeg_array, load_template("eeg_array"))
that returns a list of actions needed to make the basic template of the array (i.e. minus the colors).
This is an idea that I don't know how easy it is to implement but I think would be of great benefit for future users. Plus, it would be cool if we could open it up for users to add in their own templates for other users.
If you think it makes sense, I'd be happy to sink some time into this maybe for v0.2.0 or even v0.3.0 (dreaming big here!) as I would certainly like this functionality.
Thoughts?
There are some untested functions which might either get a test case or some might be removed for now (Base.* maybe)
For longer animations it might be useful to provide a progress bar.
No user should ask: "Is it doing something or is it hanging?"
Currently we have the problem that the standard font color is black on a white background.
We can change the color in our ground
(our normal name for the background function which is called as the first action) but it gets into its own layer such that the color is actually not "leaked" to the other layers.
Unfortunately this is normally what the user expects. It's quite easy to have a keyword argument for this to say:
Action(tframes, ground; layered=false)
(maybe there is a better name for it @TheCedarPrince ? )
and then everything inside that action is available in the outside world. This way it's also possible to make a shift of the coordinate system there if one doesn't like to have the origin being in the middle.
Currently the latex
function needs a font size as well as I have no clue whether I can get the font size from Cairo/Luxor. Maybe @cormullion knows 😄
Same is treu for color where it might be helpful to for #15 to morph one shape with a color into another shape with a different color. For this we would need to get the color set in the two function to blend between the two colors.
I want to create a polar coordinates animation similar to this:
(Source: Mesmerizing Looney Tunes GIF by Feliks Tomasz Konczakowski)
Currently, Javis.jl
doesn't have this feature.
Creating a polar coordinates animation
If a drawing function returns something other than a Point
or a Transformation
the user currently can't access it easily.
We might want to have a function val
for that.
Such that
function ret(args...)
return "Bla"
end
Action(1:100, :test, ret)
Action(1:100, (args...)->text(val(:test))
works
Came as a suggestion of @xiaodaigh during the stream today.
Sometimes it might be reasonable to write Translation(Point(x,y))
which does not depend on the frame instead of writing
Translation(Point(x,y), Point(x,y))
so I think it makes sense to have a constructor which takes in one value and just uses that one value as the starting and the end of the animation such that there is no animation. Hope that makes sense 😄
See #32 as an example.
Give a hint how to install it :)
We probably want to make it possible to create mp4
videos easily and not just gif
.
Not sure how VideoIO works but it might be even faster as we don't need to write each frame to a file.
Before I forget my thoughts on this topic, I was chatting with @sudomaze today in a stream and we had a great exchange that is looking far into the future. Not even sure when we could work on this but was thinking it would be wise to write this down to get thinking about it.
It could very well be that this idea is outside the scope of
Javis
but it is at least something to consider.
Is your feature request related to a problem? Please explain.
This feature would be dependent on #41 but the ability to both interop with popular Julia ML packages (e.g. SciML suite, Flux, Zygote, etc.) and create visualizations of neural network visualizations would be fantastic.
Describe the solution you'd like
I'd love to see an out come like this someone could render:
I am not sure how exactly a user interface could look but in broad terms what I was thinking was something like this:
The Javis
would be in the background of the main code. What I mean by this is when I was working with packages like matplotlib
, I would have to ensure the script had specific operability with the package. It really made code reusability difficult. What I imagine is only a few additional lines needed to create powerful visualizations.
Javis
could easily create these visualizations and have full interop with Actions
and SubActions
.
Describe alternatives you've considered
Seems like Alteryx can do something like this as well as TensorBoard. Deep Playground and The Building Blocks of Interpretability are great inspirations.
Besides interpolating between objects as described in #4 we probably want an easy way to move paths from point A to B
Instead of writing something like
for i=1:100
@layer begin
translate(0, i)
DRAWING
end
end
we probably want to have a general move function like
move(obj, from, to, frames, easingfunction)
Determine how to create a gridline animation similar to what is seen here:
(Source: Vectors, what even are they? | Essence of linear algebra, chapter 1 by 3Blue1Brown)
As of now, it is apparent that Luxor.jl
does not possess the ability to make an animation like this
Determine how best to create a gridlines animation using a tool like Luxor.jl
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.