LibreOffice Calc: Graphs with Two y-axes with Different Scales

While a bit technical, it’s occasionally useful to plot multiple data series that have very different scales in the same chart. Let me give an example to illustrate. Let’s say I want to see whether the number of Mormon temples being built aligns with the number of Mormon stakes (akin to a Catholic diocese) that are organized over time. (I’m a sociologist who studies religion; you’ll just have to go with my examples.)

However, the number of Mormon temples is in the hundreds while the number of Mormon stakes is in the thousands. If I plot them both on the same chart with the same y-axis (that’s the vertical axis), the number of Mormon temples is going to look really small and I won’t be able to see the variation over time in the number of temples, like this:

The chart shows that stakes have increased, but it looks like the number of temples has barely moved. LibreOffice Calc automatically creates the scale used for the y-axis based on the scale of the larger of the two data series, in this case, the number of stakes. Thus, the maximum value is 4,000 and the minimum is 0. What I want to do in this tutorial is to illustrate how to add a second y-axis on the right side of the chart that uses a different scale that is more appropriate for the number of temples.

To begin with, go ahead and create your chart with at least two data series, as I have shown in other tutorials, like this one. Once you have your chart with two data series complete, now it’s time to add a second y-axis with a different scale.

First, click on your chart then double-click it to open chart editing. Then, select the chart area by clicking on one of the axes (left or right doesn’t matter) and then right-click it. You’ll get a context menu with the option “Insert/Delete axes…” Select that:

In the window that pops up, you’ll see a second column labeled “Secondary Axes.” You want to select “Y axis.”

Click “OK” and you’ll see that a second y-axis has been added to your chart on the right side using the same metric as the left side:

The next steps are pretty straightforward, but before you do them, you should pause and think for a second so you don’t have to go back and undo what you’re about to do. You’re going to change the scale of one of the two y-axes, but which axis do you want to change? There isn’t a right or wrong answer here. Generally speaking, I typically see charts like this with the smaller of the two ranges assigned to the left axis and the larger assigned to the right axis, but, again, it is entirely up to you which way you choose to go. At this point, though, you need to make a decision. Then you can move to the next step.

I’m going to follow my suggestion above and change the y-axis on the left to a scale that fits with the number of temples (so, a smaller range of values) and keep the y-axis on the right with the larger range for the number of stakes. But before I change the scales of the axes, I need to tell LibreOffice which data series is going to align with which axis. Here’s how. Click on one of your data series lines, then right-click it and select “Format Data Series.”

In the window that pops up, you’ll see on the “Options” tab right at the top an option that says, “Align Data Series to” and then “Primary Y axis” (this is the one on the left of the chart) or “Secondary Y axis” (this is the one on the right of the chart). Since I selected the number of temples first, I’m going to leave that one aligned to the Primary Y axis:

Hit OK. Then select the other line (in my case, the number of stakes), right-click it, and select “Format Data Series.” On the “Options” tab, I’m going to select to align this line with the “Secondary Y axis”:

Once you do that, you’ll see that LibreOffice automatically adjusts the scale of the other axis. Here’s how my chart now looks:

You can see that it changed the scale of the Primary Y-axis (the one on the left) to a maximum of 250 to reflect the smaller range of that data series. If you want to customize the scale used, you can always click on the axis you want to modify and then right-click it and select “Format Axis”:

In the window that pops up, you can modify the scale of the axis by clicking on the “Scale” tab. If you want to change the values, click on the box next to “Automatic” to unselect it so you can put in your own values, then customize the value you add, like this:

When you have modified the scale to your satisfaction, select “OK” and your graph will be updated with the scale you want, like this:

The resulting chart now has two axes with different scales. It would be a good idea at this point to label the axes to reflect the differences. Simply right-click on the chart and select “Insert Titles.” In that window, add appropriate titles. The left y-axis is simply the Axes while the right y-axis is considered the “Secondary Axes”:

And your final graph will look something like this:

That’s how you can create a chart with two axes in LibreOffice Calc.

NOTE: This example was done in LibreOffice Calc version: 6.4.2.2 on a Linux-based operating system (Kubuntu 19.10).

LibreOffice Calc: Interpolating Missing Values in Graphs

Here’s my situation. I have some data over time but I’m missing values in specific years. I want to graph that data but would rather not have to estimate all of the missing values. It turns out, LibreOffice Calc can do that for you in your chart. Here’s how…

Imagine I’m plotting the number of congregations in the LDS Church over time (weird example, I’m sure you’re thinking, but I’m a sociologist who studies religion, so, yeah, that’s what I do). I have the number of congregations in 1841, 1849, 1901, etc. Basically, I have the number in certain years, but I’m missing the number of congregations in lots of other years. I could interpolate the missing values (Excel has this function built in; LibreOffice Calc does not, but you can do it following the approach I have detailed here). But, I don’t really need to do that for my project. I just need a chart that shows the growth of congregations over time.

My data are organized into two columns. Column A is years and ranges from 1841 through 2019. Column B is the number of congregations with the values I have and lots of blank cells:

Select the cells you want to plot (A1:B176 in my case) then click on “Insert Chart”:

You’ll get this window:

Since I want a Line chart, I’m going to select “Line” and because I want “points and lines,” I’m going to select that option as well. I also want “Smooth” lines rather than “Straight” lines, so I select that option, too:

Click “Next >” at the bottom. Since you already selected your Data range, you shouldn’t have to change that. However, we do want the “First column as label” for the x-axis of the chart. So, select that option:

Then select “Next >”. You shouldn’t have to change anything on the Data Series tab, so you can hit “Next >” again. On the Chart Elements tab, you’ll want to describe your chart elements. Add a Title and label your x-axis and y-axis. I also didn’t need a legend since I’m only plotting one data series, so I turned that off:

Then click “Finish.” You’ll have a chart, but it only has the points for the years when you have data, like this:

To add a line connecting the points and interpolating the missing data, click on the chart, then double-click it to modify the chart. Once you’re inside the chart, click on one of the points to select the data series, then right-click and select “Format data series”:

On the “Options” tab you’ll see “Plot Options” and just below that, “Plot missing values.” The default is “Leave gap.” Select “Continue line” and it will interpolate the missing values for you:

Select “Ok” and your line chart will now actually have a line, like this:

There you have it. A line chart with interpolated missing values in LibreOffice Calc without you having to calculate all of the missing values.

NOTE: This example was done in LibreOffice Calc version: 6.4.2.2 on a Linux-based operating system (Kubuntu 19.10).

Setting Up a New Windows Computer for Your Kids

I recently had a colleague contact me for some computer advice. He knows I’m a computer geek and was looking for some help setting up a new Windows laptop for his kids. He was wondering which antivirus software to buy.

If you’re at all familiar with my blog, you’ll know that I’m not a fan of Windows and run Linux almost exclusively in my house (I keep a Windows laptop around to use a book scanner). So, it may seem strange turning to a Linux user for advice for a Windows computer. But, it’s actually not that strange. Linux does so much right that it has taught me what you should do when setting up a computer, regardless of your operating system. So, here’s the advice I gave my colleague that I think would be good advice for anyone setting up a new computer for kids.

Antivirus Software

If what you want is just antivirus software, Microsoft Windows ships with antivirus protection now (Microsoft Security Essentials). If you don’t install any other software, you can make sure that you install that software. Plus, the price is hard to beat. It’s free. Also, from my perspective, it’s best for not slowing down your computer dramatically. Norton, Kaspersky, etc. all slow down your computer, which sucks. If all you want is virus/spyware protection, Microsoft Security Essentials is sufficient.

Additional Software

If you want additional software on the laptop to accomplish something else, that’s a different question. Since it’s for your kids, there are two types of software you could consider.

Home Internet Security

First, do you want to restrict where your kids can go online? I’m actually a proponent of simply teaching your kids good habits and not policing where they can go. That may not be your perspective. If you want to restrict where they can go, I’d suggest OpenDNS’s Family Shield (or Home). It restricts adult content and is free.

Ransomware

Second, there is also the concern of ransomware, which is basically if someone were to get a piece of software on your computer that then locks you out of your files. The easiest solution to this is just to install backup software like Dropbox and make sure your kids store any important files in the Dropbox folder. There is a free option that gives you 2 gigabytes. It’s generally good practice to back up all of your important files anyway (e.g., essays, homework, photos, etc.). So long as you have a backup, ransomware is basically not a problem. (See this guide for dealing with ransomware by Dropbox.)

Multiple Accounts and Administrator Accounts

You should also probably set up multiple accounts on the laptop, though, again, this is up to you and how much control you want to give your kids. Setting up a local account for your kids means they won’t be able to install software without your administrative password. If they don’t know what they are doing, this is generally a good idea.

Reinstall Windows

