スプレッドシートをバックエンドにした社内データアプリ構築方法
本記事では、スプレッドシートをバックエンドにして社内データアプリを構築するための複数の手段を紹介します。それぞれの手段のメリット・デメリットのまとめに加え、ニーズの高まっているAI機能の観点からの違いについてもご紹介します。
多くのチームでは、その利便性の高さから日々のデータをGoogleスプレッドシートで蓄積・管理することが珍しくありません。では、いざスプレッドシートをバックエンドとしてデータアプリを構築しようとするとどのような手段があるのでしょうか?
コードベース / ローコード / ノーコード
社内データアプリ構築の手段を分類すると、コードベースでの開発 / ローコードツールでの開発 / ノーコードツールでの構築に分類されます。それぞれの概要と代表的なサービスは以下のとおりです。
コードベース
コードベースでデータアプリを構築します。オープンソースのフレームワークが複数存在し、コードベースでの開発ではありますが、あらかじめ用意されたコンポーネントを使って素早くアプリ構築をすることが可能です。オープンソースのためデプロイ先を選べることも特徴です。
[代表的なツール]
- Streamlit:https://streamlit.io/
- Evidence:https://evidence.dev/
- Morph:https://www.morph-data.io/ja
ローコード
コードとGUIを組み合わせてデータアプリを構築します。シンプルな機能 / UIのアプリであれば、GUIのみでも構築できるため、簡単なアプリであれば非エンジニアの人でも構築ができます。ノーコードに比べると、コードを書くことで柔軟性を持った機能を作ることも可能ですが、コードベースと比べると自由度に制限があります。
[代表的なツール]
- Appsmith:https://www.appsmith.com/
- retool:https://retool.com/
- OutSystems:https://www.outsystems.com/?sc_lang=en
ノーコード
GUIでデータアプリを構築します。そのため、非エンジニアの人でも構築が可能です。一方、複雑な処理やUIには大きな制約があります。構築スキルがそのツールの習熟度に強く依存するため、属人化しやすいことも課題となります。
[代表的なツール]
- AppSheet:https://about.appsheet.com/home/
- Glide:https://www.glideapps.com/
- Softr:https://www.softr.io/
AI機能との親和性
近年ニーズが大きく高まった点として、AI機能の充実 / 親和性があります。その観点で各カテゴリの状況を見ていきます。
コードベース
Langchain や CrewAI などの、AIのためのオープンソースフレームワークを使うことができるため最も自由度高くAI機能を開発することができます。モデルの切り替えや独自のトレーニングデータを用意してファインチューニングをすることができるなど、AI機能との親和性は3カテゴリの中で最も高いと考えられます。社内の業務フローは個社ごとに状況が異なり、かつ複雑になるケースも有るため、自社に最適なAIアプリを構築するという観点では最も推奨されます。
ローコード
一般的に、事前に用意された外部APIを使用することでAI機能を開発することができます。APIのパラーメーターやプロンプトはチューニングが可能ですが、追加データを使った学習や自由なモデル選択などは行うことができません。単一のタスクを実行するユースケースなどでは適合性が高いと考えられます。そのため、AIとの親和性は中程度となります。
ノーコード
あらかじめツールが用意したAI機能を使います。使用は簡単ですが、カスタマイズができないため、使用ケースは限定的となります。PoCや検証を行う分には簡単に行えるという点でメリットがありますが、実際に運用するアプリケーションを使うという観点からは、AI機能との親和性は低くなります。
コードベースのフレームワークの比較
ここでは代表的なコードベースのフレームワークにフォーカスしてスプレッドシートをバックエンドにした簡単なアプリを実際に構築してみます。サンプルのユーザー問い合わせ管理データをためているスプレッドシートをバックエンドにして、そのダッシュボードを構築します。
Streamlit
まずはStreamlitで構築してみます。Streamlitの場合1つのPythonファイルで完結することができます。
import streamlit as st
from google.oauth2 import service_account
import gspread
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime
# Add a title to the app
st.title('Dashboard')
# Google Sheets Authentication
scopes = [ 'https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive'
]
json_file_path = os.path.join(os.path.dirname(__file__), "../credential.json")
credentials = service_account.Credentials.from_service_account_file(json_file_path, scopes=scopes)
gc = gspread.authorize(credentials)
# Get data from Google Sheets
SP_SHEET_KEY = '{Sheet ID}' # sheet id (which can be found in the URL of the Google Sheet, after https://docs.google.com/spreadsheets/d/)
sh = gc.open_by_key(SP_SHEET_KEY)
SP_SHEET = 'test' # Sheet name
worksheet = sh.worksheet(SP_SHEET)
data = worksheet.get_all_values() # Get all data from the sheet
df = pd.DataFrame(data[1:], columns=data[0]) # Convert data to DataFrame
# Display original DataFrame (limited to 100 rows with scrolling)
st.subheader('Original Data')
st.dataframe(df.head(100), height=400) # height parameter adds scrolling capability
# Check if 'Created Date' column exists
if 'Created Date' in df.columns:
# Convert to datetime format (adjust format as needed)
df['Created Date'] = pd.to_datetime(df['Created Date'])
# Group by date and count records
count_by_date = df.groupby(df['Created Date'].dt.date).size().reset_index()
count_by_date.columns = ['Created Date', 'Count']
# Sort by Created Date in descending order
count_by_date = count_by_date.sort_values('Created Date', ascending=False)
# Create two columns for side-by-side display
st.subheader('Record Count by Date')
col1, col2 = st.columns([3, 2]) # Adjust the ratio to make the first column wider
# Display grouped DataFrame in the first column
with col1:
st.dataframe(count_by_date.head(100), height=400)
# Create line chart in the second column
with col2:
# For the chart, we need to sort by date in ascending order
chart_data = count_by_date.sort_values('Created Date', ascending=True)
st.line_chart(chart_data.set_index('Created Date'))
else:
st.error("'Created Date' column not found in the DataFrame. Please check the column name.")
st.write("Available columns:", df.columns.tolist())
Evidence
続いてEvidenceを試します。EvidenceはSvelteKitというJSフレームワークでできているため、Node.jsの環境が必要になります。
## Check data connection
```sql gsheets
select * from googlesheets.test_test
```
## Count group by date
```sql count_groupby_date
select "Created Date" as date ,
count(*) as count
from googlesheets.test_test
group by "Created Date"
order by "Created Date" DESC
```
## Dashboard
<Grid cols=2>
<DataTable data={count_groupby_date}/>
<LineChart
data = {count_groupby_date}
y = count
title = 'chart'
/>
</Grid>
アプリは以下のようになります。SQLのソースコードが一緒に表示される点が特徴ですね。
Morph
最後にMorphフレームワークです。MorphはPythonとマークダウンでファイルを分割して構築する点が特徴です。また、Pythonコードは通常の関数の形式で書けるため、学習コストも低く感じます。
# Get spreadsheet data
import pandas as pd
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import os
import morph
from morph import MorphGlobalContext
@morph.func
def get_gsheets(context: MorphGlobalContext):
# Configure authentication information
json_path = os.path.join(os.path.dirname(__file__), "../credential.json")
scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
# get certification information
credentials = ServiceAccountCredentials.from_json_keyfile_name(json_path, scope)
client = gspread.authorize(credentials)
# Open Spreadsheet
spreadsheet = client.open_by_key("Sheet ID")
worksheet = spreadsheet.worksheet("Sheet name")
# Get data and convert to a DataFrame
data = worksheet.get_all_values()
df = pd.DataFrame(data[1:], columns=data[0])
return df
## Display of aggregated table
import pandas as pd
import morph
from morph import MorphGlobalContext
@morph.func()
@morph.load_data("get_gsheets")
def group_by_date(context: MorphGlobalContext):
df = context.data["get_gsheets"]
# Group by Created Date and count records, then sort by date in descending order
grouped_df = df.groupby('Created Date').size().reset_index(name='count')
grouped_df = grouped_df.sort_values('Created Date', ascending=False)
return grouped_df
# Display of Chart
import plotly.express as px
import pandas as pd
import morph
from morph import MorphGlobalContext
@morph.func()
@morph.load_data("group_by_date")
def group_by_date_chart(context: MorphGlobalContext):
df = context.data["group_by_date"]
df['Created Date'] = pd.to_datetime(df['Created Date'])
df['count'] = pd.to_numeric(df['count'], errors='coerce')
# Create a line chart using plotly
fig = px.line(df, x='Created Date', y='count', title='Record Count by Created Date')
return fig.to_html()
{/* Frontend */}
## Dashboard
<DataTable
loadData="get_gsheets"
height={300}
/>
<Grid cols="2">
<div>
## Table
<DataTable
loadData="group_by_date"
height={300}
/>
</div>
<div>
## Chart
<Embed
loadData="group_by_date_chart"
height={300}
width={800}
/>
</div>
</Grid>
比較してみた感想
Pythonに慣れていればStreamlitとMorphがやりやすく感じられるはずです。もしあなたがデータアナリストでSQLに習熟しているけれどPythonの経験があまりない場合はEvidenceを気にいると思います。
また、構築するデータアプリがダッシュボードアプリの場合は、予め用意されたチャートコンポーネントが多いEvidenceが、コード量を少なく楽にダッシュボード構築ができます。もしAI機能やダッシュボード以外の機能を設けたい場合は、StreamlitやMorphが適した選択肢になります。
UIを柔軟に作り込みたい場合はMorphが適した選択肢になると感じました。MorphはReactを使ってカスタムコンポーネントを作ったり、フロントエンドのMDXファイルにスタイルを柔軟に適用できるため、自由度高くUI表現をすることが可能だからです。
各カテゴリのメリット / デメリットとおすすめされるユースケース
メリット | デメリット | おすすめユースケース | |
---|---|---|---|
コードベース | ・AI機能開発が自由に行える ・広く認知のあるプログラミング言語のため属人性が低い。 |
・非エンジニアが構築できない | ・社内で実運用するAIアプリの開発 ・ダッシュボードアプリの開発 |
ローコード | ・GUIだけでも開発ができ、必要な部分だけエンジニアに依頼するといった開発が可能。 ・一定のカスタマイズが可能。 |
・AI機能のカスタマイズが難しい。 ・コードベースよりはUI表現に制約がある |
・AI機能がワークフローのメインではないデータアプリの開発 ・シンプルな機能のアプリ開発 |
ノーコード | ・非エンジニアでも開発できる。 ・構築が速い。 |
・開発スキルがツール習熟度に依存する ・UI / 機能の制約が大きい ・AI機能の拡張性が低い |
・AIのPoCや検証用のアプリ開発 ・シンプルな機能のアプリ開発 |
まとめ
スプレッドシートをバックエンドにしたデータアプリ開発において、ノーコード、ローコード、コードベースを比較すると、実現できる機能やUIの自由度と、構築の速さ、必要とされるエンジニアリングのスキルがトレードオフになることがわかりました。シンプルなニーズを満たすための単一機能アプリ、PoC用のアプリであれば、ノーコード、ローコード開発でも対応できますし、速さを考慮するとその方が良い選択肢になり得ます。一方、現場固有のニーズに対応し、実運用していくための社内データアプリを構築する場合はコードベースに分があると感じました。特に、今後のAI機能ニーズを考慮すると、PythonフレームワークであるStreamlitやMorphは有力な選択肢となります。ぜひ試してみてください。
Discussion