Skip to main content

Release notes *2.5.9*

ยท 4 min read

It contains the major improvements for NeuralNet standard package, provides more features for graphics and insets. We also fixed many bugs in wljs-export-html and in WXF deserializer. New examples are available in Animation folder.

Download original notebook

const balloonContainer = document.getElementById("balloon-container");

function random(num) {
  return Math.floor(Math.random() * num);
}

function getRandomStyles() {
  var r = random(255);
  var g = random(255);
  var b = random(255);
  var mt = random(200);
  var ml = random(50);
  var dur = random(5) + 5;
  return `
  background-color: rgba(${r},${g},${b},0.7);
  color: rgba(${r},${g},${b},0.7); 
  box-shadow: inset -7px -3px 10px rgba(${r - 10},${g - 10},${b - 10},0.7);
  margin: ${mt}px 0 0 ${ml}px;
  animation: float ${dur}s ease-in infinite
  `;
}

function createBalloons(num) {
  for (var i = num; i > 0; i--) {
    var balloon = document.createElement("div");
    balloon.className = "balloon";
    balloon.style.cssText = getRandomStyles();
    balloonContainer.append(balloon);
  }
}

function removeBalloons() {
  balloonContainer.style.opacity = 0;
  setTimeout(() => {
    balloonContainer.remove()
  }, 500)
}

createBalloons(10);
setTimeout(removeBalloons, 15000);

return '';

Insetโ€‹

An update for Inset expression

Now you can put any expression on top of your Graphics object. Please, make sure this expression supports WLJS Execution Enveroment (see top line of reference )

For example

