Как не допустить искажения yticks или xticks - PullRequest
0 голосов
/ 08 марта 2020

У меня проблема с установкой xticks и yticks в matplotlib. Я хочу нарисовать линейный график на основе дат и цен (например, BT C price). Я обновляю цены каждые 30 минут, поэтому я хочу, чтобы набор графика рисовался на основе на каждую цену, которую я имею, но показываю только 4 - 5 цен в xticks и показываю дату только один раз в yticks (извините, мой engli sh плохо, я не могу объяснить лучше)

так, я покажет вам здесь:

Я хочу цены (yticks), как это:

enter image description here

и даты (xticks), как:

enter image description here

но мои данные повреждены:

enter image description here

ПОЛНЫЙ КОД:


class PriceChangePlots:

    def __init__(self, session: Session, for_cars: bool):
        self.for_cars = for_cars
        self.media_path = 'media/'
        self.font_nazanin = fm.FontProperties(fname=self.media_path + 'fonts/BNAZANIN.TTF', size=14)
        self.font_yekan = fm.FontProperties(fname=self.media_path + 'fonts/BYekan+.ttf', size=14)
        self.DB = session
        self.chart: Charts = self.DB.query(Charts)
        self.cars = self.DB.query(Prices)

    def get_model_data(self, model_code):
        cars = self.cars

        # get model data from database
        models = cars.with_entities(
            Prices.datetime, Prices.price).filter(
            Prices.datetime > datetime.now() - timedelta(weeks=1)).filter_by(
            model_code=model_code).all()

        # convert datetime to persian dates
        JD = jdatetime.date.fromgregorian  # make an object of datetime converter
        models = list(
            map(
                lambda details:
                (JD(date=details[0].date()), details[1]),  # tuple of details
                #          ^^^ DATE          ^^^ PRICE
                models
            ))

        # make a dictionary to avoid repeat days
        # models = _remove_duplicates(models)
        # data = dict(models)
        return models

    @staticmethod
    def fa(persian_text):
        reshaped_text = arabic_reshaper.reshape(persian_text)
        farsi_text = get_display(reshaped_text)
        return farsi_text

    def line(self, model_code):
        cars = self.cars
        for_cars = self.for_cars

        model: Prices = cars.filter_by(model_code=model_code).first()
        fa = self.fa
        data = self.get_model_data(model_code)
        plt.style.use('default')

        dates = list(map(lambda x: x[0], data))  # dates
        prices = list(map(lambda x: x[1], data))  # prices

        average = np.average(prices)  # average of car price in last 2 weeks
        average = round(average, 2)  # round it with 2 decimals

        # if average is greater than 1M
        if average > 10 ** 6:
            avg_label = round(average / 10 ** 6, 2)
        else:
            avg_label = average

        # check if average have decimals or not
        if avg_label.is_integer():
            avg_label = int(avg_label)

        # average line
        if average > 10 ** 6:
            avg_label = f'{fa("میانگین")}={avg_label}M'
        else:
            avg_label = f'{fa("میانگین")}={avg_label}'

        fig: Figure
        ax: Axes
        fig, ax = plt.subplots()

        dates_array = np.arange(len(dates))

        # prices axe
        a: Line2D = ax.plot(dates_array, prices, linewidth=3)

        # print(type(b))

        ax.plot(dates_array, [average] * len(prices), linestyle='-.', linewidth=2,
                color='#6495ed', label=avg_label)

        ax.fill_between(dates_array, prices, average,
                        where=(prices > average), color='red',
                        alpha=0.2, interpolate=True, label=fa('بزرگتر از میانگین'))

        ax.fill_between(dates_array, prices, average,
                        where=(prices < average), color='green',
                        alpha=0.2, interpolate=True, label=fa('کوچکتر از میانگین'))

        if for_cars:
            title = fa(f"تغییرات قیمت %s %s" % (model.brand, model.model_name))
        else:
            title = fa(f"تغییرات قیمت %s" % model.model_name)

        plt.title(title, fontproperties=self.font_yekan, size=20)

        ax.grid(color='k', linewidth=.5, linestyle=':', axis='y')

        # shorten prices ( price / 1M )
        y_ticks = []
        for price in prices:
            if price > 10 ** 6:
                price = round(price / 10 ** 6, 2)

                if price.is_integer():  # if price have no decimals
                    price = int(price)
                    price = s(price)
                price = f'{price}M'

            else:
                price = float(round(price, 2))
                if price.is_integer():  # if price have no decimals
                    price = int(price)
                    price = s(price)

            y_ticks.append(price)

        # _: Line2D
        # y_data = a[0].get_ydata()

        # plt.yticks(y_data, y_ticks)
        plt.xticks(dates_array, dates, rotation=45)

        fig.text(0.5, 0.55, fa("قیمت روزانه خودرو:\nt.me/CPricesBot"),  # 't.me/CPricesBot',
                 fontsize=40, color='gray', fontproperties=self.font_yekan,
                 ha='center', va='center', alpha=0.30, size=25)

        legend: Legend = ax.legend()

        # change legend font
        text: Text
        for text in legend.texts:
            text.set_fontproperties(self.font_yekan)
            text.set_fontsize(10)

        fig.tight_layout(pad=2)

        # fig.savefig(self.media_path + 'plots/price_change_plots/' + model_code + '.png')
        fig.show()

        plt.close()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...