Embedded the matplotlib in a GtkViewport.
Still trying to work out the kinks, as only one plot is showing, and it's not updating with the sliders. I'll get there sooner or later. Also updated the gitignore, and added images showing the parametric equations used to calculate the graphs. Neat!
This commit is contained in:
parent
903ab65ea7
commit
3e96363771
7 changed files with 217 additions and 29 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,6 @@
|
||||||
|
# don't track temporary files
|
||||||
|
*~
|
||||||
|
|
||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/kdevelop4
|
# Created by https://www.toptal.com/developers/gitignore/api/kdevelop4
|
||||||
# Edit at https://www.toptal.com/developers/gitignore?templates=kdevelop4
|
# Edit at https://www.toptal.com/developers/gitignore?templates=kdevelop4
|
||||||
|
|
BIN
img/epitrochoid.png
Normal file
BIN
img/epitrochoid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
img/hypotrochoid.png
Normal file
BIN
img/hypotrochoid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
img/small_epitrochoid.png
Normal file
BIN
img/small_epitrochoid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
img/small_hypotrochoid.png
Normal file
BIN
img/small_hypotrochoid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
153
spirographs.glade
Normal file
153
spirographs.glade
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.38.2 -->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.24"/>
|
||||||
|
<object class="GtkAdjustment" id="bigRadiusAdjustment">
|
||||||
|
<property name="lower">0.10</property>
|
||||||
|
<property name="upper">100</property>
|
||||||
|
<property name="value">0.10</property>
|
||||||
|
<property name="step-increment">0.10</property>
|
||||||
|
<property name="page-increment">1</property>
|
||||||
|
<signal name="value-changed" handler="bigRadiusAdjustment_value_changed_cb" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="distanceAdjustment">
|
||||||
|
<property name="lower">0.10</property>
|
||||||
|
<property name="upper">100</property>
|
||||||
|
<property name="value">0.10</property>
|
||||||
|
<property name="step-increment">0.10</property>
|
||||||
|
<property name="page-increment">1</property>
|
||||||
|
<signal name="value-changed" handler="distanceAdjustment_value_changed_cb" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<object class="GtkAdjustment" id="smallRadiusAdjustment">
|
||||||
|
<property name="lower">0.10</property>
|
||||||
|
<property name="upper">100</property>
|
||||||
|
<property name="value">0.10</property>
|
||||||
|
<property name="step-increment">0.10</property>
|
||||||
|
<property name="page-increment">1</property>
|
||||||
|
<signal name="value-changed" handler="smallRadiusAdjustment_value_changed_cb" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<object class="GtkWindow" id="spWindow">
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<signal name="destroy" handler="onDestroy" swapped="no"/>
|
||||||
|
<child>
|
||||||
|
<!-- n-columns=2 n-rows=5 -->
|
||||||
|
<object class="GtkGrid" id="topGrid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="row-spacing">10</property>
|
||||||
|
<property name="column-homogeneous">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScale" id="bigRadiusScale">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="adjustment">bigRadiusAdjustment</property>
|
||||||
|
<property name="show-fill-level">True</property>
|
||||||
|
<property name="fill-level">100</property>
|
||||||
|
<property name="round-digits">1</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">1</property>
|
||||||
|
<property name="top-attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScale" id="smallRadiusScale">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="adjustment">smallRadiusAdjustment</property>
|
||||||
|
<property name="show-fill-level">True</property>
|
||||||
|
<property name="fill-level">100</property>
|
||||||
|
<property name="round-digits">1</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">1</property>
|
||||||
|
<property name="top-attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScale" id="distanceScale">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="adjustment">distanceAdjustment</property>
|
||||||
|
<property name="show-fill-level">True</property>
|
||||||
|
<property name="fill-level">100</property>
|
||||||
|
<property name="round-digits">1</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">1</property>
|
||||||
|
<property name="top-attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="bigRadiusLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Big Radius (R):</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="smallRadiusLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Small Radius (r):</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="distanceLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Distance (d):</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="epichondroidFormulaImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="pixbuf">img/small_epitrochoid.png</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="hypotrochoidFormulaImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="pixbuf">img/small_hypotrochoid.png</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">1</property>
|
||||||
|
<property name="top-attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkViewport" id="plotViewport">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">0</property>
|
||||||
|
<property name="width">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -1,53 +1,86 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
# gtk imports
|
# gtk imports
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk, Gdk, GObject, GLib
|
from gi.repository import Gtk, Gdk, GObject, GLib
|
||||||
|
|
||||||
# math/plot imports
|
# math/plot imports
|
||||||
|
from matplotlib.backends.backend_gtk3agg import (
|
||||||
|
FigureCanvasGTK3Agg as FigureCanvas)
|
||||||
|
from matplotlib.figure import Figure
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib.pyplot as plt
|
|
||||||
import math
|
import math
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
class spirographs:
|
class spirographs:
|
||||||
|
|
||||||
|
|
||||||
def calcEpiX(theta, bigRadius, smallRadius, distance):
|
|
||||||
return ((bigRadius + smallRadius) * math.cos(theta)) - (distance * math.cos(((bigRadius + smallRadius)/(smallRadius))*theta))
|
|
||||||
|
|
||||||
def calcEpiY(theta, bigRadius, smallRadius, distance):
|
|
||||||
return ((bigRadius + smallRadius) * math.sin(theta)) - (distance * math.sin(((bigRadius + smallRadius)/(smallRadius))*theta))
|
|
||||||
|
|
||||||
def calcHypoX(theta, bigRadius, smallRadius, distance):
|
|
||||||
return ((bigRadius - smallRadius) * math.cos(theta)) + (distance * math.cos(((bigRadius - smallRadius)/(smallRadius))*theta))
|
|
||||||
|
|
||||||
def calcHypoY(theta, bigRadius, smallRadius, distance):
|
|
||||||
return ((bigRadius - smallRadius) * math.sin(theta)) - (distance * math.sin(((bigRadius - smallRadius)/(smallRadius))*theta))
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.bigRadius = 12
|
self.bigRadius = 12
|
||||||
self.smallRadius = 5
|
self.smallRadius = 5
|
||||||
self.distance = 4
|
self.distance = 4
|
||||||
self.highestTheta = (np.lcm(smallRadius, bigRadius)/bigRadius) * 2 * math.pi
|
self.highestTheta = (np.lcm(self.smallRadius, self.bigRadius)/self.bigRadius) * 2 * math.pi
|
||||||
self.stepSize = highestTheta / 4096
|
self.stepSize = self.highestTheta / 4096
|
||||||
self.recalcPoints()
|
self.recalcPoints()
|
||||||
self.showPlot()
|
self.showPlot()
|
||||||
|
|
||||||
|
def calcEpiX(self, theta):
|
||||||
|
return ((self.bigRadius + self.smallRadius) * math.cos(theta)) - (self.distance * math.cos(((self.bigRadius + self.smallRadius)/(self.smallRadius))*theta))
|
||||||
|
|
||||||
|
def calcEpiY(self, theta):
|
||||||
|
return ((self.bigRadius + self.smallRadius) * math.sin(theta)) - (self.distance * math.sin(((self.bigRadius + self.smallRadius)/(self.smallRadius))*theta))
|
||||||
|
|
||||||
|
def calcHypoX(self, theta):
|
||||||
|
return ((self.bigRadius - self.smallRadius) * math.cos(theta)) + (self.distance * math.cos(((self.bigRadius - self.smallRadius)/(self.smallRadius))*theta))
|
||||||
|
|
||||||
|
def calcHypoY(self, theta):
|
||||||
|
return ((self.bigRadius - self.smallRadius) * math.sin(theta)) - (self.distance * math.sin(((self.bigRadius - self.smallRadius)/(self.smallRadius))*theta))
|
||||||
|
|
||||||
|
def onDestroy(self, widget):
|
||||||
|
Gtk.main_quit()
|
||||||
|
return
|
||||||
|
|
||||||
|
def bigRadiusAdjustment_value_changed_cb(self, widget):
|
||||||
|
self.bigRadius = widget.get_value()
|
||||||
|
self.recalcPoints()
|
||||||
|
self.updatePlot()
|
||||||
|
|
||||||
|
def smallRadiusAdjustment_value_changed_cb(self, widget):
|
||||||
|
self.smallRadius = widget.get_value()
|
||||||
|
self.recalcPoints()
|
||||||
|
self.updatePlot()
|
||||||
|
|
||||||
|
def distanceAdjustment_value_changed_cb(self, widget):
|
||||||
|
self.distance = widget.get_value()
|
||||||
|
self.recalcPoints()
|
||||||
|
self.updatePlot()
|
||||||
|
|
||||||
def recalcPoints(self):
|
def recalcPoints(self):
|
||||||
self.epiX = np.array([calcEpiX(i, bigRadius, smallRadius, distance) for i in np.arange(0, highestTheta, stepSize)])
|
self.epiX = np.array([self.calcEpiX(i) for i in np.arange(0, self.highestTheta, self.stepSize)])
|
||||||
self.epiY = np.array([calcEpiY(i, bigRadius, smallRadius, distance) for i in np.arange(0, highestTheta, stepSize)])
|
self.epiY = np.array([self.calcEpiY(i) for i in np.arange(0, self.highestTheta, self.stepSize)])
|
||||||
self.hypoX = np.array([calcHypoX(i, bigRadius, smallRadius, distance) for i in np.arange(0, highestTheta, stepSize)])
|
self.hypoX = np.array([self.calcHypoX(i) for i in np.arange(0, self.highestTheta, self.stepSize)])
|
||||||
self.hypoY = np.array([calcHypoY(i, bigRadius, smallRadius, distance) for i in np.arange(0, highestTheta, stepSize)])
|
self.hypoY = np.array([self.calcHypoY(i) for i in np.arange(0, self.highestTheta, self.stepSize)])
|
||||||
|
|
||||||
def showPlot(self):
|
def showPlot(self):
|
||||||
plt.subplot(1, 2, 1)
|
viewport = builder.get_object('plotViewport')
|
||||||
plt.title(f"Epichondroid of {bigRadius}, {smallRadius}, {distance}")
|
self.plotFigure = Figure(figsize=(5, 4), dpi=100)
|
||||||
plt.plot(epiX, epiY)
|
self.subPlot1 = self.plotFigure.add_subplot()
|
||||||
plt.subplot(1, 2, 2)
|
#self.subPlot1.title = f"Epichondroid of {self.bigRadius}, {self.smallRadius}, {self.distance}"
|
||||||
plt.title(f"Hypochondroid of {bigRadius}, {smallRadius}, {distance}")
|
self.subPlot1.plot(self.epiX, self.epiY)
|
||||||
plt.plot(hypoX, hypoY)
|
self.subPlot2 = self.plotFigure.add_subplot()
|
||||||
plt.show()
|
#self.subPlot2.title = f"Hypochondroid of {self.bigRadius}, {self.smallRadius}, {self.distance}"
|
||||||
|
self.subPlot2.plot(self.hypoX, self.hypoY)
|
||||||
|
|
||||||
|
self.canvas = FigureCanvas(self.plotFigure)
|
||||||
|
self.canvas.set_size_request(800, 600)
|
||||||
|
viewport.add(self.canvas)
|
||||||
|
|
||||||
|
def updatePlot(self):
|
||||||
|
self.subPlot1.plot(self.epiX, self.epiY)
|
||||||
|
self.subPlot2.plot(self.hypoX, self.hypoY)
|
||||||
|
|
||||||
builder = Gtk.Builder()
|
builder = Gtk.Builder()
|
||||||
builder.add_from_file("spirographs.glade")
|
builder.add_from_file("spirographs.glade")
|
||||||
|
@ -57,4 +90,3 @@ window = builder.get_object("spWindow")
|
||||||
window.show_all()
|
window.show_all()
|
||||||
|
|
||||||
Gtk.main()
|
Gtk.main()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue