|
164 | 164 | + "Actionability: %{customdata[1]}<br>" |
165 | 165 | + "Business Value: %{customdata[2]}<br>" |
166 | 166 | ) |
167 | | - |
| 167 | + |
168 | 168 | # Improve text display with wrapping and better visibility |
169 | 169 | # Don't set textposition here as we'll handle it individually for each point |
170 | | - |
| 170 | + |
171 | 171 | # Add text wrapping for better readability and prevent overlap |
172 | 172 | # Create a list of wrapped text labels and assign different positions to prevent overlap |
173 | 173 | wrapped_labels = [] |
174 | 174 | text_positions = [] |
175 | | - |
| 175 | + |
176 | 176 | # First, wrap the text labels |
177 | 177 | for name in plot_df["Name"]: |
178 | 178 | # Split long names into multiple lines (max 15 chars per line) |
179 | 179 | if len(name) > 15: |
180 | 180 | words = name.split() |
181 | 181 | lines = [] |
182 | 182 | current_line = "" |
183 | | - |
| 183 | + |
184 | 184 | for word in words: |
185 | 185 | if len(current_line + " " + word) > 15 and current_line: |
186 | 186 | lines.append(current_line) |
|
190 | 190 | current_line += " " + word |
191 | 191 | else: |
192 | 192 | current_line = word |
193 | | - |
| 193 | + |
194 | 194 | if current_line: # Add the last line |
195 | 195 | lines.append(current_line) |
196 | | - |
| 196 | + |
197 | 197 | wrapped_labels.append("<br>".join(lines)) |
198 | 198 | else: |
199 | 199 | wrapped_labels.append(name) |
200 | | - |
| 200 | + |
201 | 201 | # Create a grid-based positioning system to prevent overlap |
202 | 202 | # Define possible text positions |
203 | 203 | positions = [ |
204 | | - "top center", "top right", "top left", |
205 | | - "bottom center", "bottom right", "bottom left", |
206 | | - "middle right", "middle left" |
| 204 | + "top center", |
| 205 | + "top right", |
| 206 | + "top left", |
| 207 | + "bottom center", |
| 208 | + "bottom right", |
| 209 | + "bottom left", |
| 210 | + "middle right", |
| 211 | + "middle left", |
207 | 212 | ] |
208 | | - |
| 213 | + |
209 | 214 | # Group points that are close to each other |
210 | 215 | # This is a simplified approach - we'll use a grid-based system |
211 | 216 | grid_size = 0.5 # Size of each grid cell |
212 | 217 | grid = {} # Dictionary to store points in each grid cell |
213 | | - |
| 218 | + |
214 | 219 | for i, row in plot_df.iterrows(): |
215 | 220 | # Calculate grid position |
216 | 221 | grid_x = int(row["Feasibility_jitter"] / grid_size) |
217 | 222 | grid_y = int(row["Actionability_jitter"] / grid_size) |
218 | 223 | grid_key = (grid_x, grid_y) |
219 | | - |
| 224 | + |
220 | 225 | # Add point to grid |
221 | 226 | if grid_key not in grid: |
222 | 227 | grid[grid_key] = [] |
223 | 228 | grid[grid_key].append(i) |
224 | | - |
| 229 | + |
225 | 230 | # Assign positions to avoid overlap |
226 | 231 | for grid_key, indices in grid.items(): |
227 | 232 | if len(indices) == 1: |
|
235 | 240 | text_positions[point_idx] = positions[position_idx] |
236 | 241 | else: |
237 | 242 | text_positions.append(positions[position_idx]) |
238 | | - |
| 243 | + |
239 | 244 | # Ensure we have a position for each point |
240 | 245 | while len(text_positions) < len(plot_df): |
241 | 246 | text_positions.append("top center") |
242 | | - |
| 247 | + |
243 | 248 | # Update the text with wrapped labels and positions |
244 | 249 | fig.update_traces( |
245 | 250 | text=wrapped_labels, |
|
314 | 319 | font_size=12, |
315 | 320 | font_family="Arial", |
316 | 321 | bordercolor="#DFE2E6", |
317 | | - namelength=-1 # Show the full label name |
| 322 | + namelength=-1, # Show the full label name |
318 | 323 | ), |
319 | 324 | # Add some margin to ensure text labels have room |
320 | 325 | margin=dict(l=50, r=50, t=50, b=50), |
|
0 commit comments