如何在Matplotlib/Seaborn中使次X轴与主X轴按比例对齐?
Got it, let's tackle that dual X-axis alignment problem you're facing. Your goal is to have the top X-axis (showing numeri values) align proportionally with the main time X-axis—meaning each numeri tick should sit exactly above its corresponding time value on the main axis. Here's how to make that happen:
Core Issue Explanation
By default, ax.twiny() just creates a new X-axis that shares the Y-axis but has independent ticks. To align them proportionally, we need to explicitly map each numeri value to its corresponding time value from your data, then set the top axis ticks to those mapped positions.
Modified Code with Alignment
import matplotlib import matplotlib.pyplot as plt import seaborn as sns import pandas as pd from matplotlib.ticker import ScalarFormatter numeri = [1000, 10000, 100000, 1000000, 5000000,10000000, 50000000, 100000000, 250000000] # Replace with your actual num_cores list num_cores = [1, 2, 4, 6, 8] def plot_time(): matplotlib.use('TkAgg') sns.set_context('talk') plt.title('CPU Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz') data_df = pd.melt(df_cores_shuffle, 'Num Cores') ax = sns.lineplot( data=data_df, x='value', y='Num Cores', hue='Num Cores', palette=["#1f77b4", "#00FF00", "#00FFFF", "#00BFFF", "#8A2BE2"] ) ax.set(xlabel='Time (Seconds)', ylabel='# Cores') ax.set(yticks=num_cores) # ---------------- Critical Dual Axis Setup ---------------- # Grab the time values corresponding to each numeri (using first core's data as reference) # This assumes df_cores_shuffle has columns: 'Num Cores' + all values in numeri time_mapping = df_cores_shuffle[df_cores_shuffle['Num Cores'] == num_cores[0]][numeri].values[0] # Create the top X-axis ax2 = ax.twiny() # Set top axis tick positions to the corresponding time values on the main axis ax2.set_xticks(time_mapping) # Label those positions with the numeri values ax2.set_xticklabels(numeri) # Match the top axis range to the main axis to keep alignment tight ax2.set_xlim(ax.get_xlim()) # Add label for the top axis ax2.set_xlabel('Numeri') # Format large numeri values nicely with scientific notation ax2.xaxis.set_major_formatter(ScalarFormatter(useMathText=True)) ax2.ticklabel_format(style='sci', axis='x', scilimits=(0, 0)) plt.show()
Key Breakdown
time_mapping: We extract the exact time values from your raw data that correspond to eachnumerientry. Using the first core's data works here because we just need a consistent proportional relationship betweennumeriand time.ax2.set_xticks(time_mapping): This binds the top axis ticks to the exact positions on the main time axis, ensuring perfect proportional alignment.ax2.set_xticklabels(numeri): Swaps the time-based tick labels with yournumerivalues, so the top axis shows what you need while staying aligned.- Scientific Notation: The
ScalarFormattercleans up those largenumerivalues so they don't clutter the plot.
Alternative: Using a Function (If You Know the Relationship)
If you have a mathematical relationship between numeri and time (e.g., time = k * numeri + b), you can use a function-based scale instead:
def numeri_to_time(x): # Replace with your actual conversion formula return 0.00001 * x + 0.5 def time_to_numeri(x): return (x - 0.5) / 0.00001 ax2.set_xscale('function', functions=(numeri_to_time, time_to_numeri)) ax2.set_xticks(numeri)
But using the raw data mapping is more accurate for real-world datasets that might not fit a perfect linear/nonlinear function.
内容的提问来源于stack exchange,提问作者Salvatore Danilo Palumbo

