WSL2 comes with WSLg enabled by default. WSLg allows you to run graphical linux applications.
To check that you have the latest package lists, type:
sudo apt update
Then, start with some basic X11 applications:
sudo apt install x11-apps
To run the xeyes, a “follow the mouse” application, type:
xeyes &
The & at the end of the line will execute the command asynchronously. In other words, the shell will run the command in the background and return to the command prompt immediately.
The first launch of a GUI application takes a few seconds while WSL is initializing the graphics stack. Next executions of GUI applications are much faster.
Leave xeyes opened and run the calculator xcalc with:
xcalc
When you move the cursor over the calculator, xeyes follows the cursor. This shows that several GUI applications can interact together.
Note that applications running under WSLg display a little penguin at the bottom right corner of their icons in the Windows taskbar. That’s one way you can distinguish applications running on Windows or Ubuntu (besides the window decoration and styling).

Close xeyes and xcalc by pressing the cross icon on the top right corner of each X application window.
Xcalc and xeyes are very basic X Windows applications but there are plenty of choices in the Linux ecosystem corresponding to your needs and available out of the box on Ubuntu.
In the following example, we will use GNU Octave to perform numerical computation.
We will use it to calculate and draw a beautiful Julia fractal. The goal here is to use Octave to demonstrate how WSLg works, not to go through the theory of fractals.
First thing is to install the software like we did for x11-apps, from the terminal prompt run:
sudo apt install octave
Then start the application:
octave --gui &
Do not forget the ampersand & at the end of the line, so the application is started in the background and we can continue using the same terminal window.
In Octave, click on the New script icon to open a new editor window and copy/paste the following code:
#{
Inspired by the work of Bruno Girin ([Geek Thoughts: Fractals with Octave: Classic Mandelbrot and Julia](http://brunogirin.blogspot.com/2008/12/fractals-with-octave-classic-mandelbrot.html))
Calculate a Julia set
zmin: Minimum value of c
zmax: Maximum value of c
hpx: Number of horizontal pixels
niter: Number of iterations
c: A complex number
#}
function M = julia(zmin, zmax, hpx, niter, c)
%% Number of vertical pixels
vpx=round(hpx*abs(imag(zmax-zmin)/real(zmax-zmin)));
%% Prepare the complex plane
[zRe,zIm]=meshgrid(linspace(real(zmin),real(zmax),hpx),
linspace(imag(zmin),imag(zmax),vpx));
z=zRe+i*zIm;
M=zeros(vpx,hpx);
%% Generate Julia
for s=1:niter
mask=abs(z)<2;
M(mask)=M(mask)+1;
z(mask)=z(mask).^2+c;
end
M(mask)=0;
end
This code is the function that will calculate the Julia set.
Save it to a file named julia.m. Since it is a function definition, the name of the file must match the name of the function.
Open a second editor window with the New Script button and copy and paste the following code:
Jc1=julia(-1.6+1.2i, 1.6-1.2i, 640, 128, -0.75+0.2i);
imagesc(Jc1)
axis off
colormap('default');
This code calls the function defined in julia.m. You can later change the parameters if you want to explore the Julia fractal.
Save it to a file named juliatest.m.
And finally, press the button Save File and Run.

After a few seconds, depending on your hardware and the parameters, a Julia fractal is displayed.

Like Octave, this window is displayed using WSLg completely transparently to the user.
Enjoy!