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 '
'.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""" {G.nodes[node]['name']}
Category: {category.title()}
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
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"""
{node}
{info['summary']}
""", unsafe_allow_html=True)