Search code examples
pythonubuntumatplotlibplotxming

Recurring problem with plotting graphs in WSL Ubuntu


I am writing a code that should graph a simple function, and it temporarily works, but I keep encountering this cycle of problems when I restart my computer:

  1. The first time I try running the code, it doesn't send out any errors, but neither does it create any graphs.

--> To solve this, I installed Xming and wrote the export DISPLAY=localhost:0.0 command in bash, as suggested by AwokeKnowing in Show matplotlib plots in Ubuntu (Windows subsystem for Linux).

  1. When I run the code, with the above adjustments, I get the following Error:
_tkinter.TclError: no display name and no $DISPLAY environment variable.

--> To solve this, I add the line of code:

matplotlib.use('Agg')

as proposed by Serenity in _tkinter.TclError: no display name and no $DISPLAY environment variable

  1. After doing this, and running the code, initially graphs properly. But if I try again another day, it doesn't. The code runs normally, but no graph is displayed.

--> To make it work, I remove the line of code:

matplotlib.use('Agg')

And by doing this, the code graphs again.

Then, when I restart my computer, the sequence of problems starts all over again.

Does anyone know what I'm doing wrong? I am very new with using Python, so it is very possible that I am missing something obvious.

Here are the relevant parts of my code:

#Imports
import matplotlib
import matplotlib.pyplot as ply
from dolfin import *
import numpy as np
from mshr import *
import math
from math import exp

plt.plot(tiemporeal,fcmM1)
plt.xlabel('Tiempo')
plt.ylabel('Resistencia')
plt.show()

Thanks a lot, and sorry for possible formatting mistakes.

PS. I am using Python3 on Ubuntu.


Solution

  • For legacy WSL it should suffice to add

    export DISPLAY=127.0.0.1:0
    

    to your ~/.bashrc file - the default backend should then work properly. For WSL 2 it is more complicated, you need to get the name of the server from /etc/resolv.conf and then the mask from ifconfig. For example on my system:

    wmiller@lcl:~$ cat /etc/resolv.conf
    # This file was automatically generated by WSL. To stop automatic generation of this file,
    # add the following entry to /etc/wsl.conf:
    # [network]
    # generateResolvConf = false
    nameserver 172.28.176.1
    

    and

    wmiller@lcl:~$ ifconfig | grep 'inet '
            inet 172.28.176.7  netmask 255.255.240.0  broadcast 172.28.191.255 
            inet 127.0.0.1  netmask 255.0.0.0
    

    So my DISPLAY needs to be 172.28.176.7:240.0. This gets slightly complicated to extract automatically, but adding the following command to ~/.bashrc works for me:

    export DISPLAY=$((ifconfig | grep -f <(cat /etc/resolv.conf | grep nameserver |
                      awk -F'[. ]' '{print $2"."$3}') | awk '{for(i=1; i <=NF; i++) 
                      {if($i == "inet") print $(i+1)}}' ; ifconfig | 
                      grep -f <(cat /etc/resolv.conf | grep nameserver | 
                      awk -F'[. ]' '{print $2"."$3}') | 
                      awk '{for(i=1; i <=NF; i++) {if($i == "netmask") print $(i+1)}}' | 
                      awk -F'.' '{print $3"."$4}') 
                     | tr "\n" " " | awk '{print $1":"$2}')
    

    In either case you may also need to disable access control in your xserver client - I'm not sure about Xming but vcxsrv simply requires the commandline argument -ac or to check Disable Access Control during launch. You will also need to ensure that the windows firewall is permitting the connections. You may find this thread useful.

    Also note that 'Agg' is a non-gui backend, using it will not display figures. I find that with my setup 'TkAgg' works best.