Plot[x, {x,0,10}, Epilog->{Inset[EditorView["(*FB[*)((1)(*,*)/(*,*)(2))(*]FB*)"], {3,5}, {10,30}, {1,3}]}]
(*VB[*)(FrontEndRef["3ca22e97-4a4d-4068-b58a-dc793fdfd51b"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKGycnGhmlWprrmiSapOiaGJhZ6CaZWiTqpiSbWxqnpaSlmBomAQCF1hYI"*)(*]VB*)

Or even put a mermaid diagram using virtual cells

mermaid = CellView["graph LR
    A[Square Rect] -- Link text --> B((Circle))
    A --> C(Round Rect)
    B --> D{Rhombus}
    C --> D", "Display"->"mermaid"];
Plot[x, {x,0,10}, Epilog->{Inset[mermaid, {2,5}, {10,30}, {7,4}]}]
(*VB[*)(FrontEndRef["a0bb8b0e-c9e3-4c62-8ce0-b72f9844cf6f"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKJxokJVkkGaTqJlumGuuaJJsZ6VokpxroJpkbpVlamJgkp5mlAQCR6BY5"*)(*]VB*)

Slides now supports scriptsโ€‹

All inline JS scripts provided in slide cells will be executed. Use them for whatever ideas you come up with.

Tube now supports dynamicsโ€‹

3D graphics primitive Tube now can be coupled to a dynamic symbol, as an example check this out ๐Ÿ˜‰

(*BB[*)(* Just run this cell *)(*,*)(*"1:eJxTTMoPSmNhYGAo5gcSAUX5ZZkpqSn+BSWZ+XnFaYwgCS4g4Zyfm5uaV+KUXxEMUqxsbm6exgSSBPGCSnNSg9mAjOCSosy8dLBYSFFpKpoKkDkeqYkpEFXBILO1sCgJSczMQVYCAOFrJEU="*)(*]BB*)
RandomIntegerVectorWithinBox[min_List, max_List] := Table[
  RandomInteger[{min[[i]], max[[i]]}],
  {i, Length[min]}
]

PositionKey[pos_] := ToString[pos]

WithinBoundsQ[pos_, gridMin_, gridMax_] := And @@ Thread[pos >= gridMin] && And @@ Thread[pos <= gridMax]

IsUnoccupied[pos_, occupiedPositions_] := ! KeyExistsQ[occupiedPositions, PositionKey[pos]]

(* Main function to simulate a pipe *)
SimulatePipe[] := Module[
  {
    gridMin = {-10, -10, -10},
    gridMax = {10, 10, 10},
    occupiedPositions = <||>,
    currentPosition,
    positions,
    lastPosition,
    lastDirectionVector = Null,
    directionVector,
    newPosition,
    axis,
    dir,
    possibleDirections,
    triedDirections,
    moveMade
  },
  
  (* Initialize the starting position *)
  currentPosition = RandomIntegerVectorWithinBox[gridMin, gridMax];
  positions = {currentPosition};
  occupiedPositions[PositionKey[currentPosition]] = True;
  
  (* Simulate the pipe growth *)
  Function[Null,
    
    (* Initialize possible directions *)
    possibleDirections = {
      {1, 0, 0}, {-1, 0, 0},
      {0, 1, 0}, {0, -1, 0},
      {0, 0, 1}, {0, 0, -1}
    };
    
    (* Prioritize continuing in the same direction *)
    If[lastDirectionVector =!= Null && RandomReal[] < 0.5,
      (* Try to continue in the same direction *)
      directionVector = lastDirectionVector;
      possibleDirections = Prepend[DeleteCases[possibleDirections, directionVector], directionVector];,
      (* Shuffle possible directions *)
      possibleDirections = RandomSample[possibleDirections];
    ];
    
    triedDirections = {};
    moveMade = False;
    (* Try each possible direction *)
    Do[
      directionVector = dir;
      newPosition = currentPosition + directionVector;
      If[
        WithinBoundsQ[newPosition, gridMin, gridMax] && IsUnoccupied[newPosition, occupiedPositions],
        (* Valid move found *)
        positions = Append[positions, newPosition];
        occupiedPositions[PositionKey[newPosition]] = True;
        lastDirectionVector = directionVector;
        currentPosition = newPosition;
        moveMade = True;
        Break[];
      ];
      AppendTo[triedDirections, dir];
      ,
      {dir, possibleDirections}
    ];
    
    If[!moveMade,
      (* No valid moves, terminate simulation *)
      $Failed
    ,
      positions
    ]

    
  ]
  
]


With[{
  frame = CreateUUID[],
  win = CurrentWindow[]
},
  Module[{
    pipeFunction = Function[Null, $Failed],
    pipesNumber = 0,
    trigger = 1
  },

    EventHandler[frame, Function[Null,
      With[{
        result = pipeFunction[]
      },
        If[FailureQ[result],
          With[{
            segments = Unique["pipe"],
            generator = SimulatePipe[]
          },
            pipesNumber++;
            pipeFunction = Function[Null,
              With[{seg = generator[]}, 
                If[FailureQ[seg],
                  $Failed
                ,
                  segments = seg // N;
                ]
              ]
            ];

            pipeFunction[];

            FrontSubmit[{
              ColorData[97][pipesNumber],
              Tube[segments // Offload, 0.2]
            }, MetaMarker[marker], "Window"->win];
          ]
        ]
      ];

      trigger++;
    ]];
    

    Graphics3D[{
      Opacity[0], Cuboid[{-4,-4,-4}, {4,4,4}], Opacity[1], MetaMarker[marker],
      AnimationFrameListener[trigger // Offload, "Event"->frame]
    }]
  ]
]

Neural Networksโ€‹

We have finally added partial support for NeuralNet package. You can see training progress, representations of different layers and etc

(*BB[*)(* try this one *)(*,*)(*"1:eJxTTMoPSmNhYGAo5gcSAUX5ZZkpqSn+BSWZ+XnFaYwgCS4g4Zyfm5uaV+KUXxEMUqxsbm6exgSSBPGCSnNSg9mAjOCSosy8dLBYSFFpKpoKkDkeqYkpEFXBILO1sCgJSczMQVYCAOFrJEU="*)(*]BB*)
trained = 
 NetTrain[LinearLayer[], {1 -> 1.9, 2 -> 4.1, 3 -> 6.0, 4 -> 8.1}]
trained[3]
6.04994535446167`

NetGraph is not supported as well as some icons. We need volunteers to work on it ;) Please contact us if you know something about ML and Wolfram Language Graphics.

net = NetModel["LeNet Trained on MNIST Data"]
(*VB[*)temporalStorage$145507(*,*)(*"1:eJwlkc1ymlAAhWmni06foslKoTNC0AvpTBb8KgISufyImSxALoLgRZErwmP0iWPSzTdnzu585yGp3ew7RVGXX3doadHWTVCgDv77RlEr1Cp5XOC3ER3Ib/T494j+Q49H9CP3Fy17rvQ566ZJdk6um7WriUoLxCQik3UiN2Ta6FZ13RZd4XhW7QwKhB5GfPrKX71DyxiZX6BFiWcaRrmNT5rImwKUjHNhYx/EVVmogw4uxpk3sdSnTlSd8c1JbvsK76Wj6857Z7pDVQ+APdv6ZlIvu6ZtNusF6QCBRsswSqhZAjzG58uC58VkZwqi4Os2hzrzGu3mg2jlicB2WllUcENAUg1zNvQYdWo+8VubKG6aghbXe51Z+GHiuRAxcbpayblEOCNQHe1UBvF0rlmT7el2jiBrH4+Ruc6k7HblUajLp0OQC7PVQV0aM2UC7tPDmMuP5kRhVWNZZumzUwrNRc+a5wS4kzBXeqDrd0mS8loP04jHrck+7V9eHj+dvwcyPX7/f9WPO1xSIfjzM6A4dXDVf7VeQ9AH8nGRcw=="*)(*]VB*)
net[(*VB[*)(FrontEndRef["7c52eb9d-6d46-4b1d-ab0a-a2043d2ccccc"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmyebGqUmWabomqWYmOmaJBmm6CYmGSTqJhoZmBinGCWDAACODxZ6"*)(*]VB*)]
5

ok, kinda looks like 5

Some other examples

layer = NetInitialize @ LinearLayer[2, "Input" -> 2]
LinearLayer[(*VB[*) <|"Type" -> "Linear", "Arrays" -> <|"Weights" -> NumericArray[{{-0.3594474792480469, -0.04992305114865303}, {-1.127055048942566, 1.086535930633545}}, "Real32"], "Biases" -> NumericArray[{0., 0.}, "Real32"]|>, "Parameters" -> <|"OutputDimensions" -> {2}, "$OutputSize" -> 2, "$InputSize" -> 2, "$InputDimensions" -> {2}|>, "Inputs" -> <|"Input" -> NeuralNetworks`TensorT[{2}, NeuralNetworks`AtomT]|>, "Outputs" -> <|"Output" -> NeuralNetworks`TensorT[{2}, NeuralNetworks`RealT]|>|>, <|"Version" -> "14.1.2", "Unstable" -> False|> (*,*)(*"1:eJytUMsKwjAQrI+LXgQ9CJ7qL3j0ptBiQSy00rORbCWQbGSboEX8d9NUqVfBy7A7M8sMuzzrrBwEQVAtHGz1PdakThsihhfguVWKUe3ostd4Jg5i0mgi5IUgY5lshaGDnZbcDweNUPY/9F5UpjP5zWvzr7x3TmJAFQJu+cxpqTVXa0IuFGAlNFbrsD0cO4i4MJq8tyn/WD27wMxKyEfNAIzXKcra00ey8GuPqdMS/HuN9ktWyhcQzmJg"*)(*]VB*)]
NetExtract[LinearLayer[(*VB[*) <|"Type" -> "Linear", "Arrays" -> <|"Weights" -> NumericArray[{{-0.3594474792480469, -0.04992305114865303}, {-1.127055048942566, 1.086535930633545}}, "Real32"], "Biases" -> NumericArray[{0., 0.}, "Real32"]|>, "Parameters" -> <|"OutputDimensions" -> {2}, "$OutputSize" -> 2, "$InputSize" -> 2, "$InputDimensions" -> {2}|>, "Inputs" -> <|"Input" -> NeuralNetworks`TensorT[{2}, NeuralNetworks`AtomT]|>, "Outputs" -> <|"Output" -> NeuralNetworks`TensorT[{2}, NeuralNetworks`RealT]|>|>, <|"Version" -> "14.1.2", "Unstable" -> False|> (*,*)(*"1:eJytUMsKwjAQrI+LXgQ9CJ7qL3j0ptBiQSy00rORbCWQbGSboEX8d9NUqVfBy7A7M8sMuzzrrBwEQVAtHGz1PdakThsihhfguVWKUe3ostd4Jg5i0mgi5IUgY5lshaGDnZbcDweNUPY/9F5UpjP5zWvzr7x3TmJAFQJu+cxpqTVXa0IuFGAlNFbrsD0cO4i4MJq8tyn/WD27wMxKyEfNAIzXKcra00ey8GuPqdMS/HuN9ktWyhcQzmJg"*)(*]VB*)], "Weights"] // Normal
{{-0.3594474792480469`,-0.04992305114865303`},{-1.127055048942566`,1.086535930633545`}}

Support for custom CSSโ€‹

Open your settings and add any styles you want. This is a new step towards customization

Try this one

Print[Style["Hey", Red, 14]]
(*BB[*)("Hey")(*,*)(*"1:eJxTTMoPSmNiYGAo5gcSAUX5ZZkpqSn+BSWZ+XnFaYwgCRYg4ZGfkwJRxgkkgkuKMvPSnfIr0phBQhxAIsjdyTk/J78oE6QlkwFO8AEJiEaQMUGlOanBbHATwGIhRaWpAL9wHBA="*)(*]BB*)

You can also print Graphics if needed

Offset support for labelsโ€‹

It was always a bit of a pain to fight agains FrameLabel or AxesLabel and trying to position them. We extended the API for this (Mathematica does not have this feature)

Plot[PDF[NormalDistribution[0, 1], x], {x, -10, 10}, AxesLabel -> {
  {"wavenumber (cm^{-1})", {-100,-15}}, 
  {"absorption \\alpha", {112,0}}
}, PlotRange->Full]
(*VB[*)(FrontEndRef["257a6bab-bb74-4016-b624-a40b453a2e63"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKG5maJ5olJSbpJiWZm+iaGBia6SaZGZnoJpoYJJmYGicapZoZAwCDIRVZ"*)(*]VB*)

Support for Entity and Quantityโ€‹

We recreated boxes for them

Quantity[1, "Millimeters"/"Seconds"]
(*VB[*)(q)(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KWlMIB43kAgsTcwrySypdMqvyAQpgciwAomQzNzU4mCQGt/MnBwgpyS1qBghHZBfnloUzA5kBacm5+elFGf+BwIA5ecbxA=="*)(*]VB*)
Entity["Country", "Germany"]
(*VB[*)(Entity["Country", "Germany"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KWlMIB4nkHDNK8ksqXTKrwhmB/Kc80vzSooqwWz31KLcxLxKAJLGDq8="*)(*]VB*)
%["Population"]
(*VB[*)(q)(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KWlMIB43kAgsTcwrySypdMqvyFzA950lmA0oGJCaX5CTCgBVHw3o"*)(*]VB*)

Support for SystemOpenโ€‹

Works only if use our desktop application (not a console version)

SystemOpen[NotebookDirectory[]]

Better Audio supportโ€‹

We also added a new snippet in the command palette

Record Voice

(*VB[*)(Notebook`Editor`Kernel`PCMAudio`Internal`dump$112924)(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmyamJKUkmZnpJhoYJuqamKWY6CYmmVvqmpoYJZoYWBoaGpsmAwCODRWP"*)(*]VB*) // AudioPlot
(*VB[*)(FrontEndRef["fc127432-1b30-420d-b760-f91b0846329e"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKpyUbGpmbGBvpGiYZG+iaGBmk6CaZmxnoplkaJhlYmJgZG1mmAgB2gxTV"*)(*]VB*)

External APIโ€‹

We know, that normally libraries for Wolfram Language are distributed as WL Packages or paclets, which do not have support for shipping Javascript / CSS files and etc.

Now it is possible to inject them in a runtime, you have to do it only once

FrontEndRuntime[{"Modules", "js"}] = Append[FrontEndRuntime[{"Modules", "js"}], File["path to your JS"]] 

See docs for more information

To check if a code is running with WLJS frontend, you can check this system variable

Internal`Kernel`WLJSQ
True

Ballon animation by Jemima (codepen)