Finally, I’m not sure how good you are with computers, but I’d also suggest making sure you have a way to revert to a completely fresh install in case your kids manage to get past the software and screw things up. Since I build my own computers and run Linux, reinstalling my operating system is something I do regularly. But for most users, the very thought of doing that is terrifying. Microsoft has made that much easier.

Conclusion

Do all of the above and your laptop should work fine for years. Plus, all of the above will cost you exactly $0, just some time.

Plex/tinyMediaManager and Doctor Who Specials

I’m a science fiction fan. And I want my science fiction at my fingertips. To that end, I have slowly been digitizing my favorite series (e.g., Star Trek, Stargate, and now Doctor Who) and putting them on my fileserver that uses Plex to serve the episodes to whatever device I want. I recently ran into an issue with how to organize Doctor Who episodes on my fileserver and, once I figured it out, I thought I’d share it here in case others run into the same situation.

First, props to Doctor Who for occasionally having specials. They are always well done and lots of fun. So, I’m certainly not complaining. BUT, the problem is that the specials are not technically part of a season. That causes some challenges when it comes to how to organize the files.

I use tinyMediaManager for organizing my movies and TV shows on my file server. Not only does tinyMediaManager pull down all the information for my movies and TV shows but it also has the ability to rename the files and organize them. I like how it does all of this and it plays nice with Plex as well, which is important.

Now enter the problem with Doctor Who. Like most TV shows, Doctor Who has seasons. The standard ways to indicate the season and episode of a show are to include something like the following in the name of the digital file: “S03E14.” This indicates the show is from Season (“S”) 03 and is the 14th Episode (“E”) from that season. This works great for most of Doctor Who since most of the content is episodes.

But, what about the specials? The creators of Doctor Who regularly release off-season or out-of-season specials. These don’t get a season episode number. When I tried to get tinyMediaManager to scrape the specials, it didn’t know what to do with them. Basically, it ignored them because it didn’t know what they were since I didn’t know what to name them.

After a little googling, I found out that “Specials” have a special Season designation: “00.” So, for the first Doctor Who (2005) special called “The Christmas Invasion,” that aired on December 25, 2005, how you can name that file is:

Doctor Who – S00E167 – The Christmas Invasion

The naming convention breaks down like this. “S00” tells both Plex and tinyMediaManager that it is a “special.” tinyMediaManager then moves it into a folder called “Specials.” The “E167” is the episode number for the entire series (from Wikipedia). Once I figured this out, tinyMediaManager knew where to put the special:

And Plex began to recognize what the episode was:

Success! Now I can include Specials with my favorite science fiction series. There is order again in the science fiction universe.

R – create scatterplot with ggplot2

R has pretty amazing capabilities for creating charts and graphs. One of the most common packages for this is ggplot2. However, it’s not the most intuitive package I have used in R. So, I figured I’d illustrate how to make some relatively simple scatterplots in R using ggplot2. I’ll likely post instructions on how to create other graphs/charts in ggplot2 as well.

As with most of my R examples, I’m going to use the 2010 wave of the General Social Survey (R version here) to illustrate. You can open that file in R and follow along.

The point of a scatterplot is to visually examine the relationship between two variables. Since it’s well-known that there is a relationship between how much education someone has and how much money they make, let’s examine that relationship visually. The two variables in the GSS we’ll use are: EDUC (years of education ranging from 0 to 20, with 12 being a high school diploma and 16 a Bachelor’s degree) and REALRINC (the respondent’s income in 1986 dollars). Just because I want the resulting scatterplots to be more accurate, let’s go ahead and adjust the REALRINC into 2010 dollars first. Per this website, we need to multiply each income listed in the 2010 GSS by 1.989 to get 2010 dollars from 1986 dollars:

GSS2010$REALRINC2010 <- GSS2010$REALRINC * 1.989

Let’s just make sure the values make sense. To do that, first pull the first 10 incomes:

head(GSS2010$REALRINC, 10)

The “head” command tells R to simply list the first “10” values in the variable “REALRINC” and print them in the console. Here’s what I got as output:

[1] 42735.0 3885.0 NA NA NA 5827.5 42735.0 NA NA NA

We can check to see what the corresponding value in 2010 dollars is for the first value, $42,735, with the following command:

GSS2010$REALRINC2010[match(42735,GSS2010$REALRINC)];

The value I got was $84,999.92, which is $42,735 * 1.989. Groovy. Our formula worked.

Now to create the scatterplot. Install ggplot2 (I’m using version 3.2.1) and load the library.

