5

I have plotted a markov chain from a matrix in r. However, I have numerous probabilities under 0.01, and thus my probability plot looks something like this:

enter image description here

I've been searching for hours and I can't seem to find something that allows me to display all four decimal places. Is there any way to format this or should I leave it as is?

My code is as follows:

library(markovchain)

newtransition.matrix <- matrix( data = c(
  .9366, .0066, .0007, .0003 ,.0003, 0, .0015, 0, 
  .0583, .9172, .0225, .0026, .0006, .001, 0, 0,
  .004, .0694, .9176, .0483, .0044, .0032, .0029, 0,
  .0009, .0049, .0518, .8924, .0666, .0046, .0088, 0,
  .0002, .0006, .0049, .0444, .8323, .0572, .0191, 0,
  0, .0009, .002, .0081, .0746, .8362, .1028, 0,
  0, .0002, .0001, .0016, .0105, .0384, .6123, 0,
  0, .0002, .0004, .0023, .0107, .0594, .2526, 1),
  nrow = 8, ncol = 8,
  dimnames = list( c( "AAA", "AA", "A", "BBB", "BB", "B", "CCC", "Default" ), c( "AAA", "AA", "A", "BBB", "BB", "B", "CCC", "Default") ) )
 print( newtransition.matrix )

newtransition.matrix <- new( "markovchain", transitionMatrix = newtransition.matrix )
layout <- matrix(c(-3, 1, 2, 2, 2, -2, 4, 1, 0, 6, 0, -6, -3, -4, 3, -4), ncol = 2, byrow = TRUE)

plot(newtransition.matrix, vertex.size = 10, layout = layout, edge.arrow.size=0.25)

Many thanks!

Marcus Campbell
  • 2,746
  • 4
  • 22
  • 36
Megan
  • 61
  • 1
  • I went through the documentation of the package at https://mran.revolutionanalytics.com/web/packages/markovchain/vignettes/an_introduction_to_markovchain_package.pdf it seems that you can only show maximum 2 decimals. I do not know if this is acceptable but you could multiply everything by 100 or something like that? – Seymour Apr 10 '18 at 21:15
  • It might be deliberate since that plot is going to get difficult to read below 2 decimals. I'd think you're better off looking at the transition matrix itself. – Anonymous coward Apr 10 '18 at 21:24
  • @Seymour multiplying everything by 100 (and thus displaying probabilities as percentages) seems like the best solution. The solutions below (as impressive as they are) are too cluttered to read. – John Coleman Apr 10 '18 at 22:01
  • @John Coleman I agree that the solutions seem too cluttered with so many decimal places. There are some other packages that may be up to the task of de-cluttering things (see https://stackoverflow.com/a/21035960/9598813), but personally I liked your idea of using percentages. – Marcus Campbell Apr 10 '18 at 22:13

2 Answers2

5

You need to edit the S4 methods. 2 digits limit is hard coded in the plotting function. I cannot manage to edit the body of the function with code alone (if anyone else can figure it out, leave a comment). The code below requires a bit of user input.

# Digging to find the plotting function for markovchain
showMethods(plot)

# Find the source code
f <- getMethod("plot", signature = c(x="markovchain", y="missing"))

# Ahh it uses plot.igraph, and the labels are being specified with edge.label = edgeLabel
# But edgeLabel is being rounded to 2 digits
# Extract and edit the body of f, 
# Change round(E(netMc)$weight/100, 2) to round(E(netMc)$weight/100, 4) or something larger
g <- edit(body(f@.Data))

# Store the edited body again
body(f@.Data) <- g

# Call new plotting function to plot with more digits
f(newtransition.matrix, vertex.size = 10, layout = layout, edge.arrow.size=0.25)

enter image description here

Vlo
  • 3,168
  • 13
  • 27
  • 1
    I like this answer very much, as the overall thought process - using `showMethods()` and `getMethod()` to investigate the behaviour of a function - is very helpful in many situations, rather than just this one. – Marcus Campbell Apr 11 '18 at 02:21
5

Here's a simple solution that uses the igraph package. If you look at the documentation for markovchain, the plotting function for markovchain simply calls the plot function from igraph, so you will find that many (if not all) of the plotting arguments are cross-compatible between both kinds of objects.

Here, we simply create an igraph object from your transition matrix, and plot that instead. You will probably find this more convenient than plotting the markovchain objects directly.

library(markovchain)
library(igraph)
newtransition.matrix <- new( "markovchain", transitionMatrix = newtransition.matrix )
layout <- matrix(c(-3, 1, 2, 2, 2, -2, 4, 1, 0, 6, 0, -6, -3, -4, 3, -4),
ncol = 2,
byrow = TRUE)

# create an igraph object from your transition matrix
graph <- as(newtransition.matrix, "igraph") 

plot(graph, vertex.size = 15,
            edge.label = E(graph)$prob, # We add the proper edge labels here
            layout = layout,
            edge.arrow.size=0.25)

enter image description here

Marcus Campbell
  • 2,746
  • 4
  • 22
  • 36