Continual RESTful request to JSON on server, parse on the fly, render data inside P5js draw loop.

edited December 2015 in p5.js Library Questions

Hi All, I am doing an agent-based model in Go (golang.org). I am a final year CS student working on a research project for in conjunction with researchers in the Biology department at my university.

I need a web-client viewport which will render the 'state' (i.e. position etc) of each agent within the 2D environment which is handled on the server. There are tens of thousands of agents (potentially millions) which necessitates a true concurrent programming and runtime environment (hence why I am doing it in Go) – this is way too much overhead to be done entirely in a sketch or even dynamically on the client side. Therefore the actual drawing is offloaded to the client, but all the computation (beyond JSON unmarshalling and coordinate translation to the world space of the sketch/viewport) is done on a dedicated server.

I also come from art school prior to going into computer science, and I really like Processing/P5 as it directly gives you the drawing/animation environment and nothing else (unless you want to go digging under the hood). It's much faster to iterate and get what you want on screen. I know what I want to do can be done in HTML5 canvas only, or in Javascript + CSS but it's unnecessarily laborious and P5 has all the drawing functionality I need with a very easy to use API. Learning one language (Go) for this project is more than enough for me.

What I want to draw inside a sketch (viewport) is very simple: points, with varying stroke widths and colours. That's it. I just need to draw tens of thousands of them constantly, updating as they change position. All the computation which determines where those points are before being drawn is delivered via a JSON from the server. What I need is for the P5 sketch to do a bit of translation from the JSON object into some (predeclared and global) arrays of x,y pairs and just draw points at those coordinates by iterating through the said arrays. I don't need to block draw() from being called until the GET request is filled and the JSON has been processed, it should just render the contents of the arrays in the state they currently are in. So, there are two continual processes occurring by the client.

FIRST: LOOP( requesting the JSON data, processing it) SECOND: DRAW LOOP.

Anyone have any experience with something like this? Maybe there is a better and simpler way to do it?

I would say that the obvious alternative would be to bypass the seperate request for the JSON entirely and just have a web socket open so you are directly getting the array data from a function call inside the draw loop. I.e. via http you get the iteration range, then a value for the co-ordinates of each point... hmm.... It doesn't matter that this will slow down the framerate at all by waiting for the requests. I just need the easiest way to get the co-ordinates into memory to be drawn in the sketch.

