从另一个数据框添加行到绘图

时间:2018-04-19 22:22:12

标签: r ggplot2

我正在尝试在绘图上添加分组线,其中值是从另一个数据帧计算的。

我的数据如下:

demo_df <- structure(list(Sample_Run = structure(c(3L, 4L, 2L, 1L, 5L, 3L,
1L, 4L, 5L, 2L, 3L, 2L, 1L, 5L, 4L), .Label = c("Sample1", "Sample2",
"Sample3", "Sample4", "Sample5", "Sample6", "Sample7", "Sample8",
"Sample9", "Sample10", "Sample11", "Sample12", "Sample13", "Sample14",
"Sample15", "Sample16", "Sample17", "Sample18", "Sample19", "Sample20"
), class = "factor"), MUT_ID = structure(c(1L, 1L, 1L, 1L, 1L,
3L, 3L, 3L, 3L, 3L, 2L, 2L, 2L, 2L, 2L), .Label = c("AKT1 c.49G>A",
"APC c.4348C>T", "APC c.4666_4667insA", "ATM c.1058_1059delGT",
"BRAF c.1799T>A", "CTNNB1 c.121A>G", "EGFR c.2236_2250del15",
"EGFR c.2310_2311insGGT", "EGFR c.2369C>T", "EGFR c.2573T>G",
"ERBB2 c.2324_2325ins12", "FGFR3 c.746C>G", "FLT3 c.2503G>T",
"GNA11 c.626A>T", "GNAQ c.626A>C", "GNAS c.601C>T", "JAK2 c.1849G>T",
"KIT c.2447A>T", "KRAS c.35G>A", "MPL c.1544G>T", "NPM1 c.863_864insTCTG",
"NRAS c.182A>G", "PDGFRA c.1694_1695insA", "PDGFRA c.2525A>T",
"PIK3CA c.1633G>A", "PIK3CA c.3140A>G", "PIK3CA c.3204_3205insA",
"PTEN c.741_742insA", "PTEN c.800delA", "RET c.2753T>C", "SMAD4 c.1394_1395insT",
"TP53 c.524G>A", "TP53 c.723delC", "TP53 c.743G>A", "TP53 c.818G>A"
), class = "factor"), FREQ = c(0.091, 0.077, 0.09, 0.096, 0.114,
0.081, 0.071, 0.076, 0.084, 0.083, 0.08, 0.082, 0.087, 0.085,
0.094)), .Names = c("Sample_Run", "MUT_ID", "FREQ"), row.names = c(1L,
4L, 5L, 7L, 8L, 46L, 47L, 48L, 50L, 51L, 91L, 93L, 94L, 96L,
97L), class = "data.frame")

demo_sd <- aggregate(demo_df[["FREQ"]], by=list(as.factor(demo_df[["MUT_ID"]])), FUN=sd)
names(demo_sd) <- c("MUT_ID", "sd")

demo_mean <- aggregate(demo_df[["FREQ"]], by=list(as.factor(demo_df[["MUT_ID"]])), FUN=mean)
names(demo_mean) <- c("MUT_ID", "mean")

demo_mean_sd <- merge(x = demo_sd, y = demo_mean)
demo_mean_sd[["sd_interval_upper"]] <- demo_mean_sd[["mean"]] + (2 * demo_mean_sd[["sd"]])
demo_mean_sd[["sd_interval_lower"]] <- demo_mean_sd[["mean"]] - (2 * demo_mean_sd[["sd"]])

输出:

> demo_df
   Sample_Run              MUT_ID  FREQ
1     Sample3        AKT1 c.49G>A 0.091
4     Sample4        AKT1 c.49G>A 0.077
5     Sample2        AKT1 c.49G>A 0.090
7     Sample1        AKT1 c.49G>A 0.096
8     Sample5        AKT1 c.49G>A 0.114
46    Sample3 APC c.4666_4667insA 0.081
47    Sample1 APC c.4666_4667insA 0.071
48    Sample4 APC c.4666_4667insA 0.076
50    Sample5 APC c.4666_4667insA 0.084
51    Sample2 APC c.4666_4667insA 0.083
91    Sample3       APC c.4348C>T 0.080
93    Sample2       APC c.4348C>T 0.082
94    Sample1       APC c.4348C>T 0.087
96    Sample5       APC c.4348C>T 0.085
97    Sample4       APC c.4348C>T 0.094

