Spaces:
Sleeping
Sleeping
| 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) |