Сначала я следовал существующему соответствующему коду, чтобы достичь следующего результата :

# Generate a Sankey diagram for multiple time points
node_labels = []
for year in range(2000, 2022, 3): # Add node labels for all time points
node_labels += [f'Cropland {year}', f'Forest {year}', f'Shrubland {year}', f'Grassland {year}',
f'Wetland {year}', f'Tundra {year}', f'Impervious surface {year}',
f'Bare areas {year}', f'Water body {year}']
# Define the sources and targets for the Sankey diagram connections
sources = []
targets = []
values = []
# Populate the connections in the Sankey diagram
for idx, matrix in enumerate(transition_matrices):
for i in range(len(matrix)):
for j in range(len(matrix)):
if matrix[j] > 0: # Only connect categories with changes
sources.append(i + idx * len(landcover_classes)) # Source node: for example, class 1 from 2000
targets.append(j + (idx + 1) * len(landcover_classes)) # Target node: for example, class 1 in 2003
values.append(matrix[j]) # Corresponding transition value
# Plot the Sankey diagram
fig = go.Figure(data=[go.Sankey(
node=dict(
pad=15,
thickness=20,
line=dict(color="black", width=0.5),
label=node_labels
),
link=dict(
source=sources,
target=targets,
value=values
)
)])
fig.update_layout(title_text="Landcover Transition Over Multiple Time Periods", font_size=10)
fig.show()
Затем я начал пытаться самостоятельно изменить код, связанный с диаграммой Санки, надеясь понять, что метки находятся слева и внизу, но это не удалось, как показано на рисунке. :

Неосознание необходимости личной переписки
import plotly.graph_objects as go
import numpy as np
import random
# Function to generate random colors
def generate_random_color():
return f'rgba({random.randint(0, 255)}, {random.randint(0, 255)}, {random.randint(0, 255)}, 0.8)'
# Function to plot the continuous Sankey diagram
def plot_continuous_sankey(transition_matrices, year_pairs, labels):
sources = []
targets = []
values = []
all_labels = []
colors = []
num_classes = len(labels)
# Create source, target, and value for each year pair
for k, (start_year, end_year) in enumerate(year_pairs):
matrix = transition_matrices[f'{start_year}-{end_year}']
# Labels for the current year
current_labels = [f'{label} {start_year}' for label in labels]
next_labels = [f'{label} {end_year}' for label in labels]
# Append current and next year's labels to the total label list
all_labels.extend(current_labels)
if k == len(year_pairs) - 1: # Do not add next year’s labels for the last year pair
all_labels.extend(next_labels)
# Iterate over the transition matrix
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
if matrix[i, j] > 0:
# Calculate source and target
sources.append(k * num_classes + i) # Category for the start year
targets.append((k + 1) * num_classes + j) # Category for the end year
values.append(matrix[i, j]) # Transition value
# Generate random colors for each node
for _ in all_labels:
colors.append(generate_random_color())
# Create Sankey diagram data, hide labels to avoid redundant display
fig = go.Figure(go.Sankey(
node=dict(
pad=15,
thickness=20,
line=dict(color="black", width=0.5),
label=[''] * len(all_labels), # Hide node labels
color=colors # Set node colors
),
link=dict(
source=sources,
target=targets,
value=values,
color="lightgray" # Set link color
)
))
# Manually add class labels to ensure they match each node (vertical direction)
for i, label in enumerate(labels):
fig.add_annotation(
x=-0.1, # Position on the left
y=1 - (i * (1.0 / num_classes) + 0.05), # Calculate y-axis position based on the number of classes
text=label,
showarrow=False,
xref="paper",
yref="paper",
font=dict(size=12, color="black")
)
# Manually add year labels to ensure they align with each column (horizontal direction)
for k, (start_year, _) in enumerate(year_pairs):
fig.add_annotation(
x=(k + 0.5) / len(year_pairs), # Calculate x-axis position based on the year pair, +0.5 to center with the column
y=-0.1, # Position at the bottom of the chart
text=f'{start_year}', # Display start year
showarrow=False,
xref="paper",
yref="paper",
font=dict(size=12, color="black")
)
# Update chart layout to ensure enough space on the left and bottom
fig.update_layout(
title_text="Continuous Landcover Transition Sankey Diagram",
font_size=10,
margin=dict(l=150, r=100, t=50, b=100) # Adjust chart margins
)
fig.show()
# Create an empty dictionary to store transition matrices for each year pair
transition_matrices = {}
landcover_classes = ['Cropland', 'Forest', 'Grassland', 'Impervious surface', 'Bare areas', 'Water body']
# Define all year pairs
year_pairs = [
(1985, 1990),
(1990, 1995),
(1995, 2000),
(2000, 2005),
(2005, 2010),
(2010, 2015),
(2015, 2020)
]
# Loop through the year pairs
for start_year, end_year in year_pairs:
# Retrieve landcover data for start and end years
start_landcover = globals()[f'landcover{start_year}']
end_landcover = globals()[f'landcover{end_year}']
# Calculate the landcover transition matrix
translandcover = start_landcover.multiply(10).add(end_landcover)
unique_values = translandcover.reduceRegion(
reducer=ee.Reducer.frequencyHistogram(),
geometry=roi.geometry(),
scale=30,
maxPixels=1e13
).get('remapped').getInfo()
# Initialize transition matrix
transition_matrix = np.zeros((len(landcover_classes), len(landcover_classes)), dtype=int)
# Populate the transition matrix
for key, value in unique_values.items():
lc_start = int(key[0]) # Get the class of the start year
lc_end = int(key[1]) # Get the class of the end year
transition_matrix[lc_start - 1, lc_end - 1] = value
# Store the transition matrix for the year pair in the dictionary
transition_matrices[f'{start_year}-{end_year}'] = transition_matrix
# Call the function to plot the continuous Sankey diagram
plot_continuous_sankey(transition_matrices, year_pairs, landcover_classes)
Подробнее здесь: https://stackoverflow.com/questions/790 ... the-bottom