npcpy 1.3.22__py3-none-any.whl → 1.3.23__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
npcpy/memory/kg_vis.py CHANGED
@@ -65,27 +65,27 @@ def visualize_knowledge_graph_final_interactive(kg, filename="knowledge_graph.ht
65
65
  """Updated to work with the new KG structure"""
66
66
  print(f"Generating interactive graph for Gen {kg['generation']} -> {filename}")
67
67
 
68
-
68
+ # Extract facts and concepts from the new structure
69
69
  facts = kg.get("facts", [])
70
70
  concepts = kg.get("concepts", [])
71
71
  fact_to_concept_links = kg.get("fact_to_concept_links", {})
72
72
  concept_links = kg.get("concept_links", [])
73
73
 
74
-
74
+ # Create node map for easy lookup
75
75
  node_map = {}
76
76
  for fact in facts:
77
77
  node_map[fact['statement']] = fact
78
78
  for concept in concepts:
79
79
  node_map[concept['name']] = concept
80
80
 
81
-
82
-
81
+ # Calculate positions in concentric circles
82
+ # Facts in inner circle, concepts in outer circle
83
83
  fact_radius = 300
84
84
  concept_radius = 600
85
85
 
86
86
  node_positions = {}
87
87
 
88
-
88
+ # Position facts
89
89
  if facts:
90
90
  for i, fact in enumerate(facts):
91
91
  angle = (2 * math.pi * i) / len(facts)
@@ -95,7 +95,7 @@ def visualize_knowledge_graph_final_interactive(kg, filename="knowledge_graph.ht
95
95
  'y': fact_radius * math.sin(angle)
96
96
  }
97
97
 
98
-
98
+ # Position concepts
99
99
  if concepts:
100
100
  for i, concept in enumerate(concepts):
101
101
  angle = (2 * math.pi * i) / len(concepts)
@@ -105,10 +105,10 @@ def visualize_knowledge_graph_final_interactive(kg, filename="knowledge_graph.ht
105
105
  'y': concept_radius * math.sin(angle)
106
106
  }
107
107
 
108
+ # Create the network
109
+ net = Network(height="100vh", width="100%", bgcolor="#222222", font_color="white", directed=True)
108
110
 
109
- net = Network(height="100vh", width="100%", bgcolor="
110
-
111
-
111
+ # Add fact nodes
112
112
  for fact in facts:
113
113
  node_id = fact['statement']
114
114
  pos = node_positions.get(node_id, {'x': 0, 'y': 0})
@@ -119,11 +119,11 @@ def visualize_knowledge_graph_final_interactive(kg, filename="knowledge_graph.ht
119
119
  title=title_text,
120
120
  x=pos['x'],
121
121
  y=pos['y'],
122
- color='
122
+ color='#ff6961', # Red for facts
123
123
  physics=False
124
124
  )
125
125
 
126
-
126
+ # Add concept nodes
127
127
  for concept in concepts:
128
128
  node_id = concept['name']
129
129
  pos = node_positions.get(node_id, {'x': 0, 'y': 0})
@@ -134,17 +134,17 @@ def visualize_knowledge_graph_final_interactive(kg, filename="knowledge_graph.ht
134
134
  title=title_text,
135
135
  x=pos['x'],
136
136
  y=pos['y'],
137
- color='
137
+ color='#ffb480', # Orange for concepts
138
138
  physics=False
139
139
  )
140
140
 
141
-
141
+ # Add fact-to-concept edges
142
142
  for fact_statement, concept_names in fact_to_concept_links.items():
143
143
  for concept_name in concept_names:
144
144
  if fact_statement in node_map and concept_name in node_map:
145
- net.add_edge(fact_statement, concept_name, color="
146
-
145
+ net.add_edge(fact_statement, concept_name, color="#8ecae6", width=1)
147
146
 
147
+ # Add concept-to-con
148
148
  def visualize_growth(k_graphs, filename="growth_chart.png"):
149
149
  """
150
150
  Plots Facts and Concepts as separate lines instead of a stacked area.
@@ -158,15 +158,15 @@ def visualize_growth(k_graphs, filename="growth_chart.png"):
158
158
  plt.figure(figsize=(12, 8))
159
159
 
160
160
 
161
- plt.plot(gens, facts_counts, label='Facts', color='
162
- plt.plot(gens, concepts_counts, label='Concepts', color='
163
- plt.plot(gens, total_nodes, label='Total Nodes', color='
161
+ plt.plot(gens, facts_counts, label='Facts', color='#ff6961', marker='o', linestyle='-', linewidth=2)
162
+ plt.plot(gens, concepts_counts, label='Concepts', color='#ffb480', marker='o', linestyle='-', linewidth=2)
163
+ plt.plot(gens, total_nodes, label='Total Nodes', color='#8ecae6', marker='x', linestyle='--', alpha=0.7)
164
164
 
165
165
  plt.xlabel("Generation", fontsize=14)
166
166
  plt.ylabel("Number of Nodes", fontsize=14)
167
167
  plt.legend(loc='upper left', fontsize=20, frameon=False)
168
168
  plt.xticks(gens)
169
- plt.ylim(bottom=0)
169
+ plt.ylim(bottom=0) # Ensure the y-axis starts at 0
170
170
 
171
171
  plt.savefig(filename, dpi=300, bbox_inches='tight')
172
172
  plt.close()
@@ -190,8 +190,8 @@ def visualize_fact_concept_ratio(kg_pairs, filename="fact_concept_ratio.png"):
190
190
  x = np.arange(len(labels))
191
191
  width = 0.35
192
192
  fig, ax = plt.subplots(figsize=(12, 8))
193
- rects1 = ax.bar(x - width/2, before_ratios, width, label='Before Sleep', color='
194
- rects2 = ax.bar(x + width/2, after_ratios, width, label='After Sleep', color='
193
+ rects1 = ax.bar(x - width/2, before_ratios, width, label='Before Sleep', color='#95a5a6')
194
+ rects2 = ax.bar(x + width/2, after_ratios, width, label='After Sleep', color='#2ecc71')
195
195
  ax.set_ylabel("Fact-to-Concept Ratio",)
196
196
  ax.set_xticks(x, labels, fontsize=12, rotation=45, ha="right")
197
197
  ax.legend(fontsize=20, frameon=False)
@@ -208,21 +208,21 @@ def visualize_sleep_process(kg_before, kg_after, filename="sleep_process.png"):
208
208
 
209
209
  fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8))
210
210
 
211
-
211
+ # Before state
212
212
  facts_before = len(kg_before.get('facts', []))
213
213
  concepts_before = len(kg_before.get('concepts', []))
214
214
  ax1.pie([facts_before, concepts_before], labels=['Facts', 'Concepts'],
215
- colors=['
216
-
217
-
215
+ colors=['#ff6961', '#ffb480'], autopct='%1.1f%%')
216
+ #ax1.set_title(f"Before Sleep (Gen {kg_before['generation']})")
218
217
 
218
+ # After state
219
219
  facts_after = len(kg_after.get('facts', []))
220
220
  concepts_after = len(kg_after.get('concepts', []))
221
221
  ax2.pie([facts_after, concepts_after], labels=['Facts', 'Concepts'],
222
- colors=['
223
-
224
-
222
+ colors=['#ff6961', '#ffb480'], autopct='%1.1f%%')
223
+ #ax2.set_title(f"After Sleep (Gen {kg_after['generation']})")
225
224
 
225
+ #plt.suptitle(f"Sleep Process: Generation {kg_before['generation']} to {kg_after['generation']}")
226
226
  plt.savefig(filename, bbox_inches='tight', dpi=300)
227
227
  plt.close()
228
228
  print(f"Saved sleep process visualization to {filename}")
@@ -266,11 +266,11 @@ def visualize_key_experiences(kg, filename="key_experiences.png"):
266
266
  node_colors = []
267
267
  for node in G:
268
268
  if node in top_facts:
269
- node_colors.append('
269
+ node_colors.append('#ff0000') # Bright Red for key facts
270
270
  elif G.nodes[node]['type'] == 'fact':
271
- node_colors.append('
271
+ node_colors.append('#ff6961') # Standard Red for facts
272
272
  else:
273
- node_colors.append('
273
+ node_colors.append('#ffb480') # Orange for concepts
274
274
 
275
275
  plt.figure(figsize=(24, 24))
276
276
  pos = nx.spring_layout(G, k=1.5/math.sqrt(G.number_of_nodes()), iterations=100, seed=42)
@@ -324,10 +324,10 @@ def visualize_concept_trajectories(kg_history, n_pillars=2, n_risers=3, filename
324
324
  centrality_df = pd.concat([centrality_df, s.to_frame()], axis=1)
325
325
  centrality_df = centrality_df.transpose().sort_index()
326
326
 
327
-
327
+ # Pillars: High average centrality
328
328
  pillars = centrality_df.mean().nlargest(n_pillars).index
329
329
 
330
-
330
+ # Rising Stars: Exclude pillars from the candidates to find distinct risers
331
331
  riser_candidates = centrality_df.drop(columns=pillars, errors='ignore')
332
332
  centrality_diff = riser_candidates.iloc[-1].fillna(0) - riser_candidates.iloc[0].fillna(0)
333
333
  risers = centrality_diff.nlargest(n_risers).index
@@ -344,10 +344,10 @@ def visualize_concept_trajectories(kg_history, n_pillars=2, n_risers=3, filename
344
344
  label=fill(concept_name, 20), linewidth=linewidth, alpha=alpha)
345
345
  plt.xlabel("Generation", fontsize=14)
346
346
  plt.ylabel("Degree Centrality", fontsize=14)
347
-
347
+ #plt.title("Notable Concept Trajectories (Pillars vs. Risers)", fontsize=16)
348
348
  plt.xticks(gens)
349
349
  plt.legend(title="Concepts", bbox_to_anchor=(1.05, 1), loc='upper left')
350
-
350
+ #plt.grid(True, linestyle='--', alpha=0.6)
351
351
  plt.ylim(bottom=0)
352
352
  plt.tight_layout()
353
353
  plt.savefig(filename, dpi=300, bbox_inches='tight')
@@ -363,7 +363,7 @@ def visualize_associative_richness(kg_history, filename="associative_richness.pn
363
363
  ari_scores.append(total_links / num_facts if num_facts > 0 else 0)
364
364
 
365
365
  plt.figure(figsize=(12, 8))
366
- plt.plot(gens, ari_scores, marker='o', linestyle='-', color='
366
+ plt.plot(gens, ari_scores, marker='o', linestyle='-', color='#6a0dad', linewidth=2.5, label="System's ARI")
367
367
  plt.axhline(y=1, color='gray', linestyle='--', linewidth=2, label='1-to-1 Mapping Baseline (ARI=1.0)')
368
368
  plt.xlabel("Generation")
369
369
  plt.ylabel("Avg. Concepts per Fact (ARI)")
@@ -384,7 +384,7 @@ def visualize_conceptual_support(kg_history, filename="conceptual_support.png"):
384
384
  csi_scores.append(total_links / num_concepts if num_concepts > 0 else 0)
385
385
 
386
386
  plt.figure(figsize=(12, 8))
387
- plt.plot(gens, csi_scores, marker='o', linestyle='-', color='
387
+ plt.plot(gens, csi_scores, marker='o', linestyle='-', color='#17becf', linewidth=2.5, label="System's CSI")
388
388
  plt.xlabel("Generation")
389
389
  plt.ylabel("Avg. Facts per Concept (CSI)")
390
390
  plt.xticks(gens)
@@ -400,7 +400,7 @@ def visualize_specialist_concepts(kg_history, num_to_show=8, filename="specialis
400
400
  """
401
401
  print(f"Generating Specialist Concept Trajectories chart -> {filename}")
402
402
  centrality_df = pd.DataFrame()
403
- gens = [kg['generation'] for kg in kg_history]
403
+ gens = [kg['generation'] for kg in kg_history] # Define gens here
404
404
 
405
405
  for kg in kg_history:
406
406
  G = _create_networkx_graph(kg)
@@ -424,7 +424,7 @@ def visualize_specialist_concepts(kg_history, num_to_show=8, filename="specialis
424
424
  plt.xlabel("Generation")
425
425
  plt.ylabel("Degree Centrality")
426
426
 
427
- plt.xticks(gens)
427
+ plt.xticks(gens) # Use the 'gens' list, not a single value
428
428
 
429
429
  plt.legend(title="Specialist Concepts", loc=0, fontsize=17, frameon=False)
430
430
  plt.ylim(bottom=0)
@@ -460,8 +460,8 @@ def visualize_static_network(kg, top_n_concepts=25, top_n_facts=50, filename="st
460
460
  plt.figure(figsize=(16, 24))
461
461
 
462
462
 
463
- nx.draw_networkx_nodes(SubG, pos, nodelist=top_facts, node_color='
464
- nx.draw_networkx_nodes(SubG, pos, nodelist=top_concepts, node_color='
463
+ nx.draw_networkx_nodes(SubG, pos, nodelist=top_facts, node_color='#ff6961', node_size=150)
464
+ nx.draw_networkx_nodes(SubG, pos, nodelist=top_concepts, node_color='#ffb480', node_size=1200)
465
465
 
466
466
 
467
467
  nx.draw_networkx_edges(SubG, pos, alpha=0.25, width=0.6, edge_color='gray')
@@ -507,7 +507,7 @@ def visualize_concept_ontology_graph(kg, filename="concept_ontology.png"):
507
507
 
508
508
  pos = nx.spring_layout(Concept_G, k=1.5/math.sqrt(Concept_G.number_of_nodes()), iterations=100, seed=42)
509
509
 
510
- nx.draw_networkx_nodes(Concept_G, pos, node_color='
510
+ nx.draw_networkx_nodes(Concept_G, pos, node_color='#ffb480', node_size=node_sizes)
511
511
  nx.draw_networkx_edges(Concept_G, pos, alpha=0.6, width=1.0, edge_color='gray')
512
512
  nx.draw_networkx_labels(Concept_G, pos, font_size=14, font_family='serif')
513
513
 
@@ -531,13 +531,13 @@ def visualize_top_concept_centrality(kg_history, top_n=5, filename="concept_cent
531
531
 
532
532
  degree_centrality = nx.degree_centrality(G)
533
533
 
534
-
534
+ # Filter for concepts only
535
535
  concept_centrality = {node: cent for node, cent in degree_centrality.items() if G.nodes[node]['type'] == 'concept'}
536
536
 
537
537
  for concept_name, centrality in concept_centrality.items():
538
538
  centrality_data[concept_name][i] = centrality
539
539
 
540
-
540
+ # Find the top N concepts based on their peak centrality
541
541
  sorted_concepts = sorted(centrality_data.keys(), key=lambda c: np.nanmax(centrality_data[c]), reverse=True)
542
542
  top_concepts = sorted_concepts[:top_n]
543
543
 
@@ -545,7 +545,7 @@ def visualize_top_concept_centrality(kg_history, top_n=5, filename="concept_cent
545
545
  gens = [kg['generation'] for kg in kg_history]
546
546
 
547
547
  for concept_name in top_concepts:
548
-
548
+ # Interpolate NaN values for smoother plotting if a concept disappears and reappears
549
549
  s = pd.Series(centrality_data[concept_name])
550
550
  s_interpolated = s.interpolate(method='linear', limit_direction='forward', axis=0)
551
551
  plt.plot(gens, s_interpolated, marker='o', linestyle='-', label=fill(concept_name, 20))
@@ -569,7 +569,7 @@ def visualize_lorenz_curve(kg_history, filename="lorenz_curve.png"):
569
569
 
570
570
  fig, ax = plt.subplots(figsize=(10, 10))
571
571
 
572
-
572
+ # --- Lorenz curve for the first valid generation ---
573
573
  first_gen_kg = next((kg for kg in kg_history if kg.get('facts')), None)
574
574
  if first_gen_kg:
575
575
  G_first = _create_networkx_graph(first_gen_kg)
@@ -577,24 +577,24 @@ def visualize_lorenz_curve(kg_history, filename="lorenz_curve.png"):
577
577
  if degrees_first.size > 0:
578
578
  cum_degrees_first = np.cumsum(degrees_first)
579
579
  ax.plot(np.linspace(0, 1, len(degrees_first)), cum_degrees_first / cum_degrees_first[-1],
580
- label=f"Gen {first_gen_kg['generation']} (Start)", color='
580
+ label=f"Gen {first_gen_kg['generation']} (Start)", color='#1f77b4', linewidth=2)
581
581
 
582
-
582
+ # --- Lorenz curve for the last generation ---
583
583
  last_gen_kg = kg_history[-1]
584
584
  G_last = _create_networkx_graph(last_gen_kg)
585
585
  degrees_last = np.array(sorted([d for n, d in G_last.degree()]))
586
586
  if degrees_last.size > 0:
587
587
  cum_degrees_last = np.cumsum(degrees_last)
588
588
  ax.plot(np.linspace(0, 1, len(degrees_last)), cum_degrees_last / cum_degrees_last[-1],
589
- label=f"Gen {last_gen_kg['generation']} (End)", color='
589
+ label=f"Gen {last_gen_kg['generation']} (End)", color='#ff7f0e', linewidth=2)
590
590
 
591
-
591
+ # --- Line of perfect equality for reference ---
592
592
  ax.plot([0, 1], [0, 1], linestyle='--', color='black', label='Perfect Equality')
593
593
 
594
594
  ax.set_xlabel("Cumulative Share of Nodes", fontsize=14)
595
595
  ax.set_ylabel("Cumulative Share of Connections", fontsize=14)
596
596
  ax.legend(fontsize=12)
597
- ax.set_aspect('equal', adjustable='box')
597
+ ax.set_aspect('equal', adjustable='box') # Ensures the plot is square
598
598
  plt.tight_layout()
599
599
  plt.savefig(filename, dpi=300, bbox_inches='tight')
600
600
  plt.close()
@@ -631,11 +631,11 @@ def visualize_concept_bubble_chart(kg, filename="concept_bubble_chart.png"):
631
631
 
632
632
  central_node = max(concepts, key=concepts.get)
633
633
  fixed_nodes = [central_node]
634
- pos_initial = {central_node: (0, 0)}
634
+ pos_initial = {central_node: (0, 0)} # Pin the most important node at (0,0)
635
635
 
636
636
 
637
637
  pos = nx.spring_layout(Concept_G, pos=pos_initial, fixed=fixed_nodes,
638
- k=1.8/math.sqrt(Concept_G.number_of_nodes()),
638
+ k=1.8/math.sqrt(Concept_G.number_of_nodes()), # Controls spacing
639
639
  iterations=200, seed=42)
640
640
 
641
641
 
@@ -644,7 +644,7 @@ def visualize_concept_bubble_chart(kg, filename="concept_bubble_chart.png"):
644
644
 
645
645
  node_sizes = [concepts[node] * 200 for node in Concept_G.nodes()]
646
646
 
647
- nx.draw_networkx_nodes(Concept_G, pos, node_color='
647
+ nx.draw_networkx_nodes(Concept_G, pos, node_color='#ffb480', node_size=node_sizes, alpha=0.9)
648
648
 
649
649
  for node, (x, y) in pos.items():
650
650
  degree = concepts[node]
@@ -712,51 +712,51 @@ def visualize_centrality_bubble_chart(kg, node_type="concepts", filename="concep
712
712
  radius += 0.20
713
713
  nodes_in_ring = int(nodes_in_ring * 1.5)
714
714
 
715
-
715
+ # Step 4: Draw the plot
716
716
  plt.figure(figsize=(20, 20))
717
717
 
718
718
  if node_type == "both":
719
-
719
+ # Separate and draw by type
720
720
  concept_nodes = [(name, data) for name, data in sorted_nodes if data['type'] == 'concept']
721
721
  fact_nodes = [(name, data) for name, data in sorted_nodes if data['type'] == 'fact']
722
722
 
723
-
723
+ # Draw concepts
724
724
  if concept_nodes:
725
725
  concept_names = [item[0] for item in concept_nodes]
726
726
  concept_sizes = [item[1]['degree'] * 200 for item in concept_nodes]
727
727
  concept_pos = {name: pos[name] for name in concept_names if name in pos}
728
728
  nx.draw_networkx_nodes(None, concept_pos, nodelist=concept_names,
729
- node_color='
730
-
729
+ node_color='#ffb480', node_size=concept_sizes, alpha=0.9)
731
730
 
731
+ # Draw facts
732
732
  if fact_nodes:
733
733
  fact_names = [item[0] for item in fact_nodes]
734
734
  fact_sizes = [item[1]['degree'] * 100 for item in fact_nodes]
735
735
  fact_pos = {name: pos[name] for name in fact_names if name in pos}
736
736
  nx.draw_networkx_nodes(None, fact_pos, nodelist=fact_names,
737
- node_color='
738
-
737
+ node_color='#ff6961', node_size=fact_sizes, alpha=0.9)
739
738
 
739
+ # Add legend for both types
740
740
  from matplotlib.patches import Patch
741
741
  legend_elements = [
742
- Patch(facecolor='
743
- Patch(facecolor='
742
+ Patch(facecolor='#ffb480', label='Concepts'),
743
+ Patch(facecolor='#ff6961', label='Facts')
744
744
  ]
745
745
  plt.legend(handles=legend_elements, loc='upper right', fontsize=14)
746
746
 
747
747
  else:
748
-
748
+ # Single type visualization
749
749
  node_names = [item[0] for item in sorted_nodes]
750
750
  node_sizes = [item[1] * 200 for item in sorted_nodes]
751
751
 
752
-
753
- color = '
752
+ # Choose color based on type
753
+ color = '#ffb480' if node_type == "concepts" else '#ff6961'
754
754
 
755
755
  nx.draw_networkx_nodes(None, pos, nodelist=node_names,
756
756
  node_color=color, node_size=node_sizes, alpha=0.9)
757
757
 
758
758
 
759
- top_nodes = sorted_nodes[:min(20, len(sorted_nodes))]
759
+ top_nodes = sorted_nodes[:min(20, len(sorted_nodes))] # Top 20 nodes only
760
760
 
761
761
  for item in top_nodes:
762
762
  node_name = item[0]
@@ -765,13 +765,13 @@ def visualize_centrality_bubble_chart(kg, node_type="concepts", filename="concep
765
765
  node_type_actual = item[1]['type']
766
766
  else:
767
767
  degree = item[1]
768
- node_type_actual = node_type.rstrip('s')
768
+ node_type_actual = node_type.rstrip('s') # "concepts" -> "concept"
769
769
 
770
770
  if node_name in pos:
771
771
  x, y = pos[node_name]
772
772
  font_size = max(8, 8 + 2 * np.log1p(degree))
773
773
 
774
-
774
+ # Adjust label length based on type
775
775
  if node_type_actual == 'fact':
776
776
  label = fill(node_name, 10)
777
777
  else:
@@ -782,7 +782,7 @@ def visualize_centrality_bubble_chart(kg, node_type="concepts", filename="concep
782
782
 
783
783
  plt.axis('off')
784
784
 
785
-
785
+ # Set axis limits
786
786
  max_coord = radius * 1.1
787
787
  plt.xlim(-max_coord, max_coord)
788
788
  plt.ylim(-max_coord, max_coord)
@@ -798,8 +798,8 @@ def visualize_dual_richness_metrics(kg_history, filename="dual_richness_metrics.
798
798
  print(f"Generating Dual Richness Metrics chart -> {filename}")
799
799
 
800
800
  gens = [kg['generation'] for kg in kg_history]
801
- ari_scores = []
802
- csi_scores = []
801
+ ari_scores = [] # Concepts per Fact
802
+ csi_scores = [] # Facts per Concept
803
803
 
804
804
  for kg in kg_history:
805
805
  num_facts = len(kg.get('facts', []))
@@ -814,14 +814,14 @@ def visualize_dual_richness_metrics(kg_history, filename="dual_richness_metrics.
814
814
  fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 16), sharex=True)
815
815
 
816
816
 
817
- ax1.plot(gens, ari_scores, marker='o', linestyle='-', color='
817
+ ax1.plot(gens, ari_scores, marker='o', linestyle='-', color='#6a0dad', linewidth=2.5, label="System's ARI")
818
818
  ax1.axhline(y=1, color='gray', linestyle='--', linewidth=2, label='1-to-1 Mapping Baseline (ARI=1.0)')
819
819
  ax1.set_ylabel("Avg. Concepts per Fact (ARI)", fontsize=14)
820
820
  ax1.legend(loc='lower right')
821
821
  ax1.set_ylim(bottom=0)
822
822
 
823
823
 
824
- ax2.plot(gens, csi_scores, marker='o', linestyle='-', color='
824
+ ax2.plot(gens, csi_scores, marker='o', linestyle='-', color='#17becf', linewidth=2.5, label="System's CSI")
825
825
  ax2.set_xlabel("Generation", fontsize=14)
826
826
  ax2.set_ylabel("Avg. Facts per Concept (CSI)", fontsize=14)
827
827
  ax2.legend(loc='lower right')