LMS_Demo / src /modules /module4.py
raymondEDS
adding custom learning path
dfe5163
import streamlit as st
import plotly.graph_objects as go
import networkx as nx
import numpy as np
def create_intake_graph():
"""Create the intake graph structure."""
G = nx.DiGraph()
# Add nodes with their categories
nodes = {
'A': {'name': 'Student Enrollment', 'category': 'start'},
'B': {'name': 'Learner Profile Assessment', 'category': 'assessment'},
'C': {'name': 'Technical Background', 'category': 'profile'},
'D': {'name': 'Mathematical Foundation', 'category': 'profile'},
'E': {'name': 'Domain Knowledge', 'category': 'profile'},
'F': {'name': 'Learning Preferences', 'category': 'profile'},
'G': {'name': 'Prior Knowledge', 'category': 'profile'},
'H': {'name': 'Profile Classification', 'category': 'classification'},
'I': {'name': 'Learner Archetype', 'category': 'archetype'},
'J': {'name': 'Advanced Technical Path', 'category': 'path'},
'K': {'name': 'Accelerated Technical Path', 'category': 'path'},
'L': {'name': 'Applied Research Path', 'category': 'path'},
'M': {'name': 'Foundational Path', 'category': 'path'},
'N': {'name': "Bloom's Taxonomy Outcomes", 'category': 'outcomes'},
'O': {'name': 'Remember Level', 'category': 'bloom'},
'P': {'name': 'Understand Level', 'category': 'bloom'},
'Q': {'name': 'Apply Level', 'category': 'bloom'},
'R': {'name': 'Analyze Level', 'category': 'bloom'},
'S': {'name': 'Evaluate Level', 'category': 'bloom'},
'T': {'name': 'Create Level', 'category': 'bloom'},
'U': {'name': 'Adaptive Content Selection', 'category': 'content'},
'V': {'name': 'Personalized Learning Activities', 'category': 'learning'},
'W': {'name': 'Personalized Clustering Curriculum', 'category': 'final'},
}
# Add nodes to graph
for node_id, node_data in nodes.items():
G.add_node(node_id, **node_data)
# Add edges
edges = [
('A', 'B'),
('B', 'C'), ('B', 'D'), ('B', 'E'), ('B', 'F'), ('B', 'G'),
('C', 'H'), ('D', 'H'), ('E', 'H'), ('F', 'H'), ('G', 'H'),
('H', 'I'),
('I', 'J'), ('I', 'K'), ('I', 'L'), ('I', 'M'),
('J', 'N'), ('K', 'N'), ('L', 'N'), ('M', 'N'),
('N', 'O'), ('N', 'P'), ('N', 'Q'), ('N', 'R'), ('N', 'S'), ('N', 'T'),
('O', 'U'), ('P', 'U'), ('Q', 'U'), ('R', 'U'), ('S', 'U'), ('T', 'U'),
('U', 'V'),
('V', 'W')
]
G.add_edges_from(edges)
return G
def get_node_colors(G):
"""Get colors for different node categories."""
# Define colors with better contrast
category_colors = {
'start': '#2E7D32', # Darker Green
'assessment': '#1565C0', # Darker Blue
'profile': '#F57F17', # Darker Amber
'classification': '#6A1B9A', # Darker Purple
'archetype': '#BF360C', # Darker Deep Orange
'path': '#AD1457', # Darker Pink
'outcomes': '#00695C', # Darker Cyan
'bloom': '#283593', # Darker Indigo
'content': '#E65100', # Darker Orange
'learning': '#004D40', # Darker Teal
'final': '#4527A0' # Darker Deep Purple
}
return [category_colors[G.nodes[node]['category']] for node in G.nodes()]
def create_interactive_graph(G):
"""Create an interactive Plotly visualization of the graph."""
# Define node levels for hierarchical organization
node_levels = {
'A': 0, # Student Enrollment
'B': 1, # Learner Profile Assessment
'C': 2, 'D': 2, 'E': 2, 'F': 2, 'G': 2, # Profile components
'H': 3, # Profile Classification
'I': 4, # Learner Archetype
'J': 5, 'K': 5, 'L': 5, 'M': 5, # Learning Paths
'N': 6, # Bloom's Taxonomy Outcomes
'O': 7, 'P': 7, 'Q': 7, 'R': 7, 'S': 7, 'T': 7, # Bloom's levels
'U': 8, # Adaptive Content Selection
'V': 9, # Personalized Learning Activities
'W': 10 # Personalized Clustering Curriculum
}
# Define key nodes that should be highlighted
key_nodes = {'A', 'B', 'H', 'I', 'N', 'W'}
# Calculate positions based on levels
pos = {}
level_nodes = {}
for node, level in node_levels.items():
if level not in level_nodes:
level_nodes[level] = []
level_nodes[level].append(node)
# Position nodes by level with increased spacing
for level in sorted(level_nodes.keys()):
nodes = level_nodes[level]
n_nodes = len(nodes)
for i, node in enumerate(nodes):
# Center nodes horizontally within their level with more spacing
x = (i - (n_nodes - 1) / 2) * 3 # Increased from 2 to 3
y = -level * 2.5 # Increased from 2 to 2.5
pos[node] = (x, y)
# Create edge traces with arrows
edge_x = []
edge_y = []
for edge in G.edges():
x0, y0 = pos[edge[0]]
x1, y1 = pos[edge[1]]
edge_x.extend([x0, x1, None])
edge_y.extend([y0, y1, None])
edge_trace = go.Scatter(
x=edge_x, y=edge_y,
line=dict(width=2, color='#888'),
hoverinfo='none',
mode='lines',
line_shape='spline'
)
# Create node traces
node_x = []
node_y = []
node_text = []
node_hover = []
node_sizes = []
node_colors = get_node_colors(G)
def format_node_text(text):
"""Format node text with line breaks for multi-word labels."""
words = text.split()
if len(words) > 1:
return '<br>'.join(words) # Line break between words
return text
for i, node in enumerate(G.nodes()):
x, y = pos[node]
node_x.append(x)
node_y.append(y)
category = G.nodes[node]['category']
node_text.append(format_node_text(G.nodes[node]['name']))
node_hover.append(f"""
<b>{G.nodes[node]['name']}</b><br>
Category: {category.title()}<br>
Click to learn more
""")
# Make key nodes larger
node_sizes.append(45 if node in key_nodes else 35)
# Create separate traces for nodes
node_trace = go.Scatter(
x=node_x, y=node_y,
mode='markers',
hoverinfo='text',
hovertext=node_hover,
marker=dict(
showscale=False,
color=node_colors,
size=node_sizes,
line_width=3,
line=dict(color='white')
)
)
# Add text annotations for each node
annotations = []
for i, (x, y, text) in enumerate(zip(node_x, node_y, node_text)):
# Adjust vertical offset based on text length
y_offset = 0.15 if ' ' in text else 0.1
annotations.append(
dict(
x=x,
y=y + y_offset,
text=text,
showarrow=False,
textangle=0, # No tilting
font=dict(
size=14,
color='white',
family='Arial Black'
),
xanchor='center',
yanchor='bottom'
)
)
# Create figure with adjusted layout
fig = go.Figure(data=[edge_trace, node_trace],
layout=go.Layout(
showlegend=False,
hovermode='closest',
margin=dict(b=20, l=5, r=5, t=40),
xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
yaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
plot_bgcolor='#1E1E1E',
paper_bgcolor='#1E1E1E',
font=dict(color='white', size=14, family='Arial'),
height=1200,
dragmode='pan', # Enable panning
annotations=annotations + [
dict(
text="Hover over nodes to see details<br>Use pan mode to move around",
showarrow=False,
xref="paper",
yref="paper",
x=0,
y=1.1,
font=dict(size=16, color='white', family='Arial Black')
)
]
))
# Add arrows to edges
for edge in G.edges():
x0, y0 = pos[edge[0]]
x1, y1 = pos[edge[1]]
# Calculate arrow position (80% along the edge)
arrow_x = x0 + 0.8 * (x1 - x0)
arrow_y = y0 + 0.8 * (y1 - y0)
fig.add_annotation(
x=arrow_x,
y=arrow_y,
axref="x",
ayref="y",
ax=x0,
ay=y0,
xref="x",
yref="y",
showarrow=True,
arrowhead=2,
arrowsize=1,
arrowwidth=2,
arrowcolor="#888"
)
# Add interactive features
fig.update_layout(
modebar=dict(
add=['drawopenpath', 'eraseshape'],
remove=['lasso2d', 'select2d']
)
)
return fig
def show():
"""Display the interactive intake graph."""
st.title("Customized Learning Path")
# Create two columns for layout
col1, col2 = st.columns([2, 1])
with col1:
st.info("""
This interactive flowchart visualizes your personalized learning journey from enrollment to curriculum.
- Hover over nodes to see detailed information
- Follow the arrows to understand the learning progression
- Explore different paths based on your profile
""")
# Create and display the graph
G = create_intake_graph()
fig = create_interactive_graph(G)
st.plotly_chart(fig, use_container_width=True)
with col2:
st.subheader("Bloom's Taxonomy Research")
st.markdown("""
### Key Research Papers
#### Original Taxonomy (1956)
- [Bloom, B. S. (1956). Taxonomy of Educational Objectives: The Classification of Educational Goals](https://doi.org/10.1177/001316445601600310)
#### Revised Taxonomy (2001)
- [Anderson, L. W., & Krathwohl, D. R. (2001). A Taxonomy for Learning, Teaching, and Assessing](https://doi.org/10.1207/s15430421tip4104_2)
#### Digital Age Applications
- [Churches, A. (2008). Bloom's Digital Taxonomy](https://doi.org/10.1007/978-1-4419-1428-6_1)
#### Modern Learning Applications
- [Armstrong, P. (2010). Bloom's Taxonomy](https://cft.vanderbilt.edu/guides-sub-pages/blooms-taxonomy/)
### Key Concepts
#### Cognitive Process
1. **Remember**: Recall facts and basic concepts
2. **Understand**: Explain ideas or concepts
3. **Apply**: Use information in new situations
4. **Analyze**: Draw connections among ideas
5. **Evaluate**: Justify a stand or decision
6. **Create**: Produce new or original work
#### Knowledge Dimensions
- **Factual**: Basic elements
- **Conceptual**: Interrelationships
- **Procedural**: How to do something
- **Metacognitive**: Knowledge of cognition
""")
# Add a legend for key nodes with summaries
st.subheader("Key Learning Path Components")
key_nodes = {
'Student Enrollment': {
'color': '#2E7D32',
'summary': 'Initial entry point where students begin their learning journey'
},
'Learner Profile Assessment': {
'color': '#1565C0',
'summary': 'Comprehensive evaluation of student background and capabilities'
},
'Profile Classification': {
'color': '#6A1B9A',
'summary': 'Categorization of student profiles based on assessment results'
},
'Learner Archetype': {
'color': '#BF360C',
'summary': 'Identification of student learning style and preferences'
},
"Bloom's Taxonomy Outcomes": {
'color': '#283593',
'summary': 'Framework for defining learning objectives and outcomes'
},
'Personalized Clustering Curriculum': {
'color': '#4527A0',
'summary': 'Final customized learning path based on all assessments'
}
}
for node, info in key_nodes.items():
st.markdown(f"""
<div style='background-color: {info['color']}; padding: 10px; border-radius: 5px; margin-bottom: 10px;'>
<div style='color: white; font-weight: bold;'>{node}</div>
<div style='color: white; font-size: 0.9em;'>{info['summary']}</div>
</div>
""", unsafe_allow_html=True)