An Interactive Discrete Graph
Old Versions:
It may be useful for some people working on optimizing performance of their activities to see the progression and improvements here, so I’m keeping them all here for reference.
Updates
(Summarizing both updates here since no one has commented yet.)
New Features
- Added support for multiple vectors.
- Added a Reset Vectors button so the activity no longer needs to be refreshed to draw a different set of vectors.
- Fixed a state-management bug that could occur if the activity was reset after only the first node had been selected.
Performance Improvements
- Replaced
pointListwith agroupcomponent.groupallows fullpointcomponents (including labels) while still supporting indexed access.pointListappears to store only coordinate pairs. I ran into similar limitations withvectorList, butgroupsolved that as well making a more extensible design for multiple vectors.
- Reworked the dependency structure.
- By reversing the dependency logic, the generated dependency graph appears significantly smaller.
- This also allowed me to remove the
spreadsheetcomponent entirely and replace it with anumberList-based state system. - Initial rendering now feels noticeably faster.
- The current implementation still requires an O(n) computation to determine the overall system state.
- In my testing,
conditionalContentwould immediately remove update logic as soon as the controlling Boolean condition (P\land Q) changed either P or $Q$s state, so both couldn’t be changed unless they were dependent conditions. - As a result, some state aggregation is still necessary to ensure all
updateValueoperations complete reliably.
- In my testing,
Preview
Original Post
I’m currently working on adding interactive illustrations to my Real Analysis notes and wanted a manipulative to help explain Cantor’s first diagonal argument, namely that \mathbb{Q} is countable. My initial approach was simply to place draggable vectors on a grid. While that worked to some extent, it quickly became clear that I wanted something more elegant from a UX perspective.
Current State I’ve implemented a module that uses trigger-set construction to update points when they are clicked.
- Clicking a point once selects it.
- Clicking the same point again resets the state.
- Clicking a different point makes the first selection the tail of a vector and the second selection the head.
A spreadsheet component currently tracks the styleNumber state for every vector. This ended up being necessary to make the triggerSet conditionals behave correctly in this implementation. When I experimented with other DoenetML components, any change to the conditionalContent boolean state caused the remaining updateValue operations to stop processing, since the conditional content disappeared before the rest of the updates could be applied. At the moment, the implementation is functional, but performance is becoming a concern. Since the activity generates a fairly large number of graphical components, interactions can feel a bit sluggish. One of my main goals moving forward is not just adding functionality, but also finding a more efficient implementation that scales better as the number of rendered objects increases.
Planned Extensions
- Support multiple vectors, both as independent click-pairs and as daisy-chained paths. This would be much easier if
VectorListsupported the same attributes as thevectorcomponent (such as explicitheadandtaildefinitions). At the moment, it appears to be restricted to positional vectors.
-
- Optional persisting style changes and propagate them to other points that lie on the selected vector. Ideally, selecting a vector would also update the styling of any intersecting points along its path.
-
- Improve performance and simplify the implementation. Right now the activity works, but the amount of state tracking and the number of generated graphical components seem heavier than they should be. I’m particularly interested in alternative approaches that would reduce the component count, simplify state management, or otherwise make the interaction more responsive. I’m interested in hearing whether anyone has tackled similar state-management or performance issues in DoenetML, particularly involving
triggerSet,conditionalContent, or vector-based interactions.
- Improve performance and simplify the implementation. Right now the activity works, but the amount of state tracking and the number of generated graphical components seem heavier than they should be. I’m particularly interested in alternative approaches that would reduce the component count, simplify state management, or otherwise make the interaction more responsive. I’m interested in hearing whether anyone has tackled similar state-management or performance issues in DoenetML, particularly involving
Overlap with Discrete Math?
I know there are a number of folks working on discrete math tools – anything y’all done that could help me here? I could also see having students draw discrete graphs with a tool like this, if you want to take it and play with it some for that purpose. With the spreadsheet, it would be easy to track and show the adjacency matrix as well.
