Hey! I’m Daria, and I’m a software engineering student with a keen interest in data visualization. I’ve been actively exploring different visualization tools through small pet projects, and I’d like to share my latest demo with you.
In this tutorial, we will create a project that will display a historical ranking of universities around the world. It is interesting to see and analyze which institutions maintain their top positions consistently and which institutions experience significant movement up or down the rankings over the years.
When building the dashboard, we’ll load and structure the dataset, display all the key information in a pivot table, and then create a chart to see the top 10 universities and their ranking trends over time.
Although we’ll look at this specific example here, you can apply the same methodology to many other datasets to create data-like dashboards.
What we will cover:
Tech stack
Let’s talk about the tools we’ll be using so you know what to expect before you go along.
First, we will use Reactionwhich is a popular JavaScript library for creating interactive web interfaces. It helps to create reusable components and manage data efficiently. According to 2025 Stack Overflow Developer SurveyReact is the second most popular web framework.
We will also use Flex Monster Pivot Tablea web component for displaying data in a table format. In general, pivot tables are widely used for data visualization because they allow you to quickly group, aggregate, filter, and explore large data sets from different perspectives.
With Flexmonster, you can easily create reports and customize your information. It easily integrates with almost all popular modern frameworks (like React, which we’re using here!).
Next, we have E-chartswhich complements the detailed data provided by the pivot table. It’s a powerful, open-source charting library that will give us the visual insights we need, offering more than 20 chart types to effectively visualize historical university ranking trends.
Finally, we will use World University Rankings Dataset. It includes three global ranking data (The, ARWUand CWUR), providing information on leading universities from 2012 to 2015 for detailed analytical research. The size of the data set is 186.38 kB.
As a small disclaimer, this tutorial uses React, so some familiarity with that will help you get going. But actually, you can use any other framework that is convenient for you. Flexmonster offers Pivot Table. Many integrations with popular frameworksIncluding Angular, Vue, Svelte, and more.
When we are done with the project, we will get an interactive dashboard like this:
So now that you’re familiar with the tools, let’s get started!
Flexmonster Pivot Table Setup
To get started, you need to integrate Flexmonster into your React project. I’ll show you how it works with React, but you can use other frameworks as well. You can find complete instructions here. Flexmonster documentation.
First, create a React application using Vite:
npm create vite@latest flexmonster-project -- --template react
Also, don’t forget to install npm dependencies:
cd flexmonster-project
npm install
Next, we’ll install the FlexMonster wrapper for React. To do this, use this command:
npm install -g flexmonster-cli
flexmonster add react-flexmonster
Then add the Flexmonster styles and component to your App.jsx file:
import FlexmonsterReact from "react-flexmonster";
import "flexmonster/flexmonster.css";
Loading and displaying data
Now it’s time to create the report object. This is a configuration that defines how the pivot table should load and display data. It describes how the fields should be interpreted, and how the table should organize and aggregate the information.
This is the first part. dataSource. It defines where the data comes from and how it should be read by the pivot table (the format of the data set, the location of the file, and the structure of the fields that will be used).
In our case, we will load a CSV file containing the university ranking dataset and define the fields that will appear in the pivot table:
const report = {
dataSource: {
type: "csv",
filename: "/data/world-university-rankings.csv",
mapping: {
world_rank: { type: "number", caption: "World Rank" },
institution: { type: "string" },
country: { type: "string" },
score: { type: "number", caption: "Score" },
year: { type: "number", caption: "Year" },
},
},
…
}
The second part is the slice section. It defines which subset of the dataset will be displayed and how it should be organized. There, you’ll render a table by setting up steps, rows, and columns. You can also set flatOrder property, where you define the order of the fields in the flat form.
You can get more detailed information about yourself. Slice the object here.. There are so many interesting functional possibilities!
const report = {
…
slice: {
rows: ({ uniqueName: "institution" }),
columns: ({ uniqueName: "(Measures)" }),
measures: (
{ uniqueName: "world_rank", aggregation: "min" },
{
uniqueName: "year",
aggregation: "none",
filter: { members: (`year.(${selectedYear})`) },
},
),
flatOrder: ("institution", "world_rank"),
},
options: {
grid: { type: "flat", showGrandTotals: "off" },
},
};
You will also need to include Flexmonster inside the React component. In this example, we will add FlexmonsterReact tag in the JSX and pass the report object (which we defined earlier) as a property. You can do this with this code snippet:
As a result, we have a pivot table with all information about universities:

Creating charts
For some users, charts are easier to understand than tables, so let’s create some now. I decided to display the top 10 universities in the world using bar charts. Bar charts are commonly used to compare values between categories, and are quite useful for ranking or ranking high performers.
We’ll use ECharts here, but you can easily integrate Flexmonster with it. The easiest chart library for you.
As a first step, make sure to install ECharts in your project:
npm install echarts
To prepare our data for display in charts, we will create prepareData() Function This function selects the names of universities and their ranks, removes any invalid data, sorts them by rank, and keeps only the top 10. It returns two arrays: one with names (for chart labels) and one with ranks (for chart values):
const prepareData = (rawData) => {
const rows = rawData.data
.map((r) => ({ name: r.r0, rank: r.v0 }))
.filter((r) => r.name && !isNaN(r.rank))
.sort((a, b) => a.rank - b.rank)
.slice(0, 10);
return {
labels: rows.map((r) => r.name).reverse(),
values: rows.map((r) => r.rank).reverse(),
};
};
Next, we’ll set the chart options. You’ll need to decide what format your dataset will be displayed in: In this example, we’ll choose a bar chart. We will also set the title (here “Top 10 Universities by Global Ranking”), x-axis (shows rank number) and y-axis (shows names of universities) and tooltip, which shows information when you hover over the bar.
Also, don’t forget to initialize the chart and apply these options. You can do all this with this code snippet:
const drawChart = (rawData) => {
const { labels, values } = prepareData(rawData);
const options = {
title: {
text: "Top 10 Universities by World Rank",
left: "center",
textStyle: { fontSize: 20, fontWeight: "bold" },
},
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
xAxis: { type: "value", name: "Rank" },
yAxis: { type: "category", data: labels },
series: ({ type: "bar", data: values, barMaxWidth: 30 }),
};
chartInstance = echarts.init(chartRef.current);
chartInstance.setOption(options);
};
Also, chart layout is an important part updateCharts() function, which recreates the chart when needed:
const updateChart = (rawData) => {
if (chartInstance) chartInstance.dispose();
drawChart(rawData);
};
So now we can see the chart we created! It might seem a bit basic and really hard to read, but don’t worry – we’ll make it nicer and easier to understand in later sections.

Adding a year filtering button
You may have noticed that the dataset consists of rankings for different years (from 2012 to 2015). It would be great if we could use the entire dataset, not just the information for one year.
To manage this, we will create filtering buttons for each year to provide more direct navigation.
First, we’ll add a div element that contains the buttons for each year:
{(2012, 2013, 2014, 2015).map((year) => (
))}
In the code snippet above, you can see that each button calls handleYearChange(year) When clicked. Let’s now examine what this handler does:
const handleYearChange = (year) => {
setSelectedYear(year);
const pivot = pivotRef.current?.flexmonster;
if (pivot) {
const newReport = {
...report,
slice: {
...report.slice,
measures: (
{ uniqueName: "world_rank", aggregation: "min" },
{
uniqueName: "year",
aggregation: "none",
filter: { members: (`year.(${year})`) },
},
),
},
};
pivot.setReport(newReport);
}
};
This function changes the pivot table report to filter by this year, and refreshes the table. Thus, clicking the button instantly displays only the data for the selected year.
And now we have buttons that display the years from our dataset:

Styling
Finally, here’s my favorite part of every project: customization! I like to experiment with different styles and choose the one that suits me best.
For this dashboard, I chose light violet and white colors to make the interface clean and easy to read. I personally associate a university vibe with these colors, so I think they match our dashboard perfectly. So let’s go through it step by step.
The main container defines the overall layout and background. It centers the content on the page, adds some spacing, and sets the basic font and color.
.app-container {
min-height: 100vh;
width: 100vw;
padding: 32px;
display: flex;
flex-direction: column;
align-items: center;
background: #ebe6f7;
font-family: "Inter", system-ui, -apple-system, sans-serif;
color: #1b2a4e;
}
Next, we’ll style the year filter buttons. They have rounded corners, a soft shadow, and a small hover effect to make the interface feel interactive. The active button gets a violet background so it’s easy to see which year is selected.
.year-btn {
padding: 10px 20px;
background: #ffffff;
border: 1px solid #cdd2e0;
border-radius: 8px;
cursor: pointer;
}
.year-btn:hover {
background: #e1dffa;
}
.year-btn.active {
background: #6c5ce7;
color: white;
}
Also, pivot tables and charts are located within simple containers with rounded corners and light shadows. It separates the components visually and organizes the layout logically.
.pivot-container,
.chart-container {
width: 90%;
background: #ffffff;
border-radius: 12px;
padding: 14px;
box-shadow: 0 6px 20px rgba(15, 35, 95, 0.12);
}
.pivot-container {
height: 56vh;
margin-bottom: 24px;
}
.chart-container {
height: 40vh;
}
And now, here is the result of our work!


wrap up
In this tutorial, we have created an interactive dashboard to see the rankings of the world’s top universities over the years. You learned how to load and display data in a pivot table in a simple and compact way, create a bar chart to show comparative data, and add buttons to filter information by year.
Now you can use these skills to look at other data sets and play with different charts and customization options.
If you want to take a closer look at my code and get detailed styling code, you can check out my GitHub:
I would love to hear your thoughts on this little project. I want to see what you make!