> demo_mean_sd
               MUT_ID          sd   mean sd_interval_upper sd_interval_lower
1        AKT1 c.49G>A 0.013390295 0.0936        0.12038059        0.06681941
2       APC c.4348C>T 0.005412947 0.0856        0.09642589        0.07477411
3 APC c.4666_4667insA 0.005431390 0.0790        0.08986278        0.06813722

我可以像这样制作基本情节:

library("ggplot2")
ggplot(data =  demo_df, 
       aes(y = FREQ, x = Sample_Run, color = MUT_ID, group = MUT_ID) ) + 
    geom_point() +
    geom_line(alpha = 0.3) +
    facet_grid(MUT_ID~.) +
    scale_y_continuous(limits = c(0, NA))

看起来像这样:

example_plot

但是我需要从demo_mean_sd数据框中添加标准差的行,并且意味着。看起来应该是这样的:

example_plot2

然而,由于缺少一个共同的x轴,我一直在试图让线条在绘图上绘制时遇到问题。例如,我尝试过这样的事情:

ggplot(data =  demo_df, 
       aes(y = FREQ, x = Sample_Run, color = MUT_ID, group = MUT_ID) ) + 
    geom_point() +
    geom_line(alpha = 0.3) +
    facet_grid(MUT_ID~.) +
    scale_y_continuous(limits = c(0, NA)) +
    geom_ribbon(data = demo_mean_sd, aes(ymin = sd_interval_lower, ymax = sd_interval_upper))

错误:

Error in eval(expr, envir, enclos) : object 'Sample_Run' not found

由于刻面,我无法弄清楚如何使用其他绘图类型。

2 个答案:

答案 0 :(得分:2)

一种方法是在创建绘图之前合并数据框。您可以使用dplyr在MUT_ID上合并以下内容:

ggplot(data =  demo_df_merged, 
       aes(x = Sample_Run, color = MUT_ID, group = MUT_ID) ) + 
  geom_point(aes(y = FREQ)) +
  geom_line(alpha = 0.3, aes(y = FREQ)) +
  geom_line(aes(y = mean)) +
  geom_line(size = 2, aes(y = sd_interval_upper)) +
  geom_line(size = 2, aes(y = sd_interval_lower)) +
  facet_grid(MUT_ID~.) +
  scale_y_continuous(limits = c(0, NA))

合并后,您可以使用geom_line绘制上限和下限以及平均值

import 'dart:ui' as ui;

import 'package:flutter/material.dart';

///This class is use just to check if the Image returned by
///the PictureRecorder of the first Canvas is not empty.
class CanvasImageDraw extends CustomPainter {
  ui.Image image;

  CanvasImageDraw(this.image);

  @override
  void paint(ui.Canvas canvas, ui.Size size) {
    // simple aspect fit for the image
    var hr = size.height / image.height;
    var wr = size.width / image.width;

    double ratio;
    double translateX;
    double translateY;
    if (hr < wr) {
      ratio = hr;
      translateX = (size.width - (ratio * image.width)) / 2;
      translateY = 0.0;
    } else {
      ratio = wr;
      translateX = 0.0;
      translateY = (size.height - (ratio * image.height)) / 2;
    }

    canvas.translate(translateX, translateY);
    canvas.scale(ratio, ratio);
    canvas.drawImage(image, new Offset(0.0, 0.0), new Paint());
  }

  @override
  bool shouldRepaint(CanvasImageDraw oldDelegate) {
    return image != oldDelegate.image;
  }
}

///Class used to display the second canvas
class SecondView extends StatelessWidget {
  ui.Image image;

  var pictureRecorder = new ui.PictureRecorder();

  SecondView({this.image});

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('Image Debug'),
        ),
        body: new Column(
          children: <Widget>[
            new Text('Top'),
            CustomPaint(
              painter: new CanvasImageDraw(image),
              size: new Size(200.0, 200.0),
            ),
            new Text('Bottom'),
          ],
        ));
  }
}

///This is the CustomPainter of the first Canvas which is used
///to draw to display the users draw/sign.
class SignaturePainter extends CustomPainter {
  final List<Offset> points;
  final int revision;