install.packages("ggplot2")
library(ggplot2)

Now begins the rather bizarre part of working with ggplot2 – building the commands to create the charts.

The basic code for creating plots in ggplot2 is odd. You create a base object that includes the variables that will be used for creating the chart like this:

scatterEDUCxINCOME <- ggplot(GSS2010, aes(EDUC, REALRINC2010))

The first portion, “scatterEDUCxINCOME” is the base object.

ggplot” calls the ggplot2 package.

In the parentheses is, first, the database (GSS2010), followed by the “aesthetic” components of the chart (“aes” stands for aesthetic). In this case, it’s the two variables we’re going to use: EDUC and REALRINC2010.

This base object is really just the data for the scatterplot but not the scatterplot itself. To illustrate, you can tell R to display the base object:

scatterEDUCxINCOME

You’ll get some of the pieces of a scatterplot, but not the points:

To overlay the scatterplot onto the base object, you have to tell R what objects you want to be overlaid. Obviously, that should include the points, which would be done like this:

scatterEDUCxINCOME + geom_point()

geom_point()” tells R to overlay the geometric points for the scatterplot onto the base layer. The parentheses are useful as they allow for additional commands or modifiers for the points, as I’ll illustrate below.

Two points to note with the code above. First, when you run it, it will generate the scatterplot (see image below).

Second, you can actually save this entire piece of code into the base object, like this:

scatterEDUCxINCOME <- scatterEDUCxINCOME + geom_point()

However, doing so converts your base object into the scatterplot with the geometric points included. Since you may want to modify your scatterplot with additional features, it’s generally a good idea to not do that. Keep your base object simple and overlay things on top of it as you go until you get to where you want to be.

As noted, the geom_point() code can be modified. One of my favorite modifications is to add a command that adds a little bit of entropy to the scatterpoints, which is helpful when you have a large dataset. Otherwise, all the points are basically stacked on top of each other. Here’s how:

scatterEDUCxINCOME + geom_point(position = "jitter")

Of course, a scatterplot should have labels – a title and axis labels. ggplot2 tries to add the axis labels based on the names of the variables, but you can overlay these as objects onto the base object as well, like this:

scatterEDUCxINCOME + geom_point() +
ggtitle("Scatterplot of Educational Attainment and Individual Income") +
labs(x = "Educational Attainment (in years)", y = "Individual Income")

ggtitle adds a title to the chart.

labs(x = “”, y = “”) adds the labels for the x and y axes with the labels inside the quotes.

Two additional features are helpful in a basic scatterplot. First, adding a line to the chart to illustrate the relationship is helpful. I’ll show two. First, a standard regression line is always nice:

scatterEDUCxINCOME + geom_point() + geom_smooth(method = "lm", color = "red", alpha = 0.2, fill = "blue") +
ggtitle("Scatterplot of Educational Attainment and Individual Income") +
labs(x = "Educational Attainment (in years)", y = "Individual Income")

The code to add a smoothing line is geom_smooth. In this case, I modified that line to make it linear (“lm”), make it red (color = “red”), and changed the fill of the error around the line (fill = “blue”). The last modification was to change the transparency of the fill for the error (alpha = 0.2).

Other smoothing options are available. The default simply runs a best fitting line through the scatterplot:

scatterEDUCxINCOME + geom_point() + geom_smooth() +
ggtitle("Scatterplot of Educational Attainment and Individual Income") +
labs(x = "Educational Attainment (in years)", y = "Individual Income")

Finally, the scatterpoints can be modified in a variety of ways (e.g., thickness, transparency, color, etc.). Here’s a simple illustration:

scatterEDUCxINCOME + geom_point(position = "jitter", size = 4, colour = "green")

The points options that can be modified are detailed here.

A script file with the above commands is available here.

NOTE: This was done in R version 3.5.2.

R – find cases (rows) that match specific criteria

I regularly need to find a specific case or set of cases that meet some criteria when analyzing data, often so I can modify those values for one reason or another. The easiest way I have found to find such values in R is the “which” function.

As with most of my R examples, I’m going to use the 2010 wave of the General Social Survey (R version here) to illustrate. You can open that file in R and follow along.

In the 2010 GSS there is a variable for race (RACE). The options are: 1 = WHITE, 2 = BLACK, 3 = OTHER. To find all of the cases with a “3” in the dataset, I would use the following code:

which(GSS2010$RACE == "3", arr.ind = TRUE)

Here’s what the command is doing…

