-2

I want to have good looking chart so that the lines on the graph are rounded, but unfortunately they are joined "sharply". What is wrong with my code. What parameter am I missing?

import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
import pandas as pd

def data_gr():
    fr = pd.read_csv('ramka_wynikowa.csv', sep=';')
    merged_df_database = fr

    # ustalenie kolorów linii
    line_colors = ['#8497B0', '#F6DD60', '#06A297']
    marker_colors = ['#5E7594', '#F2CD16', '#047068']

    # utworzenie wykresu słupkowego
    fig, ax = plt.subplots()
    ax.bar(merged_df_database.index, merged_df_database['quantity'], color='gray', alpha=0.6, edgecolor='none', width=0.8, label='quantity', capstyle='round')

    # dodanie danych do wykresu liniowego
    for i, col in enumerate(['value', 'value_up', 'rebate_value']):
        ax.plot(merged_df_database.index, merged_df_database[col], lw=4, solid_capstyle='round', color=line_colors[i], marker='o', markerfacecolor=marker_colors[i], markeredgecolor=marker_colors[i], linestyle='-', label=col)

    # dodanie legendy i tytułu
    ax.legend()
    ax.set_title('Wykres danych')

    # dodanie podpisów danych
    for x, y, q in zip(merged_df_database.index, merged_df_database['quantity'], merged_df_database['quantity']):
        ax.text(x, y, '{:.1f}'.format(q/1000), ha='center', va='bottom', fontsize=10)

    for col in ['value', 'value_up', 'rebate_value']:
        for x, y, v in zip(merged_df_database.index, merged_df_database[col], merged_df_database[col]):
            ax.text(x, y, '{:.1f}'.format(v/1000), ha='center', va='bottom')

    ax.set_yticks(ax.get_yticks())
    ax.set_yticklabels([f'{int(t / 1000)}' for t in ax.get_yticks()])
    plt.show()

Output:

chart

Below, sample of data

invoice_num;salesman_id;market;quantity;value;customer;fv_date;surname;value_up;rebate_value;price_per_unit;;;
1001152;18;GE;7500.0;9005.12;BA125;12.01.2024;Odp;9725.529600000002;9005.12;1.2006826666666668;;;"7500.0;1.2"
1001154;12;GE;8200.0;9844.88;BA118;22.01.2024;Szy;10632.4704;9844.88;1.2005951219512194;;;"8200.0;1.2"
1001157;18;GE;6500.0;11712.42;AA088;25.01.2024;Odp;12649.413600000002;11712.42;1.8019107692307692;;;"6500.0;1.8"
1001159;18;GE;10300.0;19574.55;AC098;02.02.2024;Odp;21140.514;17617.095;1.9004417475728155;;;"10300.0;1.9"
1001161;18;GE;6900.0;11734.05;AD104;12.02.2024;Odp;12672.774;11734.05;1.700586956521739;;;"6900.0;1.7"
1001164;12;GE;12000.0;14410.85;BA138;15.02.2024;Szy;15563.718;12969.765000000001;1.2009041666666667;;;"12000.0;1.2"
1001166;12;GE;12300.0;25832.22;AF105;27.02.2024;Szy;27898.7976;23248.998000000003;2.100180487804878;;;"12300.0;2.1"
1001169;12;GE;10800.0;20526.42;AG222;03.03.2024;Szy;22168.5336;18473.778;1.9005944444444443;;;"10800.0;1.9"
1001171;18;GE;7500.0;13521.88;BA118;11.03.2024;Odpow;14603.6304;13521.88;1.8029173333333333;;;"7500.0;1.8"
1001174;18;GE;6900.0;11730.14;AH111;16.03.2024;Odpow;12668.5512;11730.14;1.7000202898550725;;;"6900.0;1.7"


2 Answers2

0

Matplotlib's plot function just draws straight lines between points (I think you're trying to use solid_capstyle='round' to "round" things, but that's actually an argument for an errorbar plot and sets the style of the error bar "caps"). What you'll need to do to get "rounded" plots is perform some smoothing or interpolation, using, e.g., the scipy interpolate1d function. For example:

from scipy.interpolate import interpolate1d
import numpy as np

...

for i, col in enumerate(['value', 'value_up', 'rebate_value']):
    # create intepolation function
    ifunc = interpolate1d(
        merged_df_database.index,
        merged_df_database[col],
        kind="cubic",
    )

    # get fine grid (say 500 points) of x-axis points at which to interpolate
    xgrid = np.linspace(
        merged_df_database.index[0],  # grid start value
        merged_df_database.index[-1],  # grid end value
        500,  # number of grid points
    )

    # plot (original) marker points (without lines inbetween)
    ax.plot(
        merged_df_database.index,
        merged_df_database[col],
        color=line_colors[i],
        marker='o',
        markerfacecolor=marker_colors[i],
        markeredgecolor=marker_colors[i],
        linestyle='none',
        label=col
    )
    

    # plot interpolated function
    ax.plot(
        xgrid,
        ifunc(xgrid),
        lw=4,
        color=line_colors[i],
        marker='o',
        markerfacecolor=marker_colors[i],
        markeredgecolor=marker_colors[i],
        linestyle='-',
    )

See also, the answers to this question.

Matt Pitkin
  • 3,989
  • 1
  • 18
  • 32
0

After changes it looks a little bit strange.

enter image description here

    merged_df_database = df_dict['merged_df_database']
    line_colors = ['#8497B0', '#F6DD60', '#06A297']
    marker_colors = ['#5E7594', '#F2CD16', '#047068']

    fig, ax = plt.subplots()
    ax.bar(merged_df_database.index, merged_df_database['quantity'], color='gray', alpha=0.6, edgecolor='none', width=0.8, label='quantity', capstyle='round')

    for i, col in enumerate(['value', 'value_up', 'rebate_value']):
        # create intepolation function
        ifunc = interp1d(
            merged_df_database.index,
            merged_df_database[col],
            kind="cubic",
        )

        # get fine grid (say 500 points) of x-axis points at which to interpolate
        xgrid = np.linspace(
            merged_df_database.index[0],  # grid start value
            merged_df_database.index[-1],  # grid end value
            500,  # number of grid points
        )

        # plot (original) marker points (without lines inbetween)
        ax.plot(
            merged_df_database.index,
            merged_df_database[col],
            color=line_colors[i],
            marker='o',
            markerfacecolor=marker_colors[i],
            markeredgecolor=marker_colors[i],
            linestyle='none',
            label=col
        )

        # plot interpolated function
        ax.plot(
            xgrid,
            ifunc(xgrid),
            lw=4,
            color=line_colors[i],
            marker='o',
            markerfacecolor=marker_colors[i],
            markeredgecolor=marker_colors[i],
            linestyle='-',
        )
    # dodanie legendy i tytułu
    ax.legend()
    ax.set_title('Wykres danych')

    # dodanie podpisów danych
    for x, y, q in zip(merged_df_database.index, merged_df_database['quantity'], merged_df_database['quantity']):
        ax.text(x, y, '{:.1f}'.format(q/1000), ha='center', va='bottom', fontsize=10)

    for col in ['value', 'value_up', 'rebate_value']:
        for x, y, v in zip(merged_df_database.index, merged_df_database[col], merged_df_database[col]):
            ax.text(x, y, '{:.1f}'.format(v/1000), ha='center', va='bottom')

    ax.set_yticks(ax.get_yticks())
    ax.set_yticklabels([f'{int(t / 1000)}' for t in ax.get_yticks()])
    plt.show()