  SignaturePainter(this.points, [this.revision = 0]);

  void paint(canvas, Size size) {
    if (points.length < 2) return;

    Paint paint = new Paint()
      ..color = Colors.black
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 5.0;

    for (int i = 0; i < points.length - 1; i++) {
      if (points[i] != null && points[i + 1] != null)
        canvas.drawLine(points[i], points[i + 1], paint);
    }
  }

  // simplified this, but if you ever modify points instead of changing length you'll
  // have to revise.
  bool shouldRepaint(SignaturePainter other) => other.revision != revision;
}

///Classes used to get the user draw/sign, send it to the first canvas,
///then display it.
///'points' list of position returned by the GestureDetector
class Signature extends StatefulWidget {
  Signature({Key key}): super(key: key);

  @override
  State<StatefulWidget> createState()=> new SignatureState();
}

class SignatureState extends State<Signature> {
  List<Offset> _points = <Offset>[];
  int _revision = 0;

  ui.Image get rendered {
    var pictureRecorder = new ui.PictureRecorder();
    Canvas canvas = new Canvas(pictureRecorder);
    SignaturePainter painter = new SignaturePainter(_points);

    var size = context.size;
    // if you pass a smaller size here, it cuts off the lines
    painter.paint(canvas, size);
    // if you use a smaller size for toImage, it also cuts off the lines - so I've
    // done that in here as well, as this is the only place it's easy to get the width & height.
    return pictureRecorder.endRecording().toImage(size.width.floor(), size.height.floor());
  }

  void _addToPoints(Offset position) {
    _revision++;
    _points.add(position);
  }

  Widget build(BuildContext context) {
    return new Stack(
      children: [
        GestureDetector(
          onPanStart: (DragStartDetails details) {
            RenderBox referenceBox = context.findRenderObject();
            Offset localPosition = referenceBox.globalToLocal(details.globalPosition);
            setState(() {
              _addToPoints(localPosition);
            });
          },
          onPanUpdate: (DragUpdateDetails details) {
            RenderBox referenceBox = context.findRenderObject();
            Offset localPosition = referenceBox.globalToLocal(details.globalPosition);
            setState(() {
              _addToPoints(localPosition);
            });
          },
          onPanEnd: (DragEndDetails details) => setState(() => _addToPoints(null)),
        ),
        CustomPaint(painter: new SignaturePainter(_points, _revision)),
      ],
    );
  }
}

///The main class which display the first Canvas, Drawing/Signing area
///
///Floating action button used to stop the PictureRecorder's recording,
///then send the Picture to the next view/Canvas which should display it
class DemoApp extends StatelessWidget {
  GlobalKey<SignatureState> signatureKey = new GlobalKey();

  Widget build(BuildContext context) => new Scaffold(
        body: new Signature(key: signatureKey),
        floatingActionButton: new FloatingActionButton(
          child: new Icon(Icons.save),
          onPressed: () async {
            var image = signatureKey.currentState.rendered;
            Navigator.push(context, new MaterialPageRoute(builder: (context) => new SecondView(image: image)));
          },
        ),
      );
}

void main() => runApp(new MaterialApp(home: new DemoApp()));

Example plot with lines

答案 1 :(得分:2)

首先,ggplot2在所有数据都在一个长格式数据帧中时效果最佳,因此我会避免在第一个实例中创建更多数据帧。

其次,我会以不同的方式显示这些数据。丝带表示沿x轴的某种进展,通常是时间,这不是这里的情况。如果您对突变的重复方法感兴趣,我建议x轴应为MUT_ID,重复应为点,然后使用stat_summary添加用误差线表示。

这样的事情:

library(tidyverse)
# mean_sdl gives you the mean + 2 SD
demo_df %>% 
  ggplot(aes(MUT_ID, FREQ)) + 
    geom_jitter(aes(color = Sample_Run), 
                width = 0.2, 
                size = 2) + 
    stat_summary(fun.data = mean_sdl, 
                 geom = "errorbar", 
                 width = 0.2) + 
    stat_summary(fun.y = mean, 
                 geom = "point", 
                 fill = "red", 
                 size = 4, 
                 shape = 23) + 
    theme_bw()

enter image description here