Вот небольшая программа на Python, которая получает налоговые данные через API treasury.gov:
import pandas as pd
import treasury_gov_pandas
# ----------------------------------------------------------------------
df = treasury_gov_pandas.update_records(
url = 'https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v1/accounting/dts/deposits_withdrawals_operating_cash')
df['record_date'] = pd.to_datetime(df['record_date'])
df['transaction_today_amt'] = pd.to_numeric(df['transaction_today_amt'])
tmp = df[(df['transaction_type'] == 'Deposits') & ((df['transaction_catg'].str.contains('Tax')) | (df['transaction_catg'].str.contains('FTD'))) ]
Программа использует следующую библиотеку для загрузки данных:
https://github.com/dharmatech/treasury-gov-pandas.py
Вот как выглядят полученные данные:
>>> tmp.tail(20).drop(columns=['table_nbr', 'table_nm', 'src_line_nbr', 'record_fiscal_year', 'record_fiscal_quarter', 'record_calendar_year', 'record_calendar_quarter', 'record_calendar_month', 'record_calendar_day', 'transaction_mtd_amt', 'transaction_fytd_amt', 'transaction_catg_desc', 'account_type', 'transaction_type'])
record_date transaction_catg transaction_today_amt
371266 2024-04-03 DHS - Customs and Certain Excise Taxes 84
371288 2024-04-03 Taxes - Corporate Income 237
371289 2024-04-03 Taxes - Estate and Gift 66
371290 2024-04-03 Taxes - Federal Unemployment (FUTA) 10
371291 2024-04-03 Taxes - IRS Collected Estate, Gift, misc 23
371292 2024-04-03 Taxes - Miscellaneous Excise 41
371293 2024-04-03 Taxes - Non Withheld Ind/SECA Electronic 1786
371294 2024-04-03 Taxes - Non Withheld Ind/SECA Other 2315
371295 2024-04-03 Taxes - Railroad Retirement 3
371296 2024-04-03 Taxes - Withheld Individual/FICA 12499
371447 2024-04-04 DHS - Customs and Certain Excise Taxes 82
371469 2024-04-04 Taxes - Corporate Income 288
371470 2024-04-04 Taxes - Estate and Gift 59
371471 2024-04-04 Taxes - Federal Unemployment (FUTA) 8
371472 2024-04-04 Taxes - IRS Collected Estate, Gift, misc 127
371473 2024-04-04 Taxes - Miscellaneous Excise 17
371474 2024-04-04 Taxes - Non Withheld Ind/SECA Electronic 1905
371475 2024-04-04 Taxes - Non Withheld Ind/SECA Other 1092
371476 2024-04-04 Taxes - Railroad Retirement 1
371477 2024-04-04 Taxes - Withheld Individual/FICA 2871
В кадре данных есть данные, относящиеся к 2005 году:
>>> tmp.drop(columns=['table_nbr', 'table_nm', 'src_line_nbr', 'record_fiscal_year', 'record_fiscal_quarter', 'record_calendar_year', 'record_calendar_quarter', 'record_calendar_month', 'record_calendar_day', 'transaction_mtd_amt', 'transaction_fytd_amt', 'transaction_catg_desc', 'account_type', 'transaction_type'])
record_date transaction_catg transaction_today_amt
2 2005-10-03 Customs and Certain Excise Taxes 127
7 2005-10-03 Estate and Gift Taxes 74
10 2005-10-03 FTD's Received (Table IV) 2515
12 2005-10-03 Individual Income and Employment Taxes, Not Wi... 353
21 2005-10-03 FTD's Received (Table IV) 15708
... ... ... ...
371473 2024-04-04 Taxes - Miscellaneous Excise 17
371474 2024-04-04 Taxes - Non Withheld Ind/SECA Electronic 1905
371475 2024-04-04 Taxes - Non Withheld Ind/SECA Other 1092
371476 2024-04-04 Taxes - Railroad Retirement 1
371477 2024-04-04 Taxes - Withheld Individual/FICA 2871
Я хотел бы представить эти данные в виде гистограммы с накоплением.
Я открыт для любой библиотеки графиков. Т.е. matplotlib, боке, сюжет и т. д.
Каков хороший способ реализовать это?
Вы можете использовать pandas, он поставляется со встроенными функциями matplotlib, такими как метод plot()
, и вы можете указать, что вам нужна составная гистограмма, как показано ниже (сначала вам нужно повернуть фрейм данных):
# First agg the data
df_agg = df.groupby(['record_date', 'transaction_catg']).agg({'transaction_today_amt': 'sum'}).reset_index()
# Pivot the dataframe
pivot_df = df_agg.pivot(index='record_date', columns='transaction_catg', values='transaction_today_amt')
# Plot stacked bar chart
pivot_df.plot(kind='bar', stacked=True, figsize=(10, 6))
plt.title('Stacked Bar Chart of Transaction Amount by Category')
plt.xlabel('Record Date')
plt.ylabel('Transaction Amount')
plt.xticks(rotation=45)
plt.legend(title='Transaction Category', bbox_to_anchor=(1.05, 1), loc='upper left') # Put legend outside of the plot
plt.tight_layout()
plt.show()
Хм, вы агрегируете данные перед их поворотом. Например, используя groupby, я отредактирую сообщение.
Я создал манекен df и проверил, работает ли он.
Этот код создает DataFrame
со случайными данными транзакции grouped
по date
и category
. Затем это pivots
данные для отображения гистограммы с накоплением, где каждая полоса представляет собой date
, а сегменты стека представляют transaction amounts
для разных категорий. Я надеюсь, что это решение поможет вашему проекту.
И окончательный код показан ниже.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.dates import DayLocator
data = {
'record_date': pd.to_datetime(['2023-10-01', '2023-10-02', '2023-10-03','2023-10-04', '2023-10-05', '2023-10-06','2023-10-07', '2023-10-08', '2023-10-09'] * 5),
'transaction_catg': ['A', 'B', 'C', 'D', 'E'] * 9,
'transaction_today_amt': np.random.randint(100, 1000, 45)
}
tmp = pd.DataFrame(data)
tmp_agg = tmp.groupby(['record_date', 'transaction_catg'])['transaction_today_amt'].sum().reset_index()
tmp_agg['record_date'] = tmp_agg['record_date'].dt.date
pivot_df = tmp_agg.pivot(index='record_date', columns='transaction_catg', values='transaction_today_amt').fillna(0)
ax = pivot_df.plot(kind='bar', stacked=True, figsize=(10, 6))
ax.xaxis.set_major_locator(DayLocator(interval=3))
plt.xticks(rotation=45)
plt.xlabel('Record Date')
plt.ylabel('Transaction Today Amount')
plt.title('Stacked Bar Chart of Transaction Amounts by Category and Date')
plt.show()
Вывод такой:
Мухаммед, спасибо за ваше предложение. Кажется, это работает! Однако есть две проблемы. Если вы попробуете это на реальных данных, это займет очень много времени. Чтобы запустить его, я использовал только последние 1000 записей. Кроме того, ось X неразборчива. Смотрите этот скриншот: i.imgur.com/thMHIOG.png
mdates locators
может помочь решить проблему с осью X. Пришло время, не знаю, как я могу это улучшить. @dharmatech
@dharmatech я отредактировал, добавив locator
. Вам нужно будет выбрать локатор в зависимости от вашего кода. Для вашего кода вы можете использовать MonthLocator
или YearLocator
, это поможет вам решить проблему оси X.
Да, ось X выглядит лучше. Если увеличить масштаб, вот как это будет выглядеть: i.imgur.com/SsV5xWJ.png
Мне удалось загрузить весь набор данных. Единственный недостаток, как я уже упоминал, заключается в том, что производительность пользовательского интерфейса matplotlib очень низкая при таком большом наборе данных. Я могу рассмотреть возможность преобразования этого в боке или сюжет для этого случая.
Я опубликовал ответ на основе ваших предложений: stackoverflow.com/a/78287908/268581
Другая проблема заключается в том, что цвета повторно используются для других категорий. Например, синий используется для двух разных категорий.
@dharmatech, вы можете использовать colormap
пример ax = pivot_df.plot(kind='bar', stacked=True, figsize=(10, 6),colormap = "tab20")
дополнительные варианты можно найти в matplotlib.org/stable/gallery/color/colormap_reference.html
Я преобразовал код в боке. Теперь это довольно быстро! Код доступен здесь. Я также дал вам должное в README. 👍🙂 github.com/dharmatech/tga_taxes.py/tree/main
@dharmatech я оценил
Вот полная программа, основанная на ответе Мухаммеда:
import pandas as pd
import treasury_gov_pandas
import matplotlib.pyplot as plt
import matplotlib
# ----------------------------------------------------------------------
df = treasury_gov_pandas.update_records(
url = 'https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v1/accounting/dts/deposits_withdrawals_operating_cash')
df['record_date'] = pd.to_datetime(df['record_date'])
df['transaction_today_amt'] = pd.to_numeric(df['transaction_today_amt'])
# ----------------------------------------------------------------------
tmp = df[(df['transaction_type'] == 'Deposits') & ((df['transaction_catg'].str.contains('Tax')) | (df['transaction_catg'].str.contains('FTD'))) ]
# tmp.drop(columns=['table_nbr', 'table_nm', 'src_line_nbr', 'record_fiscal_year', 'record_fiscal_quarter', 'record_calendar_year', 'record_calendar_quarter', 'record_calendar_month', 'record_calendar_day', 'transaction_mtd_amt', 'transaction_fytd_amt', 'transaction_catg_desc', 'account_type', 'transaction_type'])
# tmp.tail(20).drop(columns=['table_nbr', 'table_nm', 'src_line_nbr', 'record_fiscal_year', 'record_fiscal_quarter', 'record_calendar_year', 'record_calendar_quarter', 'record_calendar_month', 'record_calendar_day', 'transaction_mtd_amt', 'transaction_fytd_amt', 'transaction_catg_desc', 'account_type', 'transaction_type'])
# ----------------------------------------------------------------------
tmp_agg = tmp.groupby(['record_date', 'transaction_catg'])['transaction_today_amt'].sum().reset_index()
tmp_agg['record_date'] = tmp_agg['record_date'].dt.date
pivot_df = tmp_agg.pivot(index='record_date', columns='transaction_catg', values='transaction_today_amt').fillna(0)
# ax = pivot_df.plot(kind='bar', stacked=True)
# ax = pivot_df.tail(1000).plot(kind='bar', stacked=True)
ax = pivot_df.plot(kind='bar', stacked=True)
ax.xaxis.set_major_locator(matplotlib.dates.DayLocator(interval=10))
plt.xticks(rotation=45)
plt.ylabel('transaction_today_amt')
plt.title('TGA Taxes')
plt.ion()
plt.show()
Если увеличить масштаб, то это выглядит следующим образом:
Недостатком matplotlib является то, что пользовательский интерфейс работает очень медленно при таком большом наборе данных.
Со следующей строкой:
pivot_df = tmp.pivot(index='record_date', columns='transaction_catg', values='transaction_today_amt')
я получаю:ValueError: Index contains duplicate entries, cannot reshape
.