※当ページのリンクには広告が含まれています

3 steps to make motion chart in Excel

2021年9月30日木曜日

application/ software programming

X f B! P L

Motion Graph, Movie Graph, Moving Graph, Animation Graph, Morphing Graph, Dynamic GraphI've been thinking that it would be useful to have a bar graph or pie chart that moves along with time, rather than just a line graph, when graphing time series data or continuous data, so I made a macro to make it as easy as possible. I don't know what to call it: motion graph, morphing graph, animated graph, dynamic graph, etc.



What to want to achieve (details).

Time series data comes up a lot, doesn't it? It could be monthly sales, sales results, number of registered members, future prospects, etc....

Maybe it's the result of weighing a balance.

Let's save the balance's measurement data to an SD card and process it in Excel
https://magtanate.blogspot.com/2017/05/sdexcel.html
DIY360

This kind of data is usually represented as a line graph or a bar graph.

If it was on paper, this would be fine.

However, nowadays, presentations are often done online, and it is necessary to have a technique to make them attractive, and a mere line graph or bar graph is not very interesting or dynamic, which may eventually lead to a lack of persuasiveness.

There is no point in using a graph that is not persuasive. If you are going to use a graph, you should use one that is interesting.

Preference Mapping in R with SensoMineR...Kentucky Fried Chicken
https://magtanate.blogspot.com/2021/09/preference-mapping-by-sensominer.html
DIY360

It would be nice if there was a similar animation function in Powerpoint, but unfortunately there is not. It just pops up item by item, and does not work based on time series data.

I heard that you can use a service called Tableau to make it easier, but you have to pay for it. It's a bit of a hurdle, isn't it? As far as I can tell at the time of posting, it costs about $1000 per person per year, so it's quite expensive.

Also, if you use R or Python, which are strong in data analysis, it is relatively easy to create such moving graphs, and in fact, I have already created a script in R to make it easier for myself.

Unfortunately, in the case of R, if you use the appropriate package (such as ggplot2 or gganimation), the graphs are nice and simple, but on the other hand, they look like scientific papers. It's also difficult to adjust the colors, and it takes a lot of effort to get the desired look. I haven't done it in Python, but I assume it's the same.

On the other hand, with Excel, I can easily tweak the graphs using the mouse. You can change things like background color, transparency, gradients, etc. very easily.

I've always thought that I could just do it in R, and that's what I did, but for user-friendly graphing, Personally, I think there is nothing better than Excel.

In addition, I think most people who work in companies use Excel, but for R, I think it is still not as good as Excel, maybe less than 1/100th of Excel.

Therefore, I aimed to make it easy to represent time series data in a moving graph even in Excel, as shown in the GIF animation at the beginning of this article.

Steps of what to do

How can I get such a graph? I decided to break it down into steps and accomplish them one at a time.


1.Interpolation of data as needed

For example, suppose we have the following semi-monthly data for a year.

Time or No. Shop1 Shop2 Shop3 Shop4 Shop5 Shop6
1 17389 34801 39207 80414 40795 81082
1.5 37381 35787 69319 79253 65174.5 89374.5
2 57373 36773 99431 78092 89554 97667
2.5 73438 40585.5 63026 83870 70840.5 66641.5
3 89503 44398 26621 89648 52127 35616
3.5 85134.5 49431.5 45820.5 53355.5 59510.5 52097.5
4 80766 54465 65020 17063 66894 68579
4.5 76259.5 32163 63922.5 16222 39723.5 34444.5
5 71753 9861 62825 15381 12553 310
5.5 77514 10825.5 71243 31821.5 52711 1008.5
6 83275 11790 79661 48262 92869 1707
6.5 75819.5 41935.5 45111.5 43635 83272.5 35372.5
7 68364 72081 10562 39008 73676 69038
7.5 80655.5 64066 11996.5 44683 40157.5 54042
8 92947 56051 13431 50358 6639 39046
8.5 49848 44284.5 38205.5 66026 4883.5 41492
9 6749 32518 62980 81694 3128 43938
9.5 20520.5 30063 68149.5 69903.5 12701 68491
10 34292 27608 73319 58113 22274 93044
10.5 57529 41036.5 69169.5 37588 44584 80811.5
11 80766 54465 65020 17063 66894 68579
11.5 76259.5 32163 63922.5 16222 39723.5 34444.5
12 71753 9861 62825 15381 12553 310

In this case, there are 23 lines of data, and each line is used to draw a graph to make one frame of animation, resulting in 23 frames. If we assume that the movie is 3 frames/second, the movie will be less than 8 seconds long (23 ÷ 3 ≒ 7.67).

