Skip to content

Commit

Permalink
Merge pull request #14 from wesley5040/add_auto_resize
Browse files Browse the repository at this point in the history
Figure now resizes to fit the window
  • Loading branch information
freakboy3742 committed Sep 10, 2021
2 parents f3edfc0 + dc15e65 commit 64ba814
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 32 deletions.
1 change: 1 addition & 0 deletions changes/14.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Chart now has an ``on_draw()`` handler to ensure the chart auto-resizes.
2 changes: 1 addition & 1 deletion docs/requirements_docs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ sphinxcontrib-spelling
pyenchant
sphinx-autobuild
sphinx_rtd_theme
sphinx_tabs==1.1.8
sphinx_tabs
47 changes: 22 additions & 25 deletions examples/chart/app.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,43 @@
import toga
import toga_chart
from toga.style import Pack
from matplotlib.figure import Figure
import numpy as np
from toga.constants import COLUMN


def sample_histogram():
np.random.seed(19680801)

# example data
mu = 100 # mean of distribution
sigma = 15 # standard deviation of distribution
x = mu + sigma * np.random.randn(437)

num_bins = 50
class ExampleChartApp(toga.App):
def draw_chart(self, chart, figure, *args, **kwargs):
# example data
mu = 100 # mean of distribution
sigma = 15 # standard deviation of distribution
x = mu + sigma * np.random.randn(437)

f = Figure(figsize=(5, 4))
ax = f.add_subplot(1, 1, 1)
num_bins = 50

# the histogram of the data
n, bins, patches = ax.hist(x, num_bins, density=1)
ax = figure.add_subplot(1, 1, 1)

# add a 'best fit' line
y = ((1 / (np.sqrt(2 * np.pi) * sigma)) * np.exp(-0.5 * (1 / sigma * (bins - mu))**2))
ax.plot(bins, y, '--')
ax.set_xlabel('Value')
ax.set_ylabel('Probability density')
ax.set_title(r'Histogram: $\mu=100$, $\sigma=15$')
# the histogram of the data
n, bins, patches = ax.hist(x, num_bins, density=1)

return f
# add a 'best fit' line
y = ((1 / (np.sqrt(2 * np.pi) * sigma)) * np.exp(-0.5 * (1 / sigma * (bins - mu))**2))
ax.plot(bins, y, '--')
ax.set_xlabel('Value')
ax.set_ylabel('Probability density')
ax.set_title(r'Histogram: $\mu=100$, $\sigma=15$')

figure.tight_layout()

class ExampleChartApp(toga.App):
def resize(self, *args, **kwargs):
pass

def startup(self):
np.random.seed(19680801)

# Set up main window
self.main_window = toga.MainWindow(title=self.name)

self.chart = toga_chart.Chart(style=Pack(flex=1))
self.chart = toga_chart.Chart(style=Pack(flex=1), on_resize=self.resize, on_draw=self.draw_chart)

self.main_window.content = toga.Box(
children=[
Expand All @@ -47,8 +46,6 @@ def startup(self):
style=Pack(direction=COLUMN)
)

self.chart.draw(sample_histogram())

self.main_window.show()


Expand Down
52 changes: 46 additions & 6 deletions src/toga_chart/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
import sys

from matplotlib.backend_bases import FigureCanvasBase, RendererBase
from matplotlib.figure import Figure
from matplotlib.path import Path
from matplotlib.transforms import Affine2D

from toga.colors import color as parse_color
from toga.colors import rgba
from toga.fonts import CURSIVE, FANTASY, MONOSPACE, SANS_SERIF, SERIF, Font
from toga.handlers import wrapped_handler
from toga.widgets.canvas import Canvas


Expand All @@ -18,24 +20,62 @@ class Chart(Canvas, FigureCanvasBase):
id (str): An identifier for this widget.
style (:obj:`Style`): An optional style object. If no
style is provided then a new one will be created for the widget.
on_resize (:obj:`callable`): Handler to invoke when the chart is resized.
The default resize handler will draw the chart on every resize;
generally, you won't need to override this default behavior.
on_draw (:obj:`callable`): Handler to invoke when the chart needs to be
drawn.
factory (:obj:`module`): A python module that is capable to return a
implementation of this class with the same name. (optional &
normally not needed)
"""
def __init__(self, id=None, style=None, factory=None):
Canvas.__init__(self, id=id, style=style, factory=factory)
def __init__(self, id=None, style=None, on_resize=None, on_draw=None, factory=None):
if on_resize is None:
on_resize = self._resize
Canvas.__init__(self, id=id, style=style, on_resize=on_resize, factory=factory)
self.on_draw = on_draw

def draw(self, figure):
"""Draws the matplotlib figure onto the canvas
Args:
figure (figure): matplotlib figure to draw
"""
self.figure = figure
FigureCanvasBase.__init__(self, self.figure)
l, b, w, h = self.figure.bbox.bounds
FigureCanvasBase.__init__(self, figure)
l, b, w, h = figure.bbox.bounds
renderer = ChartRenderer(self, w, h)
self.figure.draw(renderer)
figure.draw(renderer)

def _resize(self, *args, **kwargs):
""
# 100 is the default DPI for figure at time of writing.
dpi = 100
figure = Figure(
figsize=(
self.layout.content_width / dpi,
self.layout.content_height / dpi
)
)
self.on_draw(self, figure=figure)
self.draw(figure)

@property
def on_draw(self):
"""The handler to invoke when the canvas needs to be drawn.
Returns:
The handler that is invoked on canvas draw.
"""
return self._on_draw

@on_draw.setter
def on_draw(self, handler):
"""Set the handler to invoke when the canvas is drawn.
Args:
handler (:obj:`callable`): The handler to invoke when the canvas is drawn.
"""
self._on_draw = wrapped_handler(self, handler)


class ChartRenderer(RendererBase):
Expand Down

0 comments on commit 64ba814

Please sign in to comment.