Move MPL-related code to canvas panel
This commit is contained in:
@@ -18,8 +18,45 @@
|
||||
# =============================================================================
|
||||
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import traceback
|
||||
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
|
||||
from graphs.style import BASE_COLORS, LIGHTNESSES, STYLES, hsl_to_hsv
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
try:
|
||||
import matplotlib as mpl
|
||||
|
||||
mpl_version = int(mpl.__version__[0]) or -1
|
||||
if mpl_version >= 2:
|
||||
mpl.use('wxagg')
|
||||
graphFrame_enabled = True
|
||||
else:
|
||||
graphFrame_enabled = False
|
||||
|
||||
from matplotlib.lines import Line2D
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.colors import hsv_to_rgb
|
||||
except ImportError as e:
|
||||
pyfalog.warning('Matplotlib failed to import. Likely missing or incompatible version.')
|
||||
graphFrame_enabled = False
|
||||
except Exception:
|
||||
# We can get exceptions deep within matplotlib. Catch those. See GH #1046
|
||||
tb = traceback.format_exc()
|
||||
pyfalog.critical('Exception when importing Matplotlib. Continuing without importing.')
|
||||
pyfalog.critical(tb)
|
||||
graphFrame_enabled = False
|
||||
|
||||
|
||||
class GraphCanvasPanel(wx.Panel):
|
||||
@@ -27,3 +64,140 @@ class GraphCanvasPanel(wx.Panel):
|
||||
def __init__(self, graphFrame, parent):
|
||||
super().__init__(parent)
|
||||
self.graphFrame = graphFrame
|
||||
|
||||
# Remove matplotlib font cache, see #234
|
||||
try:
|
||||
cache_dir = mpl._get_cachedir()
|
||||
except:
|
||||
cache_dir = os.path.expanduser(os.path.join('~', '.matplotlib'))
|
||||
cache_file = os.path.join(cache_dir, 'fontList.cache')
|
||||
if os.access(cache_dir, os.W_OK | os.X_OK) and os.path.isfile(cache_file):
|
||||
os.remove(cache_file)
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.figure = Figure(figsize=(5, 3), tight_layout={'pad': 1.08})
|
||||
rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
|
||||
clr = [c / 255. for c in rgbtuple]
|
||||
self.figure.set_facecolor(clr)
|
||||
self.figure.set_edgecolor(clr)
|
||||
self.canvas = Canvas(self, -1, self.figure)
|
||||
self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
|
||||
self.subplot = self.figure.add_subplot(111)
|
||||
self.subplot.grid(True)
|
||||
mainSizer.Add(self.canvas, 1, wx.EXPAND | wx.ALL, 0)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
|
||||
def draw(self):
|
||||
self.subplot.clear()
|
||||
self.subplot.grid(True)
|
||||
lineData = []
|
||||
|
||||
min_y = 0 if self.graphFrame.ctrlPanel.showY0 else None
|
||||
max_y = 0 if self.graphFrame.ctrlPanel.showY0 else None
|
||||
|
||||
chosenX = self.graphFrame.ctrlPanel.xType
|
||||
chosenY = self.graphFrame.ctrlPanel.yType
|
||||
self.subplot.set(xlabel=self.graphFrame.ctrlPanel.formatLabel(chosenX), ylabel=self.graphFrame.ctrlPanel.formatLabel(chosenY))
|
||||
|
||||
mainInput, miscInputs = self.graphFrame.ctrlPanel.getValues()
|
||||
view = self.graphFrame.getView()
|
||||
sources = self.graphFrame.ctrlPanel.sources
|
||||
if view.hasTargets:
|
||||
iterList = tuple(itertools.product(sources, self.graphFrame.ctrlPanel.targets))
|
||||
else:
|
||||
iterList = tuple((f, None) for f in sources)
|
||||
for source, target in iterList:
|
||||
# Get line style data
|
||||
try:
|
||||
colorData = BASE_COLORS[source.colorID]
|
||||
except KeyError:
|
||||
pyfalog.warning('Invalid color "{}" for "{}"'.format(source.colorID, source.name))
|
||||
continue
|
||||
color = colorData.hsl
|
||||
lineStyle = 'solid'
|
||||
if target is not None:
|
||||
try:
|
||||
lightnessData = LIGHTNESSES[target.lightnessID]
|
||||
except KeyError:
|
||||
pyfalog.warning('Invalid lightness "{}" for "{}"'.format(target.lightnessID, target.name))
|
||||
continue
|
||||
color = lightnessData.func(color)
|
||||
try:
|
||||
lineStyleData = STYLES[target.lineStyleID]
|
||||
except KeyError:
|
||||
pyfalog.warning('Invalid line style "{}" for "{}"'.format(target.lightnessID, target.name))
|
||||
continue
|
||||
lineStyle = lineStyleData.mplSpec
|
||||
color = hsv_to_rgb(hsl_to_hsv(color))
|
||||
|
||||
# Get point data
|
||||
try:
|
||||
xs, ys = view.getPlotPoints(
|
||||
mainInput=mainInput,
|
||||
miscInputs=miscInputs,
|
||||
xSpec=chosenX,
|
||||
ySpec=chosenY,
|
||||
src=source,
|
||||
tgt=target)
|
||||
|
||||
# Figure out min and max Y
|
||||
min_y_this = min(ys, default=None)
|
||||
if min_y is None:
|
||||
min_y = min_y_this
|
||||
elif min_y_this is not None:
|
||||
min_y = min(min_y, min_y_this)
|
||||
max_y_this = max(ys, default=None)
|
||||
if max_y is None:
|
||||
max_y = max_y_this
|
||||
elif max_y_this is not None:
|
||||
max_y = max(max_y, max_y_this)
|
||||
|
||||
# If we have single data point, show marker - otherwise line won't be shown
|
||||
if len(xs) == 1 and len(ys) == 1:
|
||||
self.subplot.plot(xs, ys, color=color, linestyle=lineStyle, marker='.')
|
||||
else:
|
||||
self.subplot.plot(xs, ys, color=color, linestyle=lineStyle)
|
||||
|
||||
if target is None:
|
||||
lineData.append((color, lineStyle, source.shortName))
|
||||
else:
|
||||
lineData.append((color, lineStyle, '{} vs {}'.format(source.shortName, target.shortName)))
|
||||
except Exception as ex:
|
||||
pyfalog.warning('Invalid values in "{0}"', source.name)
|
||||
self.canvas.draw()
|
||||
self.Refresh()
|
||||
return
|
||||
|
||||
# Special case for when we do not show Y = 0 and have no fits
|
||||
if min_y is None:
|
||||
min_y = 0
|
||||
if max_y is None:
|
||||
max_y = 0
|
||||
# Extend range a little for some visual space
|
||||
y_range = max_y - min_y
|
||||
min_y -= y_range * 0.05
|
||||
max_y += y_range * 0.05
|
||||
if min_y == max_y:
|
||||
min_y -= min_y * 0.05
|
||||
max_y += min_y * 0.05
|
||||
if min_y == max_y:
|
||||
min_y -= 5
|
||||
max_y += 5
|
||||
self.subplot.set_ylim(bottom=min_y, top=max_y)
|
||||
|
||||
legendLines = []
|
||||
for i, iData in enumerate(lineData):
|
||||
color, lineStyle, label = iData
|
||||
legendLines.append(Line2D([0], [0], color=color, linestyle=lineStyle, label=label.replace('$', '\$')))
|
||||
|
||||
if len(legendLines) > 0 and self.graphFrame.ctrlPanel.showLegend:
|
||||
legend = self.subplot.legend(handles=legendLines)
|
||||
for t in legend.get_texts():
|
||||
t.set_fontsize('small')
|
||||
for l in legend.get_lines():
|
||||
l.set_linewidth(1)
|
||||
|
||||
self.canvas.draw()
|
||||
self.Refresh()
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
# =============================================================================
|
||||
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import traceback
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from logbook import Logger
|
||||
@@ -31,64 +27,29 @@ import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from graphs.data.base import FitGraph
|
||||
from graphs.events import RESIST_MODE_CHANGED
|
||||
from graphs.style import BASE_COLORS, LIGHTNESSES, STYLES, hsl_to_hsv
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from service.const import GraphCacheCleanupReason
|
||||
from service.settings import GraphSettings
|
||||
from . import canvasPanel
|
||||
from .ctrlPanel import GraphControlPanel
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
try:
|
||||
import matplotlib as mpl
|
||||
|
||||
mpl_version = int(mpl.__version__[0]) or -1
|
||||
if mpl_version >= 2:
|
||||
mpl.use('wxagg')
|
||||
graphFrame_enabled = True
|
||||
else:
|
||||
graphFrame_enabled = False
|
||||
|
||||
from matplotlib.lines import Line2D
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.colors import hsv_to_rgb
|
||||
except ImportError as e:
|
||||
pyfalog.warning('Matplotlib failed to import. Likely missing or incompatible version.')
|
||||
graphFrame_enabled = False
|
||||
except Exception:
|
||||
# We can get exceptions deep within matplotlib. Catch those. See GH #1046
|
||||
tb = traceback.format_exc()
|
||||
pyfalog.critical('Exception when importing Matplotlib. Continuing without importing.')
|
||||
pyfalog.critical(tb)
|
||||
graphFrame_enabled = False
|
||||
|
||||
|
||||
class GraphFrame(AuxiliaryFrame):
|
||||
|
||||
def __init__(self, parent):
|
||||
|
||||
global graphFrame_enabled
|
||||
if not graphFrame_enabled:
|
||||
if not canvasPanel.graphFrame_enabled:
|
||||
pyfalog.warning('Matplotlib is not enabled. Skipping initialization.')
|
||||
return
|
||||
|
||||
super().__init__(parent, title='Graphs', style=wx.RESIZE_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE, size=(520, 390))
|
||||
super().__init__(parent, title='Graphs', style=wx.RESIZE_BORDER, size=(520, 390))
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
self.SetIcon(wx.Icon(BitmapLoader.getBitmap('graphs_small', 'gui')))
|
||||
|
||||
# Remove matplotlib font cache, see #234
|
||||
try:
|
||||
cache_dir = mpl._get_cachedir()
|
||||
except:
|
||||
cache_dir = os.path.expanduser(os.path.join('~', '.matplotlib'))
|
||||
cache_file = os.path.join(cache_dir, 'fontList.cache')
|
||||
if os.access(cache_dir, os.W_OK | os.X_OK) and os.path.isfile(cache_file):
|
||||
os.remove(cache_file)
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
# Layout - graph selector
|
||||
@@ -97,16 +58,8 @@ class GraphFrame(AuxiliaryFrame):
|
||||
mainSizer.Add(self.graphSelection, 0, wx.EXPAND)
|
||||
|
||||
# Layout - plot area
|
||||
self.figure = Figure(figsize=(5, 3), tight_layout={'pad': 1.08})
|
||||
rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
|
||||
clr = [c / 255. for c in rgbtuple]
|
||||
self.figure.set_facecolor(clr)
|
||||
self.figure.set_edgecolor(clr)
|
||||
self.canvas = Canvas(self, -1, self.figure)
|
||||
self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
|
||||
self.subplot = self.figure.add_subplot(111)
|
||||
self.subplot.grid(True)
|
||||
mainSizer.Add(self.canvas, 1, wx.EXPAND)
|
||||
self.canvasPanel = canvasPanel.GraphCanvasPanel(self, self)
|
||||
mainSizer.Add(self.canvasPanel, 1, wx.EXPAND | wx.ALL, 0)
|
||||
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.EXPAND)
|
||||
|
||||
@@ -142,7 +95,7 @@ class GraphFrame(AuxiliaryFrame):
|
||||
|
||||
@classmethod
|
||||
def openOne(cls, parent):
|
||||
if graphFrame_enabled:
|
||||
if canvasPanel.graphFrame_enabled:
|
||||
super().openOne(parent)
|
||||
|
||||
def UpdateWindowSize(self):
|
||||
@@ -244,116 +197,4 @@ class GraphFrame(AuxiliaryFrame):
|
||||
self.getView().clearCache(reason, extraData)
|
||||
|
||||
def draw(self):
|
||||
global mpl_version
|
||||
|
||||
self.subplot.clear()
|
||||
self.subplot.grid(True)
|
||||
lineData = []
|
||||
|
||||
min_y = 0 if self.ctrlPanel.showY0 else None
|
||||
max_y = 0 if self.ctrlPanel.showY0 else None
|
||||
|
||||
chosenX = self.ctrlPanel.xType
|
||||
chosenY = self.ctrlPanel.yType
|
||||
self.subplot.set(xlabel=self.ctrlPanel.formatLabel(chosenX), ylabel=self.ctrlPanel.formatLabel(chosenY))
|
||||
|
||||
mainInput, miscInputs = self.ctrlPanel.getValues()
|
||||
view = self.getView()
|
||||
sources = self.ctrlPanel.sources
|
||||
if view.hasTargets:
|
||||
iterList = tuple(itertools.product(sources, self.ctrlPanel.targets))
|
||||
else:
|
||||
iterList = tuple((f, None) for f in sources)
|
||||
for source, target in iterList:
|
||||
# Get line style data
|
||||
try:
|
||||
colorData = BASE_COLORS[source.colorID]
|
||||
except KeyError:
|
||||
pyfalog.warning('Invalid color "{}" for "{}"'.format(source.colorID, source.name))
|
||||
continue
|
||||
color = colorData.hsl
|
||||
lineStyle = 'solid'
|
||||
if target is not None:
|
||||
try:
|
||||
lightnessData = LIGHTNESSES[target.lightnessID]
|
||||
except KeyError:
|
||||
pyfalog.warning('Invalid lightness "{}" for "{}"'.format(target.lightnessID, target.name))
|
||||
continue
|
||||
color = lightnessData.func(color)
|
||||
try:
|
||||
lineStyleData = STYLES[target.lineStyleID]
|
||||
except KeyError:
|
||||
pyfalog.warning('Invalid line style "{}" for "{}"'.format(target.lightnessID, target.name))
|
||||
continue
|
||||
lineStyle = lineStyleData.mplSpec
|
||||
color = hsv_to_rgb(hsl_to_hsv(color))
|
||||
|
||||
# Get point data
|
||||
try:
|
||||
xs, ys = view.getPlotPoints(
|
||||
mainInput=mainInput,
|
||||
miscInputs=miscInputs,
|
||||
xSpec=chosenX,
|
||||
ySpec=chosenY,
|
||||
src=source,
|
||||
tgt=target)
|
||||
|
||||
# Figure out min and max Y
|
||||
min_y_this = min(ys, default=None)
|
||||
if min_y is None:
|
||||
min_y = min_y_this
|
||||
elif min_y_this is not None:
|
||||
min_y = min(min_y, min_y_this)
|
||||
max_y_this = max(ys, default=None)
|
||||
if max_y is None:
|
||||
max_y = max_y_this
|
||||
elif max_y_this is not None:
|
||||
max_y = max(max_y, max_y_this)
|
||||
|
||||
# If we have single data point, show marker - otherwise line won't be shown
|
||||
if len(xs) == 1 and len(ys) == 1:
|
||||
self.subplot.plot(xs, ys, color=color, linestyle=lineStyle, marker='.')
|
||||
else:
|
||||
self.subplot.plot(xs, ys, color=color, linestyle=lineStyle)
|
||||
|
||||
if target is None:
|
||||
lineData.append((color, lineStyle, source.shortName))
|
||||
else:
|
||||
lineData.append((color, lineStyle, '{} vs {}'.format(source.shortName, target.shortName)))
|
||||
except Exception as ex:
|
||||
pyfalog.warning('Invalid values in "{0}"', source.name)
|
||||
self.canvas.draw()
|
||||
self.Refresh()
|
||||
return
|
||||
|
||||
# Special case for when we do not show Y = 0 and have no fits
|
||||
if min_y is None:
|
||||
min_y = 0
|
||||
if max_y is None:
|
||||
max_y = 0
|
||||
# Extend range a little for some visual space
|
||||
y_range = max_y - min_y
|
||||
min_y -= y_range * 0.05
|
||||
max_y += y_range * 0.05
|
||||
if min_y == max_y:
|
||||
min_y -= min_y * 0.05
|
||||
max_y += min_y * 0.05
|
||||
if min_y == max_y:
|
||||
min_y -= 5
|
||||
max_y += 5
|
||||
self.subplot.set_ylim(bottom=min_y, top=max_y)
|
||||
|
||||
legendLines = []
|
||||
for i, iData in enumerate(lineData):
|
||||
color, lineStyle, label = iData
|
||||
legendLines.append(Line2D([0], [0], color=color, linestyle=lineStyle, label=label.replace('$', '\$')))
|
||||
|
||||
if len(legendLines) > 0 and self.ctrlPanel.showLegend:
|
||||
legend = self.subplot.legend(handles=legendLines)
|
||||
for t in legend.get_texts():
|
||||
t.set_fontsize('small')
|
||||
for l in legend.get_lines():
|
||||
l.set_linewidth(1)
|
||||
|
||||
self.canvas.draw()
|
||||
self.Refresh()
|
||||
self.canvasPanel.draw()
|
||||
|
||||
@@ -23,7 +23,7 @@ import wx
|
||||
import config
|
||||
from service.character import Character
|
||||
from service.fit import Fit
|
||||
from graphs.gui import frame as graphFrame
|
||||
from graphs.gui import canvasPanel as graphCanvasPanel
|
||||
import gui.globalEvents as GE
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
|
||||
@@ -101,7 +101,7 @@ class MainMenuBar(wx.MenuBar):
|
||||
graphFrameItem = wx.MenuItem(fitMenu, self.graphFrameId, "&Graphs\tCTRL+G")
|
||||
graphFrameItem.SetBitmap(BitmapLoader.getBitmap("graphs_small", "gui"))
|
||||
fitMenu.Append(graphFrameItem)
|
||||
if not graphFrame.graphFrame_enabled:
|
||||
if not graphCanvasPanel.graphFrame_enabled:
|
||||
self.Enable(self.graphFrameId, False)
|
||||
self.ignoreRestrictionItem = fitMenu.Append(self.toggleIgnoreRestrictionID, "Disable Fitting Re&strictions")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user