Motion graphs, movie graphs, moving graphs, animation graphs, missing frames

Hmmm, it's a bit choppy, isn't it? Yes, I need at least 20 frames per second to make a smooth moving graph, but with this number of frames, it would only take about 1.2 seconds.

So, by using interpolation to fill in the missing data, we can increase the 23 lines of data to, for example, 10 times (230 lines) or 100 times (2300 lines). By using this expanded data to output more detailed graphs, we can create videos with smooth motion and sufficient length.

Of course, if you have hundreds or thousands of time series data to start with, you may not need to interpolate. So, this process should be done on an as-needed basis. In my own business, this process is essential.

2.Continuous output of graphs and charts (automatic creation of each animation frames)

This step is to output the graphs and charts drawn in Excel as a series of images, like a single frame of an animation.

For example, if you have a record of monthly sales for 10 years, you will have to create 12 x 10 = 120 graphs.

Doing this manually, one by one, is very tedious. You can right-click and select "Save as Picture" and do it steadily, but it is impossible to do it hundreds of times each time, so you have to leave it to the macro.

3.Output as video (connect each frame)

This is the process of connecting the images of each graph output in step 2 to make a video.

If you are going to use it in a PowerPoint presentation, it is safer to output it as mp4 now, considering the compatibility.

This step itself can be done rather easily using the advanced video editing software AviUtl, for example, but there are some steps that need to be followed, such as specifying the length of the video (in seconds), and I don't know exactly how to do it myself (though I'm sure I can look it up). I also need to add a plugin for mp4 output. It's a little bit of a hassle, too.

So, this time, instead of using video editing software such as AviUtl, I will use a command line tool called ffmpeg with a macro call.

Step 1: Interpolate data as needed

First, I would like to try about the steps of "data interpolation".

Which interpolation method to use?

When it comes to interpolation, there are several methods.

  • Linear interpolation
  • Lagrange Interpolation
  • Spline interpolation
  • Akima interpolation

and so on. Each of them has its own merits and demerits, and there are also derived types that compensate for their weaknesses, so the situation looks a little complicated. Let's start by interpolating the following data using the mainstream methods.

No. or Time Shop1
1 300
2 900
3 600
4 600
5 600
6 100
7 800
8 600
9 800
10 300

Linear interpolation

The interpolation is done in the form of a straight line between the raw data.

Graph of the result of linear interpolation.

The advantage is that it is the simplest interpolation method and does not cause "over maximum or minimum" interpolation as seen in the other interpolation methods presented below, so it is less criticized.

The disadvantage is that when you use this as a moving graph, it may look a little choppy in some cases.

Lagrange interpolation

It seems to be a way to calculate the interpolation value by calculating a polynomial that goes through all the raw data (my own simple interpretation, I may be wrong).

Graph of the result of Lagrange interpolation.

I'm not sure what the advantages are. It has a long history, it was used in the Mathematical Olympiad, and so on, but I'm not sure what it's actually used for.

The disadvantage is that the amplitude at the end tends to be large, as shown in this graph. I heard that it is possible to create a derived version that prevents this phenomenon by devising a calculation method, but I (a layman) don't know if it is possible for general use.

So, I have never used Lagrange interpolation in practice.

Spline interpolation