which” is the function that tells R to search for information that meets the criteria detailed in the parentheses.

GSS2010 is the name of the dataset.

RACE is the name of the variable in the dataset. By including the name of the variable, we restrict R to searching just inside that variable rather than the whole dataset. (The $ tells R that RACE is a variable inside the GSS2010 dataset.

The “==” indicates “equals” in R.

The target value, which can be text, characters, or numbers, goes inside the quotes. In this case, we wanted to find all of the cases with the number “3” which is code for “OTHER.”

arr.ind = TRUE tells R to include the index if the result is an array.

In the 2010 GSS, if you type in the code above, you’ll get a list like this:

 [1]    1   12   14   19   27   28   42   44   46   50   64   73   96   97  101  102  119  120  121  123  124  130  133  140  145  147  151  152
 [29]  153  154  159  161  180  185  190  194  195  199  211  213  217  220  230  245  263  275  278  287  288  295  297  301  305  312  314  318
 [57]  333  339  345  348  349  371  373  381  403  420  441  446  458  464  465  473  475  477  478  479  483  489  495  501  505  507  508  520
 [85]  550  554  561  564  567  591  593  631  704  712  713  715  716  732  741  749  770  776  792  793  805  807  823  824  829  877  901  956
[113]  973 1092 1112 1125 1186 1193 1218 1224 1264 1281 1291 1304 1307 1331 1336 1342 1345 1347 1352 1355 1356 1364 1365 1411 1423 1440 1441 1442
[141] 1444 1445 1446 1449 1451 1513 1523 1526 1528 1532 1534 1547 1550 1552 1556 1557 1559 1562 1564 1567 1568 1569 1570 1571 1572 1573 1574 1575
[169] 1576 1656 1660 1735 1764 1913 1933 1935 1993 2010 2011 2018 2019 2022 2038

The [1] is indicating that this is the first response. The [29] indicates that the next number is the 29th response. The numbers after the brackets (“[ ]”) indicate the row where that response was found. Thus, I know that the 161st row in my dataset has the value 3 in the variable RACE.

We can check this by using the following code:

GSS2010[161,"RACE"]

The result should be:

[1] 3

BONUS:

Should you want to modify the value for an individual observation, like the one we just examined, you could use the following code:

GSS2010[161,"RACE"] <- 2

This would change the values for that case from “3” (OTHER) to “2” (BLACK). I’m not really sure why you would want to do this in this instance, but, now you can. (There is a scenario when you might, but there are better ways to recode data.) Basically, the “<-” tells R to set the value of that specific observation to 2, overwriting the 3 that was there.

And if you wanted to change all of the values from 3 to 2, since you have a massive list, the easiest way would be to save all those values as a list, then have R change all the values in one fell swoop, like this:

OTHERRACELIST <- which(GSS2010$RACE == "3", arr.ind = TRUE)
GSS2010[c(OTHERRACELIST), "RACE"] <- 2

The above two commands would create a list in your environment called “OTHERRACELIST” that includes all of the row numbers of the cases with a 3. The second command then tells R to look inside the GSS2010 dataset and use the list (c(OTHERRACELIST)) to find all the rows you want changed in the RACE variable to “2.” That will then change the code for all of the people coded as “3” into a “2.”

A script file with the above commands is available here.

NOTE: This was done in R version 3.5.2.

R – delete one or several variables in a dataset

I regularly create variables while analyzing data and then find that I need to delete a variable I created. At times, I just want to get rid of a variable in a dataset (’cause screw that variable). This short tutorial will explain how to delete a variable (or multiple variables if needed).

As with most of my R examples, I’m going to use the 2010 wave of the General Social Survey (R version here) to illustrate. You can open that file in R and follow along.

To completely remove a variable from a dataframe, you need to tell R to copy the dataframe minus the variable you want to delete. Here’s the code:

GSS2010 <- subset(GSS2010, select = -(OCC))

Here is what the code above does…

GSS2010 is the name of the dataset. Typically, when I use the subset function, I do so to create a different dataset. However, in this case I actually want to overwrite the dataset, so I’m actually naming the new dataset the same thing as the old dataset, which, effectively, overwrites the dataset, getting rid of the unwanted variables in the process.

The “subset” function tells R that you want to take part of an existing dataset. It’s a very useful function for selecting, for instance, all the men in a sample or all of the people who live in a certain region.

After the “subset” function, inside the parentheses, is the name of the dataset from which we are taking a subset, GSS2010. After the comma inside the parentheses is code to tell R how to select the subset. In this case, we use the “select =” command to tell R that we want it to select a specific variable. However, the “” before “(OCC)” actually tells R to select all the other variables BUT not the OCC variable for the subset. Thus, “-(OCC)” tells R to select the entire dataframe except the variable OCC for the subset. In effect, OCC is deleted but, to get there, you actually have to tell R to keep everything but that (pretty stupid, honestly).

NOTE: This is an instance in R when you don’t need to put the name of the variable in quotes (e.g., (“OCC”)) nor do you need to indicate which dataset the variable is in (e.g., (GSS2010$OCC)) since the dataset is already referenced in the subset command.

To remove multiple variables at the same time, the above command can be modified slightly to include other variables by putting them into a vector:

GSS2010 <- subset(GSS2010, select = -c(YEAR, WRKSTAT))

By changing what comes after the “select =” component in the parentheses to a vector (c indicates a vector in R), you can indicate multiple variables that you want deleted from the dataset in one command. Thus, in the above code, the variables YEAR and WRKSTAT would both be deleted from the dataset.

Because it is R, there is always another way. Here are two alternative lines of code that will do the same thing, the first is for removing a single variable and the second is for removing multiple variables:

GSS2010 <- GSS2010[,-match(c("EVWORK"), names(GSS2010))]
GSS2010 <- GSS2010[,-match(c("EVWORK", "PRESTIGE"), names(GSS2010))]

The logic in the above code is very similar, using the “match” command instead of subset.

You may find some tutorials that suggest you can remove a variable from a dataframe/dataset using the following code:

GSS2010$GOD <- NULL

What this command does is actually remove all of the data in the variable GOD. However, the variable remains in the dataset, it’s just empty. I prefer one of the above approaches because they completely remove the variable from the dataset.

Here’s a script file for these commands.

NOTE: This was done in R version 3.5.2.

R – create variable filled with zeros

I ran into a situation where I needed to add a variable to a dataset. I knew that I was then going to modify some of the values in the variable, but most of the values were going to be zeros. So, I wanted to create a new variable and fill it with all zeros.

As with most of my R examples, I’m going to use the 2010 wave of the General Social Survey (R version here) to illustrate. You can open that file in R and follow along.

Here’s the code I used to create the variable:

GSS2010$TEMPANALYSIS <- replicate(2044, 0)

Here is what the code above does…

GSS2010 is the name of the dataset into which I wanted to create the variable. In this case, it is a copy of the 2010 wave of the GSS.

TEMPANALYSIS is what I called the variable. (The “$” tells R that it is a variable in the dataset.)

The “replicate” function tells R to replicate the second value in the parentheses (0) the number of times noted as the first value in the parentheses (2044). I used 2,044 because that is how many cases there are in the dataset. You can obviously adjust the value for the number of cases in your dataset/dataframe. If you have 320 cases, adjust it to 320.

If you don’t include the exact number of cases, you’ll get an error like this:

Error in `$<-.data.frame`(`*tmp*`, TEMPANALYSIS, value = c(0, 0, 0, 0,  : replacement has 2042 rows, data has 2044

That error is saying that you tried to add a variable but R needs to know what to put in every one of the rows and since it is short 2 rows, it can’t do it.

Of course, with R, there is always another way to do something. Here’s an alternative command that will do the same thing:

GSS2010$TEMPANALYSIS2 <- rep(0, times=2044)

I won’t repeat the description of the dataset and variable but will detail what the rest of the code is doing.

rep” tells R to repeat the first value in the parentheses (0) the number of times specified as the second number in the parentheses (2044; technically, the “times=” portion is not required.

Here’s a script file for these commands.

NOTE: This was done in R version 3.5.2.

Unethical Amazon Review Modifications

I don’t always review products on Amazon. I don’t have the time. But there have been two instances over the past year when I have been contacted by someone because of a review I wrote on Amazon. Both times, these individuals have tried to bribe me to remove my negative review of the product. Here’s the latest email exchange over a backup cellphone charger that was a piece of garbage:

First Email:

taylor jack taylor.jack0528@outlook.com Tue, Dec 17, 2019 at 10:30 PM
To: “ryantcragun@gmail.com” ryantcragun@gmail.com

Hello,rcragun.
I’m Anna.I am a real person.Since everybody’s time is very precious,I just go directly to the topic.
Here is your review.
https://www.amazon.com/gp/customer-reviews/R1T2C38HIJ7JJQ/ref=cm_cr_getr_d_rvw_ttl?ie=UTF8&ASIN=B07SWTGDVW
I am very sorry to hear about the issues you’ve had with your item.Are you willing to help me to delete your review? If you have deleted your review, please tell me,We will give you an Amazon gift card.
Looking forward to your good news and reply !

My response:

From: Ryan Cragun ryantcragun@gmail.com
To: taylor jack taylor.jack0528@outlook.com
Subject: Re: Amazon compensation

I consider your proposal completely unethical.
You should be ashamed of yourself.
Best,
Ryan T. Cragun

I stopped responding after this, but have since received three more emails:

Email Two:

From: “taylor.jack0528” taylor.jack0528@outlook.com Using MailMasterPC/4.13.2.1001 (Windows 7)
To: “ryantcragun@gmail.com” ryantcragun@gmail.com
Subject: Re: Amazon compensation

From my perspective, we are very eager to compensate those customers who trust us but are hurt by us.
So please give us a chance. We will offer a $ 30 Amazon Gift Card.
Hope you understand us, our life and work are not easy.

Email Three:

From: “taylor.jack0528” taylor.jack0528@outlook.com Using MailMasterPC/4.13.2.1001 (Windows 7)
To: “ryantcragun@gmail.com” ryantcragun@gmail.com
Subject: Re: Amazon compensation

Time is limited and tight!!
How is thing going?
If you have deleted your review ,please tell me, I will give you $30 right away.
This is your review.
https://www.amazon.com/gp/customer-reviews/R1T2C38HIJ7JJQ/ref=cm_cr_getr_d_rvw_ttl?ie=UTF8&ASIN=B07SWTGDVW
Thank you.

Email Four:

From: Bessierh5 Nielsenqvl99 trisnatudd3cx@gmail.com
To: ryantcragun@gmail.com
Subject: $30 Amazon gift card

Hello rcragun.This is the final mail to you.
This is your review.
https://www.amazon.com/gp/customer-reviews/R1T2C38HIJ7JJQ/ref=cm_cr_getr_d_rvw_ttl?ie=UTF8&ASIN=B07SWTGDVW
If you are willing to delete your review ,I will offer an Amazon gift card worth $30.
If you have deleted it ,please tell me, I will give you $30 right away.
We will thank you profusely and even find a homeless kitten to hug on your behalf. We will waiting for you.
Again, this is the last email you will receive from us so we really do hope you are enjoying your purchase.My most sincere regards, I hope that you can reply to me as soon as possible.
Thank you and please have a fantastically glorious day.
Sincerely
Anna

With the previous company, I told them I wouldn’t delete my review. They were okay with that. They said that they would send me a new pair of headphones (the other ones died within a year) to make things right and hoped I would update my review to reflect that. That seemed fair to me and that’s what I did. They were okay with me leaving my review but wanted me to note that they tried to make things right.

That’s very different from what this person is doing. They are basically trying to bribe me to remove negative information from Amazon’s website so people will be misled about the quality of their product.

The product is NEXGADGET’s Solar Charger Power Bank. As I noted in my review, it was basically a useless brick during a 5-day hike in Wyoming. It didn’t keep its charge for a single day and wouldn’t charge in sunlight. Maybe I got a bad item. But that still speaks to the production quality and my review should stay on the website. NEXGADGET shouldn’t be trying to hide negative reviews but rather trying to make a better quality product.

Update 1/8/20:

I sent a response to their last email hoping to get more information.

My 2nd Response:

Created at: Tue, Jan 7, 2020 at 9:02 AM (Delivered after 0 seconds)
From: Ryan Cragun ryantcragun@gmail.com
To: Bessierh5 Nielsenqvl99 trisnatudd3cx@gmail.com
Subject: Re: $30 Amazon gift card

Hi Anna,
I’d like to know your real name and who you work for. Please provide that information and maybe I’ll consider your request.
Best,
Ryan

Here’s their response:

Email Five:

Created at: Wed, Jan 8, 2020 at 3:32 AM (Delivered after -325 seconds)
From: Bessierh5 Nielsenqvl99 trisnatudd3cx@gmail.com
To: Ryan Cragun ryantcragun@gmail.com
Subject: Re: $30 Amazon gift card

I understand your mood,but
On the one hand , this is not a bribe,this is just a compensation,we just hope that you are satisfied with this transaction.
On the other hand , this is not a violation ,because this shopping platform has this option after all,and the choices are in your hand.I just need you to delete it ,not a good review.
So what do you think of it ?
please give me a chance.
If you have deleted it ,please let me know, thank you!

And my final response:

3rd Response

Wed, Jan 8, 2020 at 6:41 AM (Delivered after 0 seconds)
From: Ryan Cragun ryantcragun@gmail.com
To: Bessierh5 Nielsenqvl99 trisnatudd3cx@gmail.com

Definition of BRIBE: “persuade (someone) to act in one’s favor, typically illegally or dishonestly, by a gift of money or other inducement.” You are trying to persuade me to act dishonestly with a gift of money. It is literally the definition of a bribe. Please stop emailing me or I will report you to Amazon.com directly.

To be fair, this is probably some underpaid individual in China who sees this as an opportunity to make enough money to survive. It’s just a job to someone. And my ethical pleadings will never persuade them to stop doing what they are doing because they need to eat. I get that. But it’s still a bribe.

Change Doorbell Sound on Ring App and Amazon Echo

I’ve had a Ring doorbell (and security system) for quite a while. I never bought the chime that goes with the doorbell because it has always worked through my Amazon Echo devices. However, I only recently learned that you can change the notification sounds you get when someone rings your doorbell. However, how you do this requires clicking through almost a dozen screens in the Ring app and I can never remember it. So, here’s how to do it.

Change Doorbell Sound on Ring App

I’ll start with the notification sound you get on your phone through the Ring app when someone pushes the doorbell. First, open the Ring app and you’ll be on the Dashboard or Home screen:

The dashboard or home screen.

Click the three lines in the upper left corner to open that menu:

Menu options.

Select “Devices”:

The list of devices.

Now select your Video Doorbell (mine is called “Front Door”):

Options for your Video Doorbell.

You’ll have to scroll down (at least, I did), to see the settings icon (the gear). Click on that:

These are the settings for your video doorbell.

The settings you want are the Alert Settings. So, click on that:

The alert settings for your video doorbell.

The second option down in the screenshot above is for the chimes that you can use if you have a separate chime for your device. I don’t. So, what I want to change are the “App Alert Tones.” Click on that option and you’ll get this screen:

App Alert Tones screen

We’re almost there (I know, right!?!). Now click on “Ring Alerts” and you’ll get this screen:

Here’s where you can adjust all of the alerts for your phone (through the Ring app) when someone pushes your doorbell. You can silence it. You can turn on or off the notifications. You can set it to Pop on screen. What we want is at the very bottom in the “Advanced” section. Click on that and you’ll get more options:

This is the same screen, just after I scrolled down to the see the advanced options.

Now, finally, we can change the sound. Click on “Sound” (it will indicate which sound you are currently using below “Sound”) and you’ll get this screen:

These are your options for doorbell notifications on your phone through the Ring App.

You can pick any of the sounds or music available there. If you want to set it to a song or something like that, you can put that into a folder on your phone called “Ringtones” and they will show up there.

Change Doorbell Sound on Amazone Echo Devices for Ring

In addition to changing the sound on your phone, you can also change the sound on your Amazon Echo if you have it connected to the Ring app. I’m not going to go through how to connect it to the Ring app as that is pretty straightforward (download the Ring skill for your Echo), but here is how to change your doorbell sound on your Amazon Echo.

First, open the Amazon Echo app:

Amazon Echo home screen.

In the bottom right, click on “Devices”:

A list of my devices.

I have a lot of devices set up with my Amazon Echo, so I actually have to scroll over to see all the devices (just swipe the list at the top to the left – Tinder style!) to see the option for All Devices:

I swiped left!

Click on “All Devices” and you’ll get a list of all the devices you have set up on Amazon’s Echo/Alexa app. You need to find the app that has a camera icon and is whatever you named your Ring video doorbell. Mine is called “Front Door”:

You’re looking for your Ring video doorbell in the list of devices.

Click on that and you’ll see the settings screen for your video doorbell:

The selected sound is under “Doorbell Sound.”

As you can see in the screenshot above, I had set up a “Howl” for Halloween. I want to switch it to something different. Click on the Doorbell Sound option and you’ll see a list of additional sounds:

The list of doorbell sounds.

The list includes seasonal options. I went with Xmas Elves. Select it and click back and that will be the new sound that is played through your Amazon Echo devices when the Ring video doorbell is pressed:

It worked!

Now, the next time I want to change this option, I won’t have to click on 50 different options in the various apps. Hooray for me (and you)!