Toggling dark/light GUI mode / changing matplotlib style

107 views
Skip to first unread message

Matthias Brennwald

unread,
Mar 4, 2022, 5:03:00 PM3/4/22
to wxpython-users
Hello

I am working on a program that uses a wx panel with a matplotlib figure. If the user toggles the GUI environment from light to dark mode (or vice versa), the GUI elements provided by wx will follow the change nicely, but the matplotlib figure will not. I am using the 'default' plot styles for matplotlib when my program detects the "light" GUI setting during startup, while the 'dark_background' style is used if the "dark" setting is detected at startup (like this: https://matplotlib.org/3.1.0/gallery/style_sheets/dark_background.html ).

While setting the correct matplotlib style works fine at startup, things get more difficult if I am trying to change the style after the user toggles the "light" / "dark" mode. I worked out how the the change can be detected in a handler for the wx.EVT_PAINT event. However, once the GUI style change is detected, matplotlib does not seem to allow applying a different matplotlib style to the existing plot panel. It looks like the whole matplotlib figure would need to be re-created from scratch in order to apply the correct plot style. However, this is not (easily) possible in my application.

I'd appreciate any pointers or suggestions on how to deal with "light" / "dark" mode changes in wx/matplotlib panels.

Matthias

Matt Newville

unread,
Mar 4, 2022, 11:24:58 PM3/4/22
to wxpytho...@googlegroups.com
Example code is always preferred.  
But also: you might find wxmplot (https://newville.github.io/wxmplot/index.html) useful, either for the wxmplot.PlotPanel - a subclass of wx.Panel, and containing a matplotlib plot - that it provides, or for the code to show how matplotlib and wxPython can work together.  For example, each PlotPanel can be configured by the end-user after being displayed to change plot properties (line width, join style, colors, margins, labels, etc).    One of the things it supports is setting one of matplolib's color themes (including many from seaborn).  This essentially sets the matplotlib rcParams settings and sets the colors of the various plot components.


 

--
You received this message because you are subscribed to the Google Groups "wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/wxpython-users/OKQ88R.NFAW8S5P52GH%40gmail.com.


--Matt 

Matthias Brennwald

unread,
Mar 5, 2022, 3:07:29 AM3/5/22
to wxpytho...@googlegroups.com


On Fri, Mar 4 2022 at 22:24:17 -0600, Matt Newville <newv...@cars.uchicago.edu> wrote:
... One of the things it supports is setting one of matplolib's color themes (including many from seaborn).  This essentially sets the matplotlib rcParams settings and sets the colors of the various plot components.

Sure. That's exactly what I am already doing now (use rcParams to set the plot style). However, according to the matplotlib documentation, changing the plot styles (via rcParams) of an existing plot does not work. Setting the plot styles using rcParams will therefore only work at startup, when the figure is created, but it does not allow changing the plot style if the GUI light/dark mode is changed *after* the figure has been created.

Matt Newville

unread,
Mar 5, 2022, 7:19:31 AM3/5/22
to wxpytho...@googlegroups.com
Sorry to repeat myself but: 
   a) providing example code would clarify what you are doing. 
   b) wxmplot might do what you want.
   c) even if not, the wxmplot code will show you an example of one way this can be done. 
   d) wxmplot sets rcParams **and** sets the colors of the plot components.


--Matt 

Matthias Brennwald

unread,
Mar 7, 2022, 11:07:05 AM3/7/22
to wxpytho...@googlegroups.com

Okay, here's a simple code example using wxmplot as a starting point:

----------------------------------------------
import wx
import wxmplot
import numpy

x   = numpy.arange(100)/20.0 + numpy.random.random(size=100)
y   = numpy.random.random(size=len(x))
app = wx.App()
pframe = wxmplot.PlotFrame()               
pframe.plot(x, y, color='k', xlabel='x axis', ylabel='y axis')
pframe.Show()
app.MainLoop()
----------------------------------------------

If I run this and then change the GUI from "light" to "dark" mode (and back), all the control elements follow the change, but not the plot itself (see attached screen capture). To change the plot style ("light" / "dark"), I'd need to be able to capture the paint event for the frame, and then somehow call the PlotConfig.set_theme(...) from the link Matts' message. However, I don't see how I can hook into the event loop / event handler of the wxmplot panel. Can someone help me out?

Matthias
simplescreenrecorder-2022-03-07_16.51.30.mp4

Matt Newville

unread,
Mar 7, 2022, 11:50:55 AM3/7/22
to wxpytho...@googlegroups.com
Hmm, that (setting the theme from the configuration frame) works (updating all colors and styling) for me on Windows 10, MacOS, and Linux (CentOS 7), all using Python 3.8 or 3.9, and wxPython 4.1 or later.  

To be clear, you should be able to use
   pframe.plot(x, y, color='k', xlabel='x axis', ylabel='y axis', theme='dark')

but there is some ambiguity in setting the theme and trace color -- the default is to obey the explicitly set colors, so that would draw a black trace on a dark background.

If you want to set the theme programmatically,  it would be "PlotPanel.conf.set_theme('seaborn-bright')" or "PlotFrame.panel.conf.set_theme('matplotlib')".  

And, as a general rule you can force a redraw with "PlotPanel.canvas.draw()".

--Matt 
Reply all
Reply to author
Forward
0 new messages