Again, this is my ( layman's ) interpretation, but while the above Lagrange interpolation looks for a polynomial equation that passes through the entire raw data, spline interpolation is a method that focuses on only the two points before and after the raw data to form an equation and interpolate.

Graph of the result of spline interpolation.

The advantage is that the interpolation is intuitive and natural, as can be seen from this graph, since it does not try to force the overall consistency like Lagrange. It is also used in image processing (for example, when shrinking).

The disadvantage of this method is that it produces results that exceed the raw data.For example, in the graph above, when the horizontal axis is 3, 4, and 5, the data is actually constant, but there is a slight up and down swing, which may or may not make you feel uncomfortable.

Also, right after the horizontal axis of 7 (about 7.2?), there is a number that seems to exceed 7. This may or may not be uncomfortable for you.

Akima interpolation

This method was invented by Mr. Akima in Japan in 1970. It is used for contour lines on maps.

Graph of the result of Akima interpolation.

The advantage is that excessive interpolation, as seen in spline interpolation, is unlikely to occur. If you compare the graphs, you will see that there is no swing at 3, 4, and 5 on the horizontal axis, and even at about 7.2 on the horizontal axis, there is no situation (in this case) where the value at 7 is exceeded.

The disadvantage is that if the smoothness of the graph movement is the primary concern, it is not as good as spline interpolation. As you can see by comparing the front and back of horizontal axis 2 and 6 with spline interpolation, Akima interpolation is a little sharper, closer to linear interpolation.

My (layman's) understanding is that it is somewhere between linear interpolation and spline interpolation.

Perform linear interpolation in Excel

Spline interpolation and Akima interpolation are good for smoothness in moving graphs, but if it's too much of an adaptation, I wonder how it would look in an internal or external presentation. In that case, linear interpolation is the safest choice.

So, I would like to try to execute linear interpolation in Excel.

Perhaps the procedure would be

  1. Perform the interpolation on the X axis. For example, to interpolate by a factor of 2, X1, X2, X3 → X1, X1.5, X2, X2.5, X3. 
  2. Draw a straight line between (Xn,Yn) and (Xn+1,Yn+1) and calculate the slope (like a linear function).
  3. Based on the calculated slope, calculate the interpolation value (Y1.5, Y2.5)

I guess that's it (I'm not sure).  It's just a simple proportional calculation repeated over and over, so there are many ways to do it. It may not be beautiful, but please forgive me.


    Sub linearinterpolation()

    'X(i) rawX
    'Y(i) rawY
    'Xip(ii) interpolated_X
    'Yip(ii) interpolated_Y
    'n_intp number of interpolated data数
    'Yrow number of raw data
    Dim X(2001), Y(2001) As Double
    Dim Xip(10001), Yip(10001) As Double
    Dim Yrow, n_intp, i, ii As Long

    n_intp = 91
    Yrow = 10

    'Reading raw data (X)
    For i = 0 To Yrow - 1
    X(i) = ActiveSheet.Cells(i + 2, 6).Value
    Next

    'Next, calculate the Xip
    For ii = 0 To n_intp - 1
    Xip(0) = X(0)
    Xip(ii + 1) = Xip(ii) + (X(Yrow - 1) - X(0)) / (n_intp - 1)

    'Output Xip to sheet
    ActiveSheet.Cells(ii + 2, 9) = Round(Xip(ii), 12)
    Next ii

    'Reading raw data (Y)
    For i = 0 To Yrow - 1
    Y(i) = ActiveSheet.Cells(i + 2, 7).Value
    Next

    'Further Yip calculations
    Yip(0) = Y(0)
    i = 0
    For ii = 0 To n_intp - 1
    If Round(Xip(ii), 10) >= Round(X(i + 1), 10) Then i = i + 1'Increase i when Xip enters the next interval
    Yip(ii + 1) = Yip(ii) + (Y(i + 1) - Y(i)) / (X(i + 1) - X(i)) * (Xip(ii + 1) - Xip(ii))
    ActiveSheet.Cells(ii + 2, 10) = Yip(ii)
    Next ii
    End sub

If you enter 10 rows of raw data with X values in column F and Y values in column G, and execute the above script, the respective interpolated data should be entered in columns I and J.

Excel sheet with raw data and linear interpolation results.

*On the Excel main screen, select View → Macro → TEST, etc. as the macro name → Create → Delete Sub TEST() and End Sub, and replace them with the script above → On the Excel main screen again, select View → Macro → linearinterpolation to execute.

In the above example, the maximum number of rows of raw data is set to 2,000 and the maximum number of data after interpolation is set to 10,000.

This is a tentative setting because it is unlikely that the number of rows will be more than this when creating a moving graph, and on the other hand, if the number of rows is more than this, the processing will become heavy.

It should be possible to handle cases where X is not evenly spaced. However, in most cases, I think X will be a constant interval on the time axis or something.

In addition, the number of data after interpolation is n_intp = 91, but if you want to use a number other than this, you can use a number that is a multiple of (the number of rows of raw data - 1) + 1. In this case, it is ((10 - 1) * any integer you like, say 10) + 1 = 91.

Step 2: Continuous output of graphs and charts (automatic creation of each animation frames)

I would like to do this using the linear interpolation data created above. As shown in the following image, we have interpolated data in column J that we want to graph.

Raw data and interpolated values in an Excel sheet

Continuous source movement

Scripting a macro

Register the following into the macro.


    Sub ContinuousMovementOfGraphSource()

    Dim Yrow As Long
    Yrow = 92'row number of last interpolated data
   
    For Y = 2 To Yrow
    ActiveChart.SetSourceData Source:=Union(Range(Cells(1, 10), Cells(1, 10)), Range(Cells(Y, 10), Cells(Y, 10)))
    With ActiveChart
        .HasTitle = True
        .ChartTitle.Characters.Text = Cells(Y, 9)
        .FullSeriesCollection(1).XValues = "=Sheet1!$J$1"
    End With    
   
    DoEvents
    Next Y
    End Sub


Preparing the graph

First, we need to create a graph.

Select J1:J2 first.

Inserting a graph using column J in Excel

Then choose Insert -> Bar Chart.

Insert, bar chart

Then, right-click on the graph and choose Select Data.

Right-click to select data

Select Edit in the legend item (series) on the left

Change the series name to $J$1 by pressing the arrow buttons.

Change to $I$2.

Finally, set the vertical axis of the graph to 0 for the minimum and 1000 for the maximum. If you don't do this, the vertical axis will not be fixed, resulting in a wobbly graph.

Set minimum and maximum values for graphs.

This is the graph that has been prepped.

The prototype of a moving graph


Execution

With the prepped graph selected (active), choose View→Macros→ContinuousMovementOfGraphSource and execute. 



Description of the script

    Dim Yrow As Long
    Yrow = 92'row number of last interpolated data

->Yrow is set to match the number of data after interpolation + 1.The reason for the "+1" is that the column name is included in the first line.


    For Y = 2 To Yrow
    ActiveChart.SetSourceData Source:=Union(Range(Cells(1, 10), Cells(1, 10)), Range(Cells(Y, 10), Cells(Y, 10)))

-> "Y" is increased one by one from 2 to Yrow (92 in this case). In doing so, we continuously change the source (reference range) of the original data of the currently selected graph to match the increasing Y.

We are using the Union function because as Y increases, the distance from the first row becomes more distant, making it inappropriate as a source for the graph.


    With ActiveChart
        .HasTitle = True
        .ChartTitle.Characters.Text = Cells(Y, 9)
        .FullSeriesCollection(1).XValues = "=Sheet1!$J$1"
    End With   
    DoEvents

-> Set detailed options for the currently selected graph.

.HasTitle to display the graph title and set the items in column I to that title.

FullSeriesCollection(1).XValues = "=Sheet1!$J$1" to set the first row of column J as the axis item. If I didn't explicitly set the axis item to the first row, the horizontal axis label would show "1" for the first picture, and "Yip" for the second and subsequent pictures.

At the end, I used DoEvents to make the progress appear sequentially in the graph.


Save each graph as an image.

Next, add the following to the appropriate location in the above macro and run it. A folder named MovingGraph_workingfolder will be created directly under the C drive.

   
    Dim targetPath As String
    targetPath = "C:\MovingGraph_workingfolder\"
    If Dir(targetPath, vbDirectory) = "" Then
        MkDir targetPath
    End If
   

   
    ActiveChart.Export (targetPath & "Transition_" & Format(Y - 2, "00000") & ".png")
        


Description of the script

    Dim targetPath As String
    targetPath = "C:\MovingGraph_workingfolder\"

-> The string "targetPath" is defined and the path of the folder where the image will be saved is set there. The place to add the script would be the next line after "Yrow = 92' row number of last interpolated data"

    If Dir(targetPath, vbDirectory) = "" Then
        MkDir targetPath
    End If

-> If the folder specified in targetaPath does not exist, it will be created anew.

    ActiveChart.Export (targetPath & "Transition_" & Format(Y - 2, "00000") & ".png")

-> This script is used to save the graph as an image named "Transition_00000.png" in the folder specified by "targetPath". The maximum value is 99999, and the images will be automatically saved in sequential numbers starting from Y-2, so the first image will be Transition_00000.png.

The place to add will be the next line after "End With" above.

Step 3: Output as video (connect each frame)

Since you have already created the frames of the animation, you can immediately convert it into a movie by using a good software such as AviUtl.

However, many people may feel that it is too much trouble to launch another software. Also, if you want to use AviUtl to output as mp4, you will need to install a plug-in for it, and since most people will rarely use it, you may need to create a shortcut to it somewhere you won't forget.

So for this project, I would like to use an Excel macro to call FFmpeg, a very famous command line tool for video editing.

Introducing FFmpeg

Download

Go to the FFmpeg official website and click on the DownLoad icon.

https://ffmpeg.org/

At the destination, press the Windows button and select Windows builds by BtbN (this was easier for me to understand).

In the destination, select and download the latest (at the top) ffmpeg-0000-win64-gpl-shared.zip.


Placing Folders

Extract the downloaded file.

This may vary from case to case depending on your PC environment, but usually you will find a folder with the same name in the folder.

For the contents folder, change the name to ffmpeg because it is too long.


Cut out that ffmpeg folder and move it to directly under the C drive.

If it looks like this, it is OK.


Setting the path

Lastly, the path setting, there seems to be a rather easy way to do this using Windows PowerShell, but I've read that it's not very reliable, so I'm going to use the straightforward method. I will explain it as carefully as possible.

Right-click on the Windows button at the bottom left of the screen and select System.

Click Advanced System Settings on the right side of the screen

Click on Environment Variables

Click Path.

Click "New"

Type C:\fmpeg\bin

Press OK when you're sure you've done everything correctly.

Press OK again.

That's it!

*If you are worried, you can start an application called Command Prompt, type ffmpeg, and press Enter. If you see the information about FFmpeg, you are good to go.


Script and description

Script

The script is as follows. It's so short, isn't it?

      
 
   Sub mp4output()

    ChDir "C:\MovingGraph_workingfolder"
   
    Dim command As String
    command = "ffmpeg -r 9.1 -i Transition_%05d.png  -vcodec libx264 -pix_fmt yuv420p -crf 16 -t 10 -progress log.txt movie_graph.mp4"
   
    Dim WSH2 As Object
    Set WSH2 = CreateObject("Wscript.Shell")
    WSH2.Run ("%ComSpec% /c " & command)
    Set WSH2 = Nothing
   
    End Sub
       


When registering the above script, the following settings must be done.


In the VBA screen, go to Tools → Reference Settings

Then, check the "Windows Script Host Object Model" checkbox and press OK.


If you save this file as a file with macros, it will remain checked the next time you use it.

Description

I'm having trouble finding direct information on how to link FFmpeg and Excel macros. With some research in Japanese and some in English, I managed to write the above script. However, I don't understand it very well.

    ChDir "C:\MovingGraph_workingfolder"

-> Here, simply changing the current directory to C:\MovingGraph_workingfolder

    Dim command As String
    command = "ffmpeg -r 9.1 -i Transition_%05d.png  -vcodec libx264 -pix_fmt yuv420p -crf 16 -t 10 -progress log.txt movie_graph.mp4"

-> define the string "command" and put the command to call ffmpeg at the "command prompt" there

  • -r 9.1 -> 9.1 frames per second
  • -i Transition_%05d.png → The input is a png image with "Transition_" and a sequential five-digit number.
  • -vcodec libx264 → video codec is libx264 
  • -pix_fmt yuv420p → color space? is yuv420p.
  • -crf 16 → quality is 16 (low quality (51) to high quality (0), where 0 is lossless)
  • -t 10 → Set the video duration (in seconds) to 10 seconds.
  • -progress log.txt → Keep a log of the results (progress) in a file named "log.txt".
  • movie_graph.mp4 → The name of the output movie should be "movie_graph.mp4".

According to the specifications, if the pixel size of the original image is an odd number, it cannot be converted to video. For example, a 301x240 image will not work. You need to adjust the pixel size to be an even number, such as 300x240 or 302x240. I hope to make this more convenient in the future.。


    Dim WSH2 As Object
    Set WSH2 = CreateObject("Wscript.Shell")
    WSH2.Run ("%ComSpec% /c " & command)
    Set WSH2 = Nothing

-> I honestly don't know what it is. It's faster and more accurate if you Google it than if I explain it. I think it's like an Excel macro spell that calls the command prompt. The third line executes the command to ffmpeg that you put in the command, and the last line releases the role.

Actually, this was the part I had the most trouble with this time. I heard that there are two ways to invoke the command prompt, .Run and .exec. At first, I used the .exec method.

However, when the number of frames increased, or the number of seconds increased, or the resolution increased, FFmpeg instantly stopped working. Why is that? I don't know. Even though I have enough memory...

After a lot of struggling, I switched to ".Run" and it worked. It was hard for me to switch... Hmmm....

I don't know why it doesn't work with ".exec" at all.  Someone please write an article about it... Anyway, I got stuck here, and it took me a lot of time and energy. By the way, the name "WSH2" is a remnant of the failure I had with WSH and .exec. I kept it as a souvenir.


Closing words

If you did all of the above and everything went well, you should have a video file in a folder called C:\MovingGraph_workingfolder.

In this case, 91 frames are used to create a 10-second movie at 9.1 frames/second. It would be more convenient if this could be set automatically in the cell (for example, if you specify the number of seconds, the frame speed is automatically set, or if you set the frame speed, the number of seconds is automatically set, etc.) instead of specifying it in the script. I would like to implement this feature when the final version is completed.

That's it for now, the sequence of events is complete.

In the next article, I would like to introduce a more convenient version that integrates these features.


QooQ