Łączę dwa odrębne wątki w układ siatki z grid
zgodnie z sugestią @lgautier w rpy2 przy użyciu Pythona. Górna działka jest gęstość i a dolny wykres słupkowy:wyrównywanie wyraźnych wykresów niefazowych w ggplot2 przy użyciu Rpy2 w Pythonie
iris = r('iris')
import pandas
# define layout
lt = grid.layout(2, 1)
vp = grid.viewport(layout = lt)
vp.push()
# first plot
vp_p = grid.viewport(**{'layout.pos.row': 1, 'layout.pos.col':1})
p1 = ggplot2.ggplot(iris) + \
ggplot2.geom_density(aes_string(x="Sepal.Width",
colour="Species")) + \
ggplot2.facet_wrap(Formula("~ Species"))
p1.plot(vp = vp_p)
# second plot
mean_df = pandas.DataFrame({"Species": ["setosa", "virginica", "versicolor"],
"X": [10, 2, 30],
"Y": [5, 3, 4]})
mean_df = pandas.melt(mean_df, id_vars=["Species"])
r_mean_df = get_r_dataframe(mean_df)
p2 = ggplot2.ggplot(r_mean_df) + \
ggplot2.geom_bar(aes_string(x="Species",
y="value",
group="variable",
colour="variable"),
position=ggplot2.position_dodge(),
stat="identity")
vp_p = grid.viewport(**{'layout.pos.row': 2, 'layout.pos.col':1})
p2.plot(vp = vp_p)
co mam jest blisko tego, co chcę, ale działki nie są dokładnie dopasowane (pokazany przez strzałki, które dodałem):
Chciałbym, aby obszary działek (nie legendy) dokładnie się zgadzały. Jak można to osiągnąć? różnica tutaj nie jest tak duża, ale gdy dodasz warunki do wykresu słupkowego poniżej lub zmusisz je do uniknięcia wykresów słupkowych z position_dodge
różnice mogą stać się bardzo duże, a wykresy nie są wyrównane.
Standardowe rozwiązanie ggplot nie da się łatwo przełożyć na rpy2:
arrange
wydaje się być grid_arrange
w gridExtra
:
>>> gridExtra = importr("gridExtra")
>>> gridExtra.grid_arrange
<SignatureTranslatedFunction - Python:0x430f518/R:0x396f678>
ggplotGrob
nie jest dostępne od ggplot2
, ale mogą być dostępne tak:
>>> ggplot2.ggplot2.ggplotGrob
Chociaż nie mam pojęcia, jak uzyskać dostęp do grid::unit.pmax
:
>>> grid.unit
<bound method type.unit of <class 'rpy2.robjects.lib.grid.Unit'>>
>>> grid.unit("pmax")
Error in (function (x, units, data = NULL) :
argument "units" is missing, with no default
rpy2.rinterface.RRuntimeError: Error in (function (x, units, data = NULL) :
argument "units" is missing, with no default
więc nie jest jasne, w jaki sposób tłumaczyć standardowe rozwiązanie ggplot2 do rpy2.
edycja: jak inni wskazali grid::unit.pmax
jest . Nadal nie wiem, jak uzyskać dostęp do parametru rpy2 o wartości widths
obiektów grob
, co jest konieczne do ustawienia szerokości wykresów na szerszy wykres. Mam:
gA = ggplot2.ggplot2.ggplotGrob(p1)
gB = ggplot2.ggplot2.ggplotGrob(p2)
g = importr("grid")
print "gA: ", gA
maxWidth = g.unit_pmax(gA.widths[2:5], gB.widths[2:5])
gA.widths
nie jest poprawną składnią. W grob
obiektów gA
drukuje jak:
gA: TableGrob (8 x 13) "layout": 17 grobs
z cells name grob
1 0 (1- 8, 1-13) background rect[plot.background.rect.350]
2 1 (4- 4, 4- 4) panel-1 gTree[panel-1.gTree.239]
3 2 (4- 4, 7- 7) panel-2 gTree[panel-2.gTree.254]
4 3 (4- 4,10-10) panel-3 gTree[panel-3.gTree.269]
5 4 (3- 3, 4- 4) strip_t-1 absoluteGrob[strip.absoluteGrob.305]
6 5 (3- 3, 7- 7) strip_t-2 absoluteGrob[strip.absoluteGrob.311]
7 6 (3- 3,10-10) strip_t-3 absoluteGrob[strip.absoluteGrob.317]
8 7 (4- 4, 3- 3) axis_l-1 absoluteGrob[axis-l-1.absoluteGrob.297]
9 8 (4- 4, 6- 6) axis_l-2 zeroGrob[axis-l-2.zeroGrob.298]
10 9 (4- 4, 9- 9) axis_l-3 zeroGrob[axis-l-3.zeroGrob.299]
11 10 (5- 5, 4- 4) axis_b-1 absoluteGrob[axis-b-1.absoluteGrob.276]
12 11 (5- 5, 7- 7) axis_b-2 absoluteGrob[axis-b-2.absoluteGrob.283]
13 12 (5- 5,10-10) axis_b-3 absoluteGrob[axis-b-3.absoluteGrob.290]
14 13 (7- 7, 4-10) xlab text[axis.title.x.text.319]
15 14 (4- 4, 2- 2) ylab text[axis.title.y.text.321]
16 15 (4- 4,12-12) guide-box gtable[guide-box]
17 16 (2- 2, 4-10) title text[plot.title.text.348]
aktualizacja: pewien postęp w sprawie dostępu szerokościach, ale wciąż nie może tłumaczyć rozwiązanie. Aby ustawić szerokość grobs, mam:
# get grobs
gA = ggplot2.ggplot2.ggplotGrob(p1)
gB = ggplot2.ggplot2.ggplotGrob(p2)
g = importr("grid")
# get max width
maxWidth = g.unit_pmax(gA.rx2("widths")[2:5][0], gB.rx2("widths")[2:5][0])
print gA.rx2("widths")[2:5]
wA = gA.rx2("widths")[2:5]
wB = gB.rx2("widths")[2:5]
print "before: ", wA[0]
wA[0] = robj.ListVector(maxWidth)
print "After: ", wA[0]
print "before: ", wB[0]
wB[0] = robj.ListVector(maxWidth)
print "after:", wB[0]
gridExtra.grid_arrange(gA, gB, ncol=1)
Działa, ale nie działa. Wyjście jest:
[[1]]
[1] 0.740361111111111cm
[[2]]
[1] 1null
[[3]]
[1] 0.127cm
before: [1] 0.740361111111111cm
After: [1] max(0.740361111111111cm, sum(1grobwidth, 0.15cm+0.1cm))
before: [1] sum(1grobwidth, 0.15cm+0.1cm)
after: [1] max(0.740361111111111cm, sum(1grobwidth, 0.15cm+0.1cm))
Update2: realizowane jako @baptiste podkreślić, że przydatne byłoby, aby pokazać czystą wersję R, co próbuję odtworzyć w rpy2. Oto czysta wersja R:
df <- data.frame(Species=c("setosa", "virginica", "versicolor"),X=c(1,2,3), Y=c(10,20,30))
p1 <- ggplot(iris) + geom_density(aes(x=Sepal.Width, colour=Species))
p2 <- ggplot(df) + geom_bar(aes(x=Species, y=X, colour=Species))
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)
grid.arrange(gA, gB, ncol=1)
myślę, że to w ogólnych pracach na dwa panele z legendami, które mają różne aspekty w ggplot2 i chcę, aby zaimplementować to w rpy2.
update3: prawie dostał go do pracy, budując FloatVector
aż jeden element na raz:
maxWidth = []
for x, y in zip(gA.rx2("widths")[2:5], gB.rx2("widths")[2:5]):
pmax = g.unit_pmax(x, y)
print "PMAX: ", pmax
val = pmax[1][0][0]
print "VAL->", val
maxWidth.append(val)
gA[gA.names.index("widths")][2:5] = robj.FloatVector(maxWidth)
gridExtra.grid_arrange(gA, gB, ncol=1)
jednak to generuje zrzut segfault/Rdzeń:
Error: VECTOR_ELT() can only be applied to a 'list', not a 'double'
*** longjmp causes uninitialized stack frame ***: python2.7 terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x37)[0x7f83742e2817]
/lib/x86_64-linux-gnu/libc.so.6(+0x10a78d)[0x7f83742e278d]
/lib/x86_64-linux-gnu/libc.so.6(__longjmp_chk+0x33)[0x7f83742e26f3]
...
7f837591e000-7f8375925000 r--s 00000000 fc:00 1977264 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
7f8375926000-7f8375927000 rwxp 00000000 00:00 0
7f8375927000-7f8375929000 rw-p 00000000 00:00 0
7f8375929000-7f837592a000 r--p 00022000 fc:00 917959 /lib/x86_64-linux-gnu/ld-2.15.so
7f837592a000-7f837592c000 rw-p 00023000 fc:00 917959 /lib/x86_64-linux-gnu/ld-2.15.so
7ffff4b96000-7ffff4bd6000 rw-p 00000000 00:00 0 [stack]
7ffff4bff000-7ffff4c00000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)
Aktualizacja: nagroda została zakończona. Doceniam otrzymane odpowiedzi, ale żadna z odpowiedzi nie używa rpy2 i jest to pytanie rpy2, więc technicznie odpowiedzi nie dotyczą tematu. Istnieje proste rozwiązanie tego problemu (nawet jeśli nie ma na to rozwiązania w ogóle, jak wskazał @baptiste), a pytanie brzmi po prostu, jak przetłumaczyć je na rpy2
osoby, które oznaczyły to jako duplikat, mają zerową ocenę subtelności tłumaczenia kodu z R na Rpy2. Tak, czasami tłumaczenie jest łatwe, ale czasami jest sprzeczne z intuicją. To jest pytanie rpy2. To nie jest proste pytanie ggplot2. Po prostu przeszkadzasz i blokujesz proces pytań i odpowiedzi bez żadnego powodu. – user248237dfsf
'unit.pmax' to funkcja oddzielona od' jednostki' (chociaż oba są w pakiecie 'grid'). Czy w pythonie dostępne jest 'grid.unit.pmax' po' grid = importr ("grid") '? Czy też "rpy" robi tłumaczenie na kropki w nazwach funkcji, które nie są związane z wysyłką metody S3? –
@BrianDiggs wydaje się, że 'grid :: unit.pmax' stanie się' grid.unit_pmax' – baptiste