Creating a Stock Market Treemap Using Python
Learn how to create a dynamic stock market treemap using Python for data processing and React.js for visualization, leveraging the EODHD API for real-time data.
We found a fascinating treemap on the Finviz website and were inspired to create something similar using the EODHD APIs fundamentals data, Python, and React.js.
We researched the data available through the EODHD APIs and identified the appropriate API endpoints. Additionally, we explored the Python and React.js libraries that could be used to create such visualizations. This type of data representation is known as a treemap.
Sourcing the Data
The data we need will come from the EODHD Fundamental APIs. To access the required data, you will need a subscription that includes Fundamental Data. It’s important to note that there are daily limits on data retrieval. While working on this article, we exceeded the daily limit on one of the days, which is around 5000 requests. Creating the full Finviz treemap by “Sector” would require a substantial number of requests. To stay within the limits, we used the 4300 “Common Stocks” listed on the NASDAQ for this tutorial.
Start by creating a new Python project and installing the EODHD Python library. Then, create a configuration file named “config.py” with the following content:
API_KEY="YOUR API KEY"
Next, create a Python script to retrieve a list of the “Common Stocks” on the “NASDAQ”. The “list_symbols” variable below should contain the list of symbols, e.g., “AAPL.US”.
Iterate through the symbols and request the fundamental data for each one. This process may take some time. Once the 4300 entries have been processed, save the results in “data.csv” and “data.json” for further processing.
After examining the Fundamental Data (which is extensive), we identified that the information needed includes the “Sector” from “General” and the “MarketCapitalization” from “Highlights”.
import config as cfg
from eodhd import APIClient
def main() -> None:
api = APIClient(cfg.API_KEY)
df_symbols = api.get_exchange_symbols("US")
df_symbols = df_symbols[df_symbols["Exchange"] == "NASDAQ"]
df_symbols = df_symbols[df_symbols["Type"] == "Common Stock"]
df_symbols = df_symbols[["Code"]] + ".US"
list_symbols = df_symbols["Code"].tolist()
# print(list_symbols)
results = []
for ticker in list_symbols:
print(f"Processing: {ticker} :")
json_data = api.get_fundamentals_data(ticker)
result = {}
result["Ticker"] = ticker
result["Sector"] = json_data["General"]["Sector"]
result["MarketCapitalization"] = json_data["Highlights"]["MarketCapitalization"]
print(result)
results.append(result)
print("Length: ", len(results))
with open("data.json", "w") as file:
json.dump(results, file, indent=4)
df = pd.DataFrame(results)
df.to_csv("data.csv", index=False)
print(df)
Preprocessing the Data
The next step involves reading the “data.csv” into a Pandas DataFrame and preprocessing it. This part can be divided into several sections. First, we’ll filter the data to include only the “Technology” sector. We’ll remove any null values using “dropna” and convert the relevant column to an integer type.
df = pd.read_csv("data.csv")
df_technology = df[df["Sector"] == "Technology"]
df_technology = df_technology.dropna(subset=["MarketCapitalization"])
df_technology["MarketCapitalization"] = df_technology[
"MarketCapitalization"
].astype(int)
Next, we’ll narrow down the dataset to the 10 largest companies by “MarketCapitalization”. The “MarketCapitalization” is listed in millions of USD. We’ll convert this to a percentage and round it to two decimal places for better visual representation.
df_technology_top10 = df_technology.nlargest(10, "MarketCapitalization")
df_technology_top10["Percentage"] = ((
df_technology_top10["MarketCapitalization"]
/ df_technology_top10["MarketCapitalization"].sum()
) * 100).round(2)
Our goal is to create a JSON string that can be easily loaded by a React.js application. Most libraries typically expect columns named “name” and “value”, and sometimes “children”. To prepare for this, we’ll drop the “Sector” column since we know it’s “Technology” and the “MarketCapitalization” column since we’ll use “Percentage” instead. We’ll then rename the columns to map “Ticker” to “name”, “Percentage” to “value”, and set “children” to None.
df_technology_top10.drop(columns=["Sector", "MarketCapitalization"], inplace=True)
df_technology_top10.rename(columns={"Ticker": "name", "Percentage": "value"}, inplace=True)
df_technology_top10["children"] = None
print(df_technology_top10)
Finally, save the results as “technology_top10.csv” for use in the React.js application.
df_technology_top10.to_csv("technology_top10.csv", index=False)
with open("technology_top10.json", "w") as file:
df_technology_top10.to_json(file, orient="records")
Rendering the Treemap in Python
To render a treemap in Python, several libraries are available, with “squarify” being one of the most popular. It uses “matplotlib” for visualization. While effective, it may seem quite basic.
import squarify
import matplotlib.pyplot as plt
labels = df_technology_top10["name"].tolist()
sizes = df_technology_top10["value"].tolist()
squarify.plot(sizes=sizes, label=labels, alpha=0.7, pad=False)
plt.axis("off")
plt.show()
The good news is that it worked with minimal code. However, the downside is that this is about as good as it gets. Adding additional information isn’t straightforward. It can be done, but it requires all blocks to be the same size, which defeats the purpose. It’s useful to know how to do this, but it doesn’t make for the most visually appealing result in our opinion.
Rendering the Treemap in React.js
We have our “technology_top10.json” file ready to use as input for our React.js web app. The file looks like this:
[{"name":"AAPL.US","value":34.76,"children":null},{"name":"MSFT.US","value":31.71,"children":null},{"name":"NVDA.US","value":13.24,"children":null},{"name":"AVGO.US","value":5.42,"children":null},{"name":"ADBE.US","value":3.19,"children":null},{"name":"ASML.US","value":3.18,"children":null},{"name":"AMD.US","value":2.41,"children":null},{"name":"CSCO.US","value":2.26,"children":null},{"name":"INTC.US","value":2.0,"children":null},{"name":"INTU.US","value":1.84,"children":null}]
We will use the standard “create-react-app” tool to set up a React.js starter application.
% npx create-react-app treemap --template typescript
Once this is completed, you should be able to run the React.js app with the command “npm run start”.
% cd treemap
treemap % npm run start
Please note that we are using a Typescript template with “–template typescript”. We will use the “react-d3-treemap” library, which you can install with the following command: “npm install react-d3-treemap — legacy-peer-deps”.
You will need to make the following modifications to the default code.
- Replace the App.tsx file.
You will find that the content of “technology_top10.json” is included below. To make it work, we replaced “children: null” with “children: []”.
import "./App.css";
import TreeMap from "react-d3-treemap";
import React from "react";
interface TreeMapInPutData {
name: string;
value?: number;
children: Array<TreeMapInPutData> | null;
onClick?: any;
}
export default class App extends React.Component<
unknown,
{ data: TreeMapInPutData }
> {
private treeMapRef: React.RefObject<TreeMap<TreeMapInPutData>>;
constructor(props: {}) {
super(props);
this.state = {
data: {
name: "Technology",
children: [
{ name: "AAPL.US", value: 34.76, children: [] },
{ name: "MSFT.US", value: 31.71, children: [] },
{ name: "NVDA.US", value: 13.24, children: [] },
{ name: "AVGO.US", value: 5.42, children: [] },
{ name: "ADBE.US", value: 3.19, children: [] },
{ name: "ASML.US", value: 3.18, children: [] },
{ name: "AMD.US", value: 2.41, children: [] },
{ name: "CSCO.US", value: 2.26, children: [] },
{ name: "INTC.US", value: 2.0, children: [] },
{ name: "INTU.US", value: 1.84, children: [] },
],
},
};
this.treeMapRef = React.createRef();
}
render() {
return (
<div className="div-style">
<TreeMap<TreeMapInPutData>
nodeStyle={{
fontSize: 12,
paddingLeft: 10,
stroke: "transparent !important",
alignSelf: "center !important",
alignContent: "center !important",
}}
data={this.state.data}
/>
</div>
);
}
}
2. Replace the App.css
.App {
font-family: sans-serif;
text-align: center;
}
.div-style {
display: inline-grid;
grid-template-columns: 30% 70%;
}
And the result appears as follows…
This approach looks and functions significantly better than the Python alternative. Each box has a mouse-over tooltip, and the numbers beneath the symbols represent the percentage of the overall area.
Summary
You might be curious why the entire process wasn’t built solely in React.js. There are several reasons for opting to use Python for data collection and preprocessing.
1. React.js operates on the client side within the user’s browser. All React.js code, including the EODHD API keys, would be exposed to the user. Using Python ensures that data requests to the API remain secure.
2. React.js connecting directly to a third-party API is often blocked if the API is properly configured. EODHD has CORS filters preventing React.js from direct communication.
3. Retrieving the list of symbols and the fundamental data takes over an hour. This duration makes it impractical to perform such tasks front-end in a user’s browser. Therefore, it is more efficient to retrieve, process, and then deliver the final data to the React.js web app.
Please note that this article is for informational purposes only and should not be taken as financial advice. We do not bear responsibility for any trading decisions made based on the content of this article. Readers are advised to conduct their own research or consult with a qualified financial professional before making any investment decisions.
For those eager to delve deeper into such insightful articles and broaden their understanding of different strategies in financial markets, we invite you to follow our account and subscribe for email notifications.
Stay tuned for more valuable articles that aim to enhance your data science skills and market analysis capabilities.