Launching the app
To begin with, let’s run the app locally using the code below (or online: https://smin95.shinyapps.io/ggsem/):
install.packages("devtools")
devtools::install_github("smin95/ggsem")
ggsem::ggsem()
The app’s layout
The picture shows the ggsem
app. First, there’s space
where plots are rendered (red box). On the left side, there is a menu.
It begins with a dropdown menu for Element Selection,
allowing users to choose the type of graphical elements to add on the
plotting space (inside the purple box). There are five options for
Element Selection: Point,
Line, Text Annotation,
Self-loop Arrow, and Lavaan Input.
Below Element Selection, users can select the order of the layer in how the graphical elements are displayed (inside the blue box). The default is set so that points are most at the front. In other words, when a line and a point overlap, a point will mask the line.
Next, there is a slider for Zoom Level (within the green box). The default is set to a factor of 1.2x but it can be increased to zoom out (all the way to a factor of 10).
Then, there are sliders for Horizontal Position and Vertical Position (in the green box). This changes the focus of the plotting space that is displayed. For instance, if a point is cutoff on the right side of the plotting space because the space is not enough, simply adjust the slider for Horizontal Position.
Furthermore, there are Undo and Redo buttons (in the yellow box). These correspond to CTRL + Z and CTRL + Y. respectively. To illustrate, if you have accidently deleted a line, then simply click the Undo button to cancel the most previous action. The app remembers all steps of inputs, so Undo button can work all the way back to the beginning.
Finally, there is menu (within the orange box) that has specific input depending on the selected menu in Chose Element Type. Without further ado, let’s add graphical elements and see how these options interact together.
Adding Elements
Adding Points
Lets begin by adding a point. The default coordinate of its X and Y position corresponds to the origin (0, 0). After a point is created, users can hover their mouse point on the point and realize that the center of the point is at X = 0 and Y = 0, as shown on the bottom-left of the plotting space.
Users can provide several inputs to specify the aesthetics of the point. This includes not only its X and Y coordinates, but also its filling color (Point Color), shape (Select Shape), size (Point Size), width of the border (Border Width), color of the border (Border Color), alpha level (Point Alpha).
Here, We can draw a square point by setting the inputs as shown below:
- X Coordinate: 5
- Y Coordinate: 5
- Point Color: #D0C5ED
- Select Shape: square
- Point Size: 50
- Border Width: 2
- Border Color: #9646D4
- Point Alpha: 1
After these have been specified, please click the Add Point button (pink box) to render the output. If you make any mistakes, you can click the Undo button to cancel the changes.
Notice that the output that has just been created is now part of the output table for points (within the green box). Users can directly change the values within the table to directly change the aesthetics of the selected element, or delete a selected row (or all rows). Simply click a row of interest, and click the Delete Selected Point (in the green box).
Adding Lines
Next, we will add a line by selecting Line in the dropdown menu of Choose Element Type.
There are numerous parameters of aesthetics that users can specify. We can start by drawing a black line with these coordinates (and leave all other default inputs unchanged):
- Start X Coordinate: 2
- Start Y Coordinate: -2
- End X Coordinate: 8
- End Y Coordinate: -2
After the Add Line button has been clicked, a line will be drawn below the purple square. This line has a single color, as specified in the dropdown menu Line Color Type.
Next, we will draw a curved line, whose curvature is automatically adjusted based on the X and Y coordinates of the line segment but it can be manually adjusted by controlling Control Point X and Control Point Y. Additionally, we can set it to have a gradient between two colors by setting it as Gradient. After we choose Gradient, a conditional color menu will appear (End Color), as well as Gradient Intersection, which is a slider that allows us to give a fine control of where the gradient occurs in the line segment’s length.
- Start X Coordinate: 2
- Start Y Coordinate: 12
- End X Coordinate: 8
- End Y Coordinate: 12
- Start Color: #F57373
- Line Color Type: Gradient
- End Color: #53F26D
- Gradient Intersection: 0.5
- Line Width: 2
- Line Alpha: 1
- Line Type: Curved Line
If gradient intersection is either close to 0 or 1, then it will display one color more than the other. For instance, if its set to 0.01, the End Color will dominate the line segment.
Next, we will add an arrow by setting the dropdown menu Line Type as Straight Arrow, with these parameters below:
- Start X Coordinate: 18
- Start Y Coordinate: 5
- End X Coordinate: 12
- End Y Coordinate: 5
- Start Color: #9E9E9E
- Line Color Type: Gradient
- End Color: #54F5AF
- Gradient Intersection: 0.2
- Line Width: 2
- Line Alpha: 1
- Line Type: Straight Arrow
Leave the other inputs as intact, such as Arrow Type (open or closed arrowheads) and Arrow Size (size of the arrow head).
Adding Text Annotations
Now, we will add a text annotation beside the end of the arrow, labelled as “Square One” using these inputs below:
- Text: Square One
- X Coordinate: 26
- Y Coordinate: 5
- Font: sans
- Text Size: 20
- Color: #000000
- Angle (deg): 0
- Text Alpha: 1
- Typeface: Bold
After Add Text button is pressed, a text “Square One”” will be rendered. However, we see that the text has been cutoff on the right side because there is not enough plotting space. The X and Y coordinates of the text refer to the position of the text’s center.
So, we use the slider Horizontal Position to re-adjust the focus of the plotting space:
- Horizontal Position: 8
Adding Self-loop Arrows
Finally, we can add a circular self-loop arrow on the plotting output using these inputs below:
- X Coordinate (Center): -5
- Y Coordinate (Center): 5
- Radius: 2
- Line Width: 1
- Line Color: #000000
- Line Alpha: 1
- Arrow Type: closed
- Arrow Size: 0.1
- Loop Width: 1
- Loop Height: 1
This will generate the self-loop arrow on the left side after the Add Self-loop Arrow button has been clicked.
Note that there are also Apply Changes and Lock Self-loop Arrows buttons.
Apply Changes button: Changes the currently existing self-loop arrows’ Gap Size (between two ends of the arrow) and Loop Orientation (deg).
Lock Self-Loop Arrows button: Makes the currently existing self-loop arrows immune to the subsequent usages of the Apply Changes button. Only press if you are satisfied with the current orientation and gap size of the existing self-loop arrow.
Saving Data and Graphics
Notice that whenever we add graphical element onto the plotting space, the output table gets updated. There are four tables total: 1) Points Table, 2) Lines Table, 3) Annotations Table, and 4) Self-loop Arrows Table. Users can directly manipulate the aesthetics of elements by modifying the numiercal inputs in the table, such as x and Y coordinates and alpha level. They can also save the CSV files, close the ggsem app, and the load them again to continue working on the figures later in the future.
To download each of the four tables, go down to the dropdown menu Choose CSV to Download, and click the button Download Selected CSV, for each of the four tables.
To reload the CSV files back into the app, users can click Browse under Upload CSV Files to locate their CSV files of their interest.
The output image can also exported as either PNG, JPEG, PDF or SVG.
Modifying the Plot from ggsem app in ggplot2 Workflow
The plot that we have generated can be recreated as a ggplot
object in RStudio using the function csv_to_ggplot()
, which
might take some time to run if the CSV of line include gradient
settings. To reduce its time, you can choose to reduce the value of
n
(default value = 100) to a lower value, which is an
argument that is used to set the resolution of the gradient coloring and
curvature of the line.
library(tidyverse)
library(ggsem)
# CSV files from ggsem app
points_data <- read_csv("https://www.smin95.com/points.csv")
lines_data <- read_csv("https://www.smin95.com/lines.csv")
annotations_data <- read_csv("https://www.smin95.com/annotations.csv")
loops_data <- read_csv("https://www.smin95.com/loops.csv")
p1 <- csv_to_ggplot(
points_data = points_data,
lines_data = lines_data,
annotations_data = annotations_data,
loops_data = loops_data,
zoom_level = 1.2, # From the ggsem app
horizontal_position = 8, # From the ggsem app
vertical_position = 0,
n = 100
) # Default vertical position on the app
We can save the figure as a PNG file to verify whether it is
identical to the one we have drawn on the ggsem Shiny app. Here, we set
width = 9
and height = 9
as the dimension of
the exported image file.
ggsave("p1.png", p1, width = 9, height = 9)
We can also add a plot light-grey (grey90
) background to
our graphical output using typical ggplot2 functions and change the
range of the y-axis.
p2 <- p1 + theme(
plot.background = element_rect(fill = "grey90", color = NA) # Grey background, no border
)
We can then save the figure again using ggsave()
.
ggsave("p2.png", p2, width = 9, height = 9)
We can also chip away the extra space by directly dealing with the
axis limits of the figure. First, we extract the current range of the
y-axis limit of the p2
object using the function
get_axis_range()
, which only has one argument (a
ggplot object).
get_axis_range(p2)
#> $x_range
#> [1] -18.4 34.4
#>
#> $y_range
#> [1] -26.4 26.4
The y-axis spans from -22 to 22. We can reduce the some space at the
top and bottom (y-axis range: -8 to 19). To do so, we will need to use
the function coord_cartesian()
.
p2b <- p2 + coord_cartesian(ylim = c(-8, 19))
We can also modify the range of the x-axis slightly (-9 to 30).
p2c <- p2b + coord_cartesian(xlim = c(-9, 30))
Then, save the figure using ggsave()
.
ggsave("p2c.png", p2c, width = 5.5, height = 2.3)
We have successfully cropped out the empty space and recreated the figure as it would appear on the Shiny app by only using the ggplot2 workflow.
The height
and width
arguments might need
to be tested for a few attempts to find the best ones (takes some
practice!). Essentially, csv_to_ggplot()
returns a
ggplot object where the ratio has been fixed to 1, allowing the
plots to appear exactly the same as those from the Shiny app. However,
when the x and y limits must be changed in a ggplot2
workflow (as in this example), this ratio must be broken (by the
function coord_cartesian()
). This changes the relative
spacing of visual elements on the plot. So, the ratio has to be set
again by setting the width
and height
of the
output image file, which in here are width = 5.5
and
height = 2.3
.
Tip: If your plot gets cut-off, either increase
width
or height
(or both) in
ggsave()
.