Answers

  • Sounds interesting, but also far from simple: have you estimated the amount of data you'd have to throw across the network to keep all those points updated?

    Someone somewhere (will try and dig out a link) is working on parsing JSON on the fly (i.e. before it's fully loaded); but, even with that ability, loading JSON files over standard HTTP is surely going to be way too slow. I'd go straight for a websocket solution...

    In terms of doing this with p5js - I feel bad saying this - but I don't think it's up to the scale you describe just yet. There is now WebGL support which does make a massive difference in 2d performance; but for what you describe I'd look at pixijs. It's focused specifically on fast 2d rendering, includes optimisations for large numbers of particles and claims to be the fastest 2d JS library out there.

    From my recent experiments porting an old Java Processing sketch, pixijs definitely seems quicker than p5js (as in able to support a larger number of particles without slowdown). My first attempt in p5js was painfully slow; but that was before WebGL support. To be fair I've only just gone back to it and switched it over to WebGL and I need to optimise it to match the code I implemented in pixijs; but the implementation in pixijs just seemed so much more straightforward; and I'm currently doubtful the p5js will be as performant...

  • Answer ✓
  • Hi Blindfish, I have looked at PIXI but it's so hard to actually get it drawing and know if it's going to work without creating a web server instance. You can't use it in a CodePen properly, I could play with it using Brackets but live preview doesn't work with the OS X version. Also, it is so much more verbose than P5js, the amount of lines just to get anything drawing is painful, and the logic of staging things is confusing. I spent the last two days looking over the different APIs, the reason I chose P5js is that it had WebGL support like PIXI and it is easy. It's not the important part of the research, the modelling of the agents is. So, draw performance is an optimisation problem, I just want the simplest way to get it visualised in a browser. I have no doubt PIXI is more performant, I just want the drawing programming to be painless considering what I want to draw is so simple.

    I think you are right about using web sockets though. I appreciate your candour and advice.

  • Hi GoToLoop, thanks for the straightforward information. I can see how I can use it to block the drawing until the JSON loading is complete. It may not be perfect, but it seems like it will work.

  • edited December 2015

    @bisr: Once you get your head round pixi it's actually pretty straightforward. Drawing operations may be verbose; but sometimes more verbose code is more optimal... pixi does rely on using sprites for speed though; but in your case you could either pre-bake drawing operations into a texture or prepare them in advance in a graphics package...

    For the sake of comparison check out the source of my ported sketch compared to the p5js version. The latter is old code and still needs reworking (to apply optimisations I figured out in the pixi version)

  • @bisr: I've just pushed my updated/optimised p5js code and you'll see there's not a great deal of difference in the particle code. There's a little more set-up work with pixi; but it's not overwhelming.

    Here's the pixi version in action running comfortably with 9072 particles (just wave the mouse over the image).

    Even reducing the particle count to 2240 the p5js version is struggling at a quarter the framerate on my admittedly slow net-top...

    This is in no way meant to be a criticism of p5js: it just demonstrates that for the task you describe pixijs is a better choice in terms of performance; if you're willing to face the (IMO) reasonable learning curve.

  • edited December 2015

    Tried the whole day to speed up your p5.js sketch version, @blindfish.
    But didn't have many significant bottlenecks. :\">

    In p5.js, each p5.Image & p5.Renderer is a full blown HTMLCanvasElement:
    https://developer.Mozilla.org/en-US/docs/Web/API/HTMLCanvasElement

    Therefore the 1st obstacle is survive thru' this dreadful loop:

    for (var block, x, y = 0; y != rh; ++y)  for (x = 0; x != rw; ++x) {
      block = img.get(x*DIAM, y*DIAM, DIAM, DIAM);
      particles[y*rw + x] = new Particle(x*DIAM + RAD, y*DIAM + RAD, block);
    }
    

    W/ DIAM = 8, it just halts my PC for some seconds.
    But DIAM = 5 can consume all my laptop's 4 GB and almost crash the OS! :-SS

    If the sketch reaches the main draw() callback loop, memory goes down to some saner amount.
    But performance now varies a lot among major browser families. :-S

    To my surprise, SlimJet (Chrome-based) had the worst performance by even halting the browser when the picture is still whole.

    Both Waterfox & Cyberfox (Firefox-based) had good performance w/ DIAM = 8.

    And another surprise, IE11 had above expectation performance!
    Even the loop part seemed faster on it! B-)

    In this refactored version I've included confirm() for WEBGL or P2D renderers.
    But WEBGL only works w/ <script src=https://cdnjs.CloudFlare.com/ajax/libs/p5.js/0.4.5/p5.js></script>;.
    Anything past that version is crashing when using image() w/ p5.Image, dunno why... :-??

    Well, I've hosted it online too @ http://p5js.SketchPad.cc/. Check it out: :D
    http://p5js.ProcessingTogether.com/sp/pad/export/ro.C7yI5n-rAMHkBH
    http://p5js.SketchPad.cc/sp/pad/view/ro.80gqevzuan$/latest

  • @ version 2.3 after some tweaks, changed DIAM to 6.
    Now it's 4050 square blocks representing together the whole p5.Image.
    Still I don't dare to set DIAM to 5 in my laptop here.
    And avoid Chrome family browsers to run it. 8-X

  • @GoToLoop: running the pixi version locally via a Brackets preview (i.e. Chrome) I start to see noticeable slowdown (i.e. only 10-20fps when active) when I reduce particle size to 3 (that's 16200 particles). At size 2 (36450 particles) I'm down to 10-15fps. I can reduce the size down to 1 (146250 particles!) and it will run; but at a painful max of about 3fps...

    This is on an old Acer Revo 3610 nettop (Atom processor with nVidia ION chipset) running Peppermint Linux. Pixijs is optimised to use the GPU and it really shows compared to p5js. Obviously the trade-off is that the particleContainer that allows you to run that many particles also limits what can be done with them (e.g. some filters can't be applied); so it's not a like-for-like comparison.

  • edited December 2015

    B/c you're on some Atom CPU nettop, but w/ a reasonable powerful ION GPU, WebGL is always gonna be faster for ya.
    In my AMD 2.2 GHz quad-core CPU, there's not much diff. whether I'm running at renderer P2D or WEBGL. I have the impression P2D is slightly faster!
    As said I can't use DIAM < 6 b/c in p5.js every single p5.Image is a behemoth HTMLCanvasElement and swallows all my 4GB RAM while creating them! ~X(

Sign In or Register to comment.