pythonmatplotlib

Matplotlib vertical grid lines not match points


Could you please explain why vertical grid lines not match points?

enter image description here

Here is my data for plot:

{datetime.datetime(2025, 4, 15, 19, 23, 50, 658000, tzinfo=datetime.timezone.utc): 68.0, datetime.datetime(2025, 4, 16, 19, 31, 1, 367000, tzinfo=datetime.timezone.utc): 72.0, datetime.datetime(2025, 4, 17, 19, 34, 21, 507000, tzinfo=datetime.timezone.utc): 75.0, datetime.datetime(2025, 4, 18, 19, 50, 28, 446000, tzinfo=datetime.timezone.utc): 80.0, datetime.datetime(2025, 4, 19, 19, 57, 15, 393000, tzinfo=datetime.timezone.utc): 78.0, datetime.datetime(2025, 4, 20, 19, 57, 49, 60000, tzinfo=datetime.timezone.utc): 77.0, datetime.datetime(2025, 4, 21, 20, 28, 51, 127710, tzinfo=datetime.timezone.utc): 73.0}

And here is my code:

    fig, ax = plt.subplots(figsize=(12, 6))

    ax.plot(df['Дата'], df['Вес'], marker='o', linestyle='-', color='royalblue', label='Вес')

    ax.scatter(df['Дата'], df['Вес'], color='red', zorder=5)

    ax.set_title('График изменения веса по дням', fontsize=16)
    ax.set_xlabel('Дата', fontsize=12)
    ax.set_ylabel('Вес (кг)', fontsize=12)
    ax.xaxis.set_major_locator(mdates.AutoDateLocator())  # Раз в день

    ax.xaxis.set_major_formatter(mdates.DateFormatter('%d.%m.%Y'))

    plt.setp(ax.xaxis.get_majorticklabels(), rotation=45, ha="right")

    ax.grid(True, linestyle='--', alpha=0.6)

    plt.tight_layout()

Solution

  • There are multiple solutions for it.

    I think using ax.set_xticks(df['Дата']) "to force the ticks to match your actual datetimes" might be better for you when the time of day matters, not just the date.

    The full code:

    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    import pandas as pd
    from datetime import datetime, timezone
    
    data = {
        datetime(2025, 4, 15, 19, 23, 50, 658000, tzinfo=timezone.utc): 68.0,
        datetime(2025, 4, 16, 19, 31, 1, 367000, tzinfo=timezone.utc): 72.0,
        datetime(2025, 4, 17, 19, 34, 21, 507000, tzinfo=timezone.utc): 75.0,
        datetime(2025, 4, 18, 19, 50, 28, 446000, tzinfo=timezone.utc): 80.0,
        datetime(2025, 4, 19, 19, 57, 15, 393000, tzinfo=timezone.utc): 78.0,
        datetime(2025, 4, 20, 19, 57, 49, 60000, tzinfo=timezone.utc): 77.0,
        datetime(2025, 4, 21, 20, 28, 51, 127710, tzinfo=timezone.utc): 73.0
    }
    
    df = pd.DataFrame(list(data.items()), columns=['Дата', 'Вес'])
    
    fig, ax = plt.subplots(figsize=(12, 6), layout='constrained')
    
    ax.plot(df['Дата'], df['Вес'], 
            marker='o', 
            markersize=8,
            markerfacecolor='red',
            markeredgecolor='white',
            markeredgewidth=1.5,
            linestyle='-', 
            linewidth=2,
            color='royalblue', 
            label='Вес')
    
    ax.set_xticks(df['Дата'])
    
    date_fmt = mdates.DateFormatter('%d.%m.%Y\n%H:%M')
    ax.xaxis.set_major_formatter(date_fmt)
    
    ax.grid(True, 
            which='major',
            linestyle='--', 
            linewidth=0.7,
            alpha=0.7)
    
    ax.set_title('График изменения веса по дням', fontsize=16, pad=20)
    ax.set_xlabel('Дата и время измерения', fontsize=12, labelpad=10)
    ax.set_ylabel('Вес (кг)', fontsize=12, labelpad=10)
    
    ax.tick_params(axis='x', which='major', rotation=45, labelsize=10)
    
    fig.autofmt_xdate(ha='center', bottom=0.2)
    
    plt.show()
    

    Another solution is "normalizing datetime to midnight" using df['Дата'] = df['Дата'].dt.normalize(). It might be better when time is not required. You’re plotting daily trends.

    The full code:

    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    import pandas as pd
    import datetime
    
    data = {
        datetime.datetime(2025, 4, 15, 19, 23, 50, 658000, tzinfo=datetime.timezone.utc): 68.0,
        datetime.datetime(2025, 4, 16, 19, 31, 1, 367000, tzinfo=datetime.timezone.utc): 72.0,
        datetime.datetime(2025, 4, 17, 19, 34, 21, 507000, tzinfo=datetime.timezone.utc): 75.0,
        datetime.datetime(2025, 4, 18, 19, 50, 28, 446000, tzinfo=datetime.timezone.utc): 80.0,
        datetime.datetime(2025, 4, 19, 19, 57, 15, 393000, tzinfo=datetime.timezone.utc): 78.0,
        datetime.datetime(2025, 4, 20, 19, 57, 49, 60000, tzinfo=datetime.timezone.utc): 77.0,
        datetime.datetime(2025, 4, 21, 20, 28, 51, 127710, tzinfo=datetime.timezone.utc): 73.0,
    }
    
    df = pd.DataFrame(list(data.items()), columns=["Дата", "Вес"])
    df['Дата'] = df['Дата'].dt.tz_convert(None).dt.normalize()
    
    fig, ax = plt.subplots(figsize=(12, 6))
    ax.plot(df['Дата'], df['Вес'], marker='o', linestyle='-', color='royalblue', label='Вес')
    ax.scatter(df['Дата'], df['Вес'], color='red', zorder=5)
    
    ax.set_title('График изменения веса по дням', fontsize=16)
    ax.set_xlabel('Дата', fontsize=12)
    ax.set_ylabel('Вес (кг)', fontsize=12)
    
    ax.xaxis.set_major_locator(mdates.DayLocator())
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%d.%m.%Y'))
    
    plt.setp(ax.xaxis.get_majorticklabels(), rotation=45, ha="right")
    
    ax.grid(True, linestyle='--', alpha=0.6)
    plt.tight_layout()
    plt.show()
    

    If none of the solutions is not functional for you, please inform me and I will attempt to provide other solution.

    Output:

    enter image description here