ggplot ที่มี 2 แกน y ในแต่ละด้านและระดับที่แตกต่างกัน


231

ฉันต้องพล็อตแผนภูมิแท่งที่แสดงจำนวนและแผนภูมิเส้นที่แสดงอัตราทั้งหมดในหนึ่งแผนภูมิฉันสามารถทำทั้งสองอย่างแยกจากกัน แต่เมื่อฉันรวมเข้าด้วยกันฉันจะปรับสเกลของเลเยอร์แรก (เช่นgeom_bar) ทับซ้อนกันเป็นวินาที ชั้น (เช่นgeom_line)

ฉันสามารถเลื่อนแกนของgeom_lineไปทางขวาได้ไหม?


5
คุณสามารถใช้แนวทางเป็นชวอนที่นี่ได้หรือไม่rpubs.com/kohske/dual_axis_in_ggplot2
Tom Wenseleers


2
วิธีเลื่อนลงไปดูพื้นเมืองggplot2การดำเนินงานภายในปัจจุบันเรียกscale_y_* sec.axis
PatrickT

คำตอบ:


106

บางครั้งลูกค้าต้องการเครื่องชั่งสองเครื่อง ให้พวกเขาพูด "สมบูรณ์" มักจะไม่มีจุดหมาย แต่ฉันชอบการยืนยัน ggplot2 ในการทำสิ่งที่ถูกต้อง ฉันแน่ใจว่า ggplot กำลังให้ความรู้แก่ผู้ใช้โดยเฉลี่ยเกี่ยวกับเทคนิคการสร้างภาพข้อมูลที่เหมาะสม

บางทีคุณสามารถใช้ faceting และ scale ได้ฟรีเพื่อเปรียบเทียบชุดข้อมูลสองชุด - เช่นดูที่นี่: https://github.com/hadley/ggplot2/wiki/Align-two-plots-on-a-page


30
ฉันเห็นด้วยกับ Andreas - บางครั้ง (เช่นตอนนี้สำหรับฉัน) ลูกค้าต้องการข้อมูลสองชุดในพล็อตเดียวกันและไม่ต้องการฟังฉันพูดคุยเกี่ยวกับพล็อตเรื่องทฤษฎี ฉันต้องโน้มน้าวให้พวกเขาไม่ต้องการอีกต่อไป (ไม่ใช่การต่อสู้ที่ฉันต้องการค่าจ้าง) หรือบอกพวกเขาว่า "แพ็คเกจการวางแผนที่ฉันใช้ไม่รองรับ" ดังนั้นฉันจึงเปลี่ยนจาก ggplot ในวันนี้สำหรับโครงการนี้โดยเฉพาะ = (
Ken Williams

58
ทำไมแพ็คเกจการลงจุดจึงจำเป็นต้องแทรกความคิดเห็นส่วนตัวของตัวเองลงในการทำงานของมัน? ไม่เป็นไรขอบคุณ.
ลิน

5
ลิงก์ของคุณหายไป คุณสามารถแก้ไขคำตอบและโพสต์สรุปสิ่งที่เคยพูดได้หรือไม่
Zach

24
ไม่สามารถเห็นด้วยกับความคิดเห็นนี้ (คุยโว) มันเป็นเรื่องธรรมดามาก (!) ในการย่อข้อมูลให้มากที่สุดเท่าที่จะทำได้เช่นได้รับข้อ จำกัด ที่เข้มงวดที่กำหนดโดยวารสารทางวิทยาศาสตร์ ฯลฯ ดังนั้นการเพิ่มแกน y อันที่สองก็เสร็จเรียบร้อยแล้วและในความคิดของฉัน ggplot ควรช่วยในการทำเช่นนั้น
ปลากระเบน

57
น่าประหลาดใจที่คำว่า "ข้อบกพร่อง" และ "ทางที่ถูกต้อง" ถูกโยนทิ้งราวกับว่าพวกเขาไม่ได้มีพื้นฐานมาจากทฤษฎีที่ว่าตัวเองค่อนข้างดื้อดึงและดื้อรั้น แต่เป็นที่ยอมรับโดยคนจำนวนมากจนมองไม่เห็น ความจริงที่ว่าคำตอบที่ไม่ช่วยเหลืออย่างสมบูรณ์ (ซึ่งส่งลิงค์กระดูก) มี 72 upvotes ณ เวลาที่เขียน Whe เปรียบเทียบอนุกรมเวลาเช่นมันสามารถล้ำค่าที่จะมีทั้งในชาร์ตเหมือนกันเพราะความสัมพันธ์ของความแตกต่างเป็นเรื่องง่ายที่จะจุด เพียงแค่ถามผู้เชี่ยวชาญด้านการเงินที่มีการศึกษาสูงหลายพันคนที่ทำสิ่งนี้ทุกวันทุกวัน
โทมัสบราวน์

149

เป็นไปไม่ได้ใน ggplot2 เพราะฉันเชื่อว่าแปลงที่มีเกล็ด y แยกต่างหาก (ไม่ใช่เครื่องชั่งน้ำหนัก y ที่เป็นการแปลงซึ่งกันและกัน) นั้นมีข้อบกพร่องพื้นฐาน ปัญหาบางอย่าง:

  • ไม่สามารถย้อนกลับได้: เมื่อกำหนดจุดบนพื้นที่ว่างลงคุณไม่สามารถแมปกลับไปยังจุดหนึ่งในพื้นที่ข้อมูลได้

  • อ่านค่อนข้างยากเมื่อเปรียบเทียบกับตัวเลือกอื่น ๆ ดูการศึกษาแผนภูมิข้อมูลสองมิติโดย Petra Isenberg, Anastasia Bezerianos, Pierre Dragicevic และ Jean-Daniel Fekete สำหรับรายละเอียด

  • พวกมันถูกทำให้เข้าใจผิดได้ง่าย: ไม่มีวิธีใดที่จะระบุสเกลสัมพัทธ์ของแกนได้ ตัวอย่างที่สองจาก Junkcharts บล็อก: หนึ่ง , สอง

  • มันมีกฎเกณฑ์: ทำไมมีเพียง 2 สเกลเท่านั้นไม่ใช่ 3, 4 หรือสิบ

คุณอาจต้องการอ่านการสนทนาที่ยาวเหยียดของ Stephen Few ในหัวข้อDual-Scaled Axes ในกราฟพวกเขาเคยเป็นทางออกที่ดีที่สุดหรือไม่? .


39
คุณจะอธิบายความคิดเห็นของคุณให้ละเอียดหรือไม่? ฉันคิดว่ามันเป็นวิธีที่กะทัดรัดในการวางแผนตัวแปรอิสระสองตัว นอกจากนี้ยังเป็นคุณสมบัติที่ดูเหมือนว่าจะถูกถามและมันถูกใช้อย่างกว้างขวาง
KarlP

66
@Hadley: ส่วนใหญ่ฉันเห็นด้วย แต่มีการใช้งานจริงสำหรับเครื่องชั่งหลายเครื่อง - การใช้ 2 หน่วยที่แตกต่างกันสำหรับข้อมูลเดียวกันเช่นเครื่องชั่ง Celsius และ Fahrenheit ในชุดเวลาที่มีอุณหภูมิ
Richie Cotton

11
@Hadley ในความคิดของคุณ ไม่ใช่ของฉันหรือนักวิทยาศาสตร์อื่น ๆ อีกมากมาย แน่นอนว่าสิ่งนี้สามารถเกิดขึ้นได้ด้วยการวางจุดที่สอง (ที่มีพื้นหลังโปร่งใสอย่างเต็มที่) โดยตรงในช่วงแรก ฉันไม่ทราบวิธีการตรวจสอบมุมของ boxex bounding ที่สอดคล้อง / ลงทะเบียนกัน
นิโคลัสแฮมิลตัน

8
@hadley ตัวอย่างเช่นในWalther-Lieth Climate Diagramsจะใช้แกน y สองแกน เนื่องจากมีการกําหนดคงที่วิธีการทำที่สับสนเป็นไปได้น้อย ...
sebschub

32
@ แฮดลีย์ฉันขอโทษฉันไม่เห็นว่ามีปัญหาอะไรกับแผนภาพสภาพภูมิอากาศที่ระบุ การใส่อุณหภูมิและการตกตะกอนในหนึ่งไดอะแกรม (เมื่อมีการกําหนดตายตัว) จะมีการคาดเดาอย่างรวดเร็วก่อนว่าสภาพอากาศชื้นหรือแห้งแล้ง หรือวิธีการ: สิ่งที่จะเป็นวิธีที่ดีกว่าที่จะเห็นภาพอุณหภูมิการเร่งรัดและ "ความสัมพันธ์" ของพวกเขา? อย่างไรก็ตามขอบคุณมากสำหรับการทำงานของคุณใน ggplot2!
sebschub

121

เริ่มต้นด้วย ggplot2 2.2.0 คุณสามารถเพิ่มแกนทุติยภูมิเช่นนี้ (นำมาจากการประกาศ ggplot2 2.2.0 ):

ggplot(mpg, aes(displ, hwy)) + 
  geom_point() + 
  scale_y_continuous(
    "mpg (US)", 
    sec.axis = sec_axis(~ . * 1.20, name = "mpg (UK)")
  )

ป้อนคำอธิบายรูปภาพที่นี่


25
ข้อเสียคือมันสามารถใช้การแปลงสูตรบางอย่างของแกนปัจจุบันไม่ใช่ตัวแปรใหม่ตัวอย่างเช่น
ลูกโซ่

41

รับคำตอบข้างต้นและปรับจูน (และสำหรับสิ่งที่คุ้มค่า) นี่คือวิธีการบรรลุสองเครื่องชั่งผ่านsec_axis:

สมมติว่าชุดข้อมูลที่เรียบง่าย (และบริสุทธิ์) dt: เป็นเวลาห้าวันที่จะติดตามจำนวนการหยุดชะงักของ VS การเพิ่มผลผลิต:

        when numinter prod
1 2018-03-20        1 0.95
2 2018-03-21        5 0.50
3 2018-03-23        4 0.70
4 2018-03-24        3 0.75
5 2018-03-25        4 0.60

(ช่วงของคอลัมน์ทั้งสองแตกต่างกันไปตามปัจจัยที่ 5)

รหัสต่อไปนี้จะวาดทั้งสองซีรี่ส์ที่ใช้แกน y ทั้งหมด:

ggplot() + 
  geom_bar(mapping = aes(x = dt$when, y = dt$numinter), stat = "identity", fill = "grey") +
  geom_line(mapping = aes(x = dt$when, y = dt$prod*5), size = 2, color = "blue") + 
  scale_x_date(name = "Day", labels = NULL) +
  scale_y_continuous(name = "Interruptions/day", 
    sec.axis = sec_axis(~./5, name = "Productivity % of best", 
      labels = function(b) { paste0(round(b * 100, 0), "%")})) + 
  theme(
      axis.title.y = element_text(color = "grey"),
      axis.title.y.right = element_text(color = "blue"))

นี่คือผลลัพธ์ (โค้ดด้านบน + การปรับแต่งสี):

สองเครื่องชั่งในหนึ่ง ggplot2

จุด (นอกเหนือจากการใช้sec_axisเมื่อระบุ y_scale คือการคูณแต่ละชุดข้อมูลชุดที่ 2 กับ 5 เมื่อระบุชุดเพื่อให้ได้ฉลากที่ถูกต้องในคำจำกัดความ sec_axis นั้นก็ต้องหารด้วย 5 (และการจัดรูปแบบ) ดังนั้น ส่วนสำคัญในรหัสข้างต้นเป็นจริง*5ใน geom_line และ~./5ใน sec_axis (สูตรหารค่าปัจจุบัน.ด้วย 5)

ในการเปรียบเทียบ (ฉันไม่ต้องการตัดสินแนวทางที่นี่) นี่คือลักษณะของแผนภูมิสองแผนภูมิที่อยู่ด้านบนของอีกแผนภูมิหนึ่งที่มีลักษณะดังนี้:

สองชาร์ตเหนือกันและกัน

คุณสามารถตัดสินด้วยตัวคุณเองว่าคนไหนส่งข้อความได้ดีกว่า (“ อย่ารบกวนผู้คนในที่ทำงาน!”) เดาว่าเป็นวิธีที่ยุติธรรมในการตัดสินใจ

รหัสเต็มสำหรับภาพทั้งสอง (ไม่มากไปกว่าสิ่งที่กล่าวมาข้างต้นเพียงกรอกและพร้อมใช้งาน) อยู่ที่นี่: https://gist.github.com/sebastianrothbucher/de847063f32fdff02c83b75f59c36a7dคำอธิบายโดยละเอียดเพิ่มเติมได้ที่นี่: https: // sebastianrothbucher github.io/datascience/r/visualization/ggplot/2018/03/24/two-scales-ggplot-r.html


31

มีกรณีที่ใช้กันอย่างแพร่หลายเช่นขวาน y, เช่นclimatographแสดงอุณหภูมิรายเดือนและปริมาณน้ำฝน นี่คือวิธีแก้ปัญหาอย่างง่ายโดยทั่วไปจากโซลูชันของ Megatron โดยอนุญาตให้คุณตั้งค่าขีด จำกัด ล่างของตัวแปรเป็นอย่างอื่นที่ไม่ใช่ศูนย์:

ข้อมูลตัวอย่าง:

climate <- tibble(
  Month = 1:12,
  Temp = c(-4,-4,0,5,11,15,16,15,11,6,1,-3),
  Precip = c(49,36,47,41,53,65,81,89,90,84,73,55)
  )

ตั้งค่าสองค่าต่อไปนี้เป็นค่าใกล้เคียงกับขีด จำกัด ของข้อมูล (คุณสามารถเล่นกับสิ่งเหล่านี้เพื่อปรับตำแหน่งของกราฟแกนจะยังคงถูกต้อง):

ylim.prim <- c(0, 180)   # in this example, precipitation
ylim.sec <- c(-4, 18)    # in this example, temperature

ต่อไปนี้ทำให้การคำนวณที่จำเป็นขึ้นอยู่กับข้อ จำกัด เหล่านี้และสร้างพล็อตของตัวเอง:

b <- diff(ylim.prim)/diff(ylim.sec)
a <- b*(ylim.prim[1] - ylim.sec[1])

ggplot(climate, aes(Month, Precip)) +
  geom_col() +
  geom_line(aes(y = a + Temp*b), color = "red") +
  scale_y_continuous("Precipitation", sec.axis = sec_axis(~ (. - a)/b, name = "Temperature")) +
  scale_x_continuous("Month", breaks = 1:12) +
  ggtitle("Climatogram for Oslo (1961-1990)")  

Climatogram แสดงอุณหภูมิเป็นเส้นและการตกตะกอนเป็น barplot

หากคุณต้องการตรวจสอบให้แน่ใจว่าเส้นสีแดงตรงกับแกน y ด้านขวาคุณสามารถเพิ่มthemeประโยคให้กับรหัสได้:

ggplot(climate, aes(Month, Precip)) +
  geom_col() +
  geom_line(aes(y = a + Temp*b), color = "red") +
  scale_y_continuous("Precipitation", sec.axis = sec_axis(~ (. - a)/b, name = "Temperature")) +
  scale_x_continuous("Month", breaks = 1:12) +
  theme(axis.line.y.right = element_line(color = "red"), 
        axis.ticks.y.right = element_line(color = "red"),
        axis.text.y.right = element_text(color = "red"), 
        axis.title.y.right = element_text(color = "red")
        ) +
  ggtitle("Climatogram for Oslo (1961-1990)")

แกนสีทางขวา:

Climatogram ที่มีแกนขวาสีแดง


แบ่งนี้ที่ค่าของบางส่วนและylim.prim ylim.sec
Eric Krantz

5
มันเยี่ยมมาก ตัวอย่างที่ดีของเวลาที่แผนภูมิสองแกนไม่ "สมบูรณ์" ส่วนหนึ่งของความคิดที่เป็นระเบียบเรียบร้อยทั่วไปของการคิดว่าพวกเขารู้มากขึ้นเกี่ยวกับงานของคุณมากกว่าที่คุณทำ
Leo Barlach

เมื่อฉันเลือกขีด จำกัด ของแกนที่เฉพาะเจาะจง (ในกรณีของฉัน ylim.prim <- c (90, 130) และ ylim.sec <- c (15, 30)) มันใช้ไม่ได้ แต่เลือกขีด จำกัด โดยพลการ . ฉันไม่แน่ใจว่าสิ่งที่ฉันหายไปเมื่อฉันคัดลอกรหัสข้างต้นและเพิ่งเปลี่ยนชื่อตัวแปรและข้อ จำกัด แกน
Anke

@anke: ข้อความค่อนข้างเลอะเทอะเมื่ออ้างถึง ylim.prim และ ylim.sec พวกเขาไม่ได้อ้างถึงขีด จำกัด ของแกน แต่หมายถึงขีด จำกัด ของข้อมูลของคุณ เมื่อคุณตั้งค่า ylim.prim <- c (90, 130) และ ylim.sec <- c (15, 30) ตามที่คุณพูดถึงกราฟอุณหภูมิจะสูงขึ้นเหนือพล็อตแท่ง (เมื่อแกนอุณหภูมิเริ่มต้นที่ -75) แต่แกนของแต่ละกราฟยังคงถูกต้อง
Dag Hjermann

16

คุณสามารถสร้างตัวคูณสเกลซึ่งใช้กับ geom ที่สองและแกน y ที่เหมาะสม สิ่งนี้ได้มาจากการแก้ปัญหาของเซบาสเตียน

library(ggplot2)

scaleFactor <- max(mtcars$cyl) / max(mtcars$hp)

ggplot(mtcars, aes(x=disp)) +
  geom_smooth(aes(y=cyl), method="loess", col="blue") +
  geom_smooth(aes(y=hp * scaleFactor), method="loess", col="red") +
  scale_y_continuous(name="cyl", sec.axis=sec_axis(~./scaleFactor, name="hp")) +
  theme(
    axis.title.y.left=element_text(color="blue"),
    axis.text.y.left=element_text(color="blue"),
    axis.title.y.right=element_text(color="red"),
    axis.text.y.right=element_text(color="red")
  )

ป้อนคำอธิบายรูปภาพที่นี่

หมายเหตุ: ใช้ggplot2 v3.0.0


14

กระดูกสันหลังทางเทคนิคในการแก้ไขปัญหานี้ได้รับการจัดหาโดยKohske เมื่อ 3 ปีที่แล้ว [ KOHSKE ] หัวข้อและด้านเทคนิครอบโซลูชันได้ถูกกล่าวถึงในหลาย ๆ กรณีที่นี่ใน Stackoverflow [IDs: 18989001, 29235405, 21026598] ดังนั้นฉันจะให้เฉพาะรูปแบบที่เฉพาะเจาะจงและคำอธิบายแบบบางส่วนโดยใช้วิธีการแก้ปัญหา

ให้เราสมมติว่าเรามีข้อมูลy1ในกลุ่มG1ซึ่งข้อมูลบางอย่างy2ในกลุ่มG2มีความสัมพันธ์ในทางใดทางหนึ่งเช่นการแปลงช่วง / สเกลหรือการเพิ่มสัญญาณรบกวน ดังนั้นหนึ่งต้องการพล็อตข้อมูลร่วมกันในหนึ่งพล็อตที่มีสเกลy1ทางด้านซ้ายและy2ทางด้านขวา

  df <- data.frame(item=LETTERS[1:n],  y1=c(-0.8684, 4.2242, -0.3181, 0.5797, -0.4875), y2=c(-5.719, 205.184, 4.781, 41.952, 9.911 )) # made up!

> df
  item      y1         y2
1    A -0.8684 -19.154567
2    B  4.2242 219.092499
3    C -0.3181  18.849686
4    D  0.5797  46.945161
5    E -0.4875  -4.721973

ถ้าตอนนี้เราวางแผนข้อมูลของเราพร้อมกับสิ่งที่ชอบ

ggplot(data=df, aes(label=item)) +
  theme_bw() + 
  geom_segment(aes(x='G1', xend='G2', y=y1, yend=y2), color='grey')+
  geom_text(aes(x='G1', y=y1), color='blue') +
  geom_text(aes(x='G2', y=y2), color='red') +
  theme(legend.position='none', panel.grid=element_blank())

มันไม่จัดอย่างเป็นขนาดที่เล็กy1 obviosuly ได้รับการทรุดตัวลงโดยขนาดใหญ่y2

เคล็ดลับที่นี่เพื่อตอบสนองความท้าทายคือการ techncially พล็อตทั้งสองชุดข้อมูลกับขนาดแรกy1แต่รายงานที่สองกับแกนรองที่มีป้ายแสดงขนาดเดิมy2

ดังนั้นเราจึงสร้างฟังก์ชันผู้ช่วยคนแรกCalcFudgeAxisซึ่งคำนวณและรวบรวมคุณสมบัติของแกนใหม่ที่จะแสดง ฟังก์ชั่นสามารถแก้ไขได้เป็น ayones โดนใจ (อันนี้แค่แมปy2กับช่วงy1 )

CalcFudgeAxis = function( y1, y2=y1) {
  Cast2To1 = function(x) ((ylim1[2]-ylim1[1])/(ylim2[2]-ylim2[1])*x) # x gets mapped to range of ylim2
  ylim1 <- c(min(y1),max(y1))
  ylim2 <- c(min(y2),max(y2))    
  yf <- Cast2To1(y2)
  labelsyf <- pretty(y2)  
  return(list(
    yf=yf,
    labels=labelsyf,
    breaks=Cast2To1(labelsyf)
  ))
}

อะไรให้ผลบ้าง:

> FudgeAxis <- CalcFudgeAxis( df$y1, df$y2 )

> FudgeAxis
$yf
[1] -0.4094344  4.6831656  0.4029175  1.0034664 -0.1009335

$labels
[1] -50   0  50 100 150 200 250

$breaks
[1] -1.068764  0.000000  1.068764  2.137529  3.206293  4.275058  5.343822


> cbind(df, FudgeAxis$yf)
  item      y1         y2 FudgeAxis$yf
1    A -0.8684 -19.154567   -0.4094344
2    B  4.2242 219.092499    4.6831656
3    C -0.3181  18.849686    0.4029175
4    D  0.5797  46.945161    1.0034664
5    E -0.4875  -4.721973   -0.1009335

ตอนนี้ฉันห่อคำตอบของ Kohskeในฟังก์ชันผู้ช่วยที่สองPlotWithFudgeAxis (ซึ่งเราโยนวัตถุ ggplot และวัตถุผู้ช่วยของแกนใหม่):

library(gtable)
library(grid)

PlotWithFudgeAxis = function( plot1, FudgeAxis) {
  # based on: https://rpubs.com/kohske/dual_axis_in_ggplot2
  plot2 <- plot1 + with(FudgeAxis, scale_y_continuous( breaks=breaks, labels=labels))

  #extract gtable
  g1<-ggplot_gtable(ggplot_build(plot1))
  g2<-ggplot_gtable(ggplot_build(plot2))

  #overlap the panel of the 2nd plot on that of the 1st plot
  pp<-c(subset(g1$layout, name=="panel", se=t:r))
  g<-gtable_add_grob(g1, g2$grobs[[which(g2$layout$name=="panel")]], pp$t, pp$l, pp$b,pp$l)

  ia <- which(g2$layout$name == "axis-l")
  ga <- g2$grobs[[ia]]
  ax <- ga$children[[2]]
  ax$widths <- rev(ax$widths)
  ax$grobs <- rev(ax$grobs)
  ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15, "cm")
  g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
  g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)

  grid.draw(g)
}

ตอนนี้ทุกอย่างสามารถรวมกันได้: รหัสด้านล่างแสดงให้เห็นว่าวิธีการแก้ปัญหาที่เสนอสามารถนำมาใช้ในสภาพแวดล้อมแบบวันต่อวันได้อย่างไร พล็อตโทรพล็อตในขณะนี้ไม่ได้ข้อมูลเดิมy2อีกต่อไป แต่โคลนรุ่นYF (ถือหุ้นภายในก่อนคำนวณผู้ช่วยวัตถุFudgeAxis ) ซึ่งไหลจากขนาดของy1 จากนั้น ggplot objet จะถูกจัดการด้วยฟังก์ชั่นผู้ช่วยของKohske PlotWithFudgeAxisเพื่อเพิ่มแกนที่สองที่รักษาระดับy2ไว้ มันแปลงเช่นเดียวกับพล็อตที่มีการจัดการ

FudgeAxis <- CalcFudgeAxis( df$y1, df$y2 )

tmpPlot <- ggplot(data=df, aes(label=item)) +
      theme_bw() + 
      geom_segment(aes(x='G1', xend='G2', y=y1, yend=FudgeAxis$yf), color='grey')+
      geom_text(aes(x='G1', y=y1), color='blue') +
      geom_text(aes(x='G2', y=FudgeAxis$yf), color='red') +
      theme(legend.position='none', panel.grid=element_blank())

PlotWithFudgeAxis(tmpPlot, FudgeAxis)

ตอนนี้แปลงตามต้องการด้วยสองแกนy1ทางด้านซ้ายและy2ทางด้านขวา

2 แกน

วิธีการแก้ปัญหาด้านบนคือการแฮ็คที่สั่นคลอน จำกัด ในขณะที่เล่นกับเคอร์เนล ggplot มันจะโยนคำเตือนบางอย่างที่เราแลกเปลี่ยนเกล็ดหลังความจริง ฯลฯ มันจะต้องได้รับการจัดการด้วยความระมัดระวังและอาจก่อให้เกิดพฤติกรรมที่ไม่พึงประสงค์ในการตั้งค่าอื่น เช่นกันอาจต้องทำเล่น ๆ กับฟังก์ชั่นตัวช่วยเพื่อรับเค้าโครงตามต้องการ การวางตำแหน่งของตำนานเป็นปัญหาดังกล่าว (มันจะถูกวางไว้ระหว่างแผงควบคุมและแกนใหม่นั่นคือเหตุผลที่ฉันวางมันลง) การปรับ / การจัดตำแหน่งของ 2 แกนนั้นท้าทายเล็กน้อยเช่นกัน: โค้ดด้านบนใช้งานได้ดีเมื่อเครื่องชั่งทั้งสองมี "0" อีกแกนหนึ่งจะได้รับการเลื่อน ดังนั้นด้วยโอกาสที่จะปรับปรุง ...

ในกรณีที่ต้องการบันทึกรูปหนึ่งจะต้องตัดสายเข้าสู่อุปกรณ์เปิด / ปิด:

png(...)
PlotWithFudgeAxis(tmpPlot, FudgeAxis)
dev.off()

9

บทความต่อไปนี้ช่วยให้ฉันรวมสองแปลงที่สร้างโดย ggplot2 ในแถวเดียว:

กราฟหลายกราฟในหนึ่งหน้า (ggplot2) โดย Cookbook สำหรับ R

และนี่คือรหัสที่อาจมีลักษณะในกรณีนี้:

p1 <- 
  ggplot() + aes(mns)+ geom_histogram(aes(y=..density..), binwidth=0.01, colour="black", fill="white") + geom_vline(aes(xintercept=mean(mns, na.rm=T)), color="red", linetype="dashed", size=1) +  geom_density(alpha=.2)

p2 <- 
  ggplot() + aes(mns)+ geom_histogram( binwidth=0.01, colour="black", fill="white") + geom_vline(aes(xintercept=mean(mns, na.rm=T)), color="red", linetype="dashed", size=1)  

multiplot(p1,p2,cols=2)

เกิดอะไรขึ้นกับฟังก์ชันทวีคูณ ฉันได้รับข้อผิดพลาดที่ไม่พบฟังก์ชันแม้ว่าจะมีการติดตั้งและโหลดไลบรารี ggplot2 แล้วก็ตาม
Nneka

1
@Danka ฟังก์ชัน multipot เป็นฟังก์ชันที่กำหนดเอง (ที่ด้านล่างของหน้าเชื่อมโยง)
Dribbel

คุณสามารถเพิ่มเนื้อเรื่องได้หรือไม่?
Sibo Jiang

เมื่อเร็ว ๆ นี้มีแพ็คเกจจำนวนมากที่มีตัวเลือก / คุณสมบัติมากกว่าmultiplot stackoverflow.com/a/51220506
ตุง

7

สำหรับฉันแล้วชิ้นส่วนที่ยุ่งยากคือการหาฟังก์ชั่นการแปลงระหว่างสองแกน ฉันใช้ myCurveFitสำหรับสิ่งนั้น

> dput(combined_80_8192 %>% filter (time > 270, time < 280))
structure(list(run = c(268L, 268L, 268L, 268L, 268L, 268L, 268L, 
268L, 268L, 268L, 263L, 263L, 263L, 263L, 263L, 263L, 263L, 263L, 
263L, 263L, 269L, 269L, 269L, 269L, 269L, 269L, 269L, 269L, 269L, 
269L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 261L, 
267L, 267L, 267L, 267L, 267L, 267L, 267L, 267L, 267L, 267L, 265L, 
265L, 265L, 265L, 265L, 265L, 265L, 265L, 265L, 265L, 266L, 266L, 
266L, 266L, 266L, 266L, 266L, 266L, 266L, 266L, 262L, 262L, 262L, 
262L, 262L, 262L, 262L, 262L, 262L, 262L, 264L, 264L, 264L, 264L, 
264L, 264L, 264L, 264L, 264L, 264L, 260L, 260L, 260L, 260L, 260L, 
260L, 260L, 260L, 260L, 260L), repetition = c(8L, 8L, 8L, 8L, 
8L, 8L, 8L, 8L, 8L, 8L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 5L, 5L, 
5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 
6L, 6L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 4L, 4L, 4L, 4L, 
4L, 4L, 4L, 4L, 4L, 4L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L
), module = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "scenario.node[0].nicVLCTail.phyVLC", class = "factor"), 
    configname = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L), .Label = "Road-Vlc", class = "factor"), packetByteLength = c(8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 
    8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L, 8192L
    ), numVehicles = c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L
    ), dDistance = c(80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
    80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
    80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
    80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
    80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
    80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
    80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
    80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L, 
    80L, 80L, 80L, 80L, 80L, 80L, 80L, 80L), time = c(270.166006903445, 
    271.173853699836, 272.175873251122, 273.177524313334, 274.182946177105, 
    275.188959464989, 276.189675339937, 277.198250244799, 278.204619457189, 
    279.212562800009, 270.164199199177, 271.168527215152, 272.173072994958, 
    273.179210429715, 274.184351047337, 275.18980754378, 276.194816792995, 
    277.198598277809, 278.202398083519, 279.210634593917, 270.210674322891, 
    271.212395107473, 272.218871923292, 273.219060500457, 274.220486359614, 
    275.22401452372, 276.229646658839, 277.231060448138, 278.240407241942, 
    279.2437126347, 270.283554249858, 271.293168593832, 272.298574288769, 
    273.304413221348, 274.306272082517, 275.309023049011, 276.317805897347, 
    277.324403550028, 278.332855848701, 279.334046374594, 270.118608539613, 
    271.127947700074, 272.133887145863, 273.135726000491, 274.135994529981, 
    275.136563912708, 276.140120735361, 277.144298344151, 278.146885137621, 
    279.147552358659, 270.206015567272, 271.214618077209, 272.216566814903, 
    273.225435592582, 274.234014573683, 275.242949179958, 276.248417809711, 
    277.248800670023, 278.249750333404, 279.252926560188, 270.217182684494, 
    271.218357511397, 272.224698488895, 273.231112784327, 274.238740508457, 
    275.242715184122, 276.249053562718, 277.250325509798, 278.258488063493, 
    279.261141590137, 270.282904173953, 271.284689544638, 272.294220723234, 
    273.299749415592, 274.30628880553, 275.312075103126, 276.31579134717, 
    277.321905523606, 278.326305136748, 279.333056502253, 270.258991527456, 
    271.260224091407, 272.270076810133, 273.27052037648, 274.274119348094, 
    275.280808254502, 276.286353887245, 277.287064312339, 278.294444793276, 
    279.296772014594, 270.333066283904, 271.33877455992, 272.345842319903, 
    273.350858180493, 274.353972278505, 275.360454510107, 276.365088896161, 
    277.369166956941, 278.372571708911, 279.38017503079), distanceToTx = c(80.255266401689, 
    80.156059067023, 79.98823695539, 79.826647129071, 79.76678667135, 
    79.788239825292, 79.734539327997, 79.74766421514, 79.801243848241, 
    79.765920888341, 80.255266401689, 80.15850240049, 79.98823695539, 
    79.826647129071, 79.76678667135, 79.788239825292, 79.735078924078, 
    79.74766421514, 79.801243848241, 79.764622734914, 80.251248121732, 
    80.146436869316, 79.984682320466, 79.82292012342, 79.761908518748, 
    79.796988776281, 79.736920997657, 79.745038376718, 79.802638836686, 
    79.770029970452, 80.243475525691, 80.127918207499, 79.978303140866, 
    79.816259117883, 79.749322030693, 79.809916018889, 79.744456560867, 
    79.738655068783, 79.788697533211, 79.784288359619, 80.260412958482, 
    80.168426829066, 79.992034911214, 79.830845773284, 79.7756751763, 
    79.778156038931, 79.732399593756, 79.752769548846, 79.799967731078, 
    79.757585110481, 80.251248121732, 80.146436869316, 79.984682320466, 
    79.822062073459, 79.75884601899, 79.801590491435, 79.738335109094, 
    79.74347007248, 79.803215965043, 79.771471198955, 80.250257298678, 
    80.146436869316, 79.983831684476, 79.822062073459, 79.75884601899, 
    79.801590491435, 79.738335109094, 79.74347007248, 79.803849157574, 
    79.771471198955, 80.243475525691, 80.130180105198, 79.978303140866, 
    79.816881283718, 79.749322030693, 79.80984572883, 79.744456560867, 
    79.738655068783, 79.790548644175, 79.784288359619, 80.246349000313, 
    80.137056554491, 79.980581246037, 79.818924707937, 79.753176142361, 
    79.808777040341, 79.741609845588, 79.740770913572, 79.796316397253, 
    79.777593733292, 80.238796415443, 80.119021911134, 79.974810568944, 
    79.814065350562, 79.743657315504, 79.810146783217, 79.749945098869, 
    79.737122584544, 79.781650522348, 79.791554933936), headerNoError = c(0.99999999989702, 
    0.9999999999981, 0.99999999999946, 0.9999999928026, 0.99999873265475, 
    0.77080141574964, 0.99007491438593, 0.99994396605059, 0.45588747062284, 
    0.93484381262491, 0.99999999989702, 0.99999999999816, 0.99999999999946, 
    0.9999999928026, 0.99999873265475, 0.77080141574964, 0.99008458785106, 
    0.99994396605059, 0.45588747062284, 0.93480223051707, 0.99999999989735, 
    0.99999999999789, 0.99999999999946, 0.99999999287551, 0.99999876302649, 
    0.46903147501117, 0.98835168988253, 0.99994427085086, 0.45235035271542, 
    0.93496741877335, 0.99999999989803, 0.99999999999781, 0.99999999999948, 
    0.99999999318224, 0.99994254156311, 0.46891362282273, 0.93382613917348, 
    0.99994594904099, 0.93002915596843, 0.93569767251247, 0.99999999989658, 
    0.99999999998074, 0.99999999999946, 0.99999999272802, 0.99999871586781, 
    0.76935240919896, 0.99002587758346, 0.99999881589732, 0.46179415706093, 
    0.93417422376389, 0.99999999989735, 0.99999999999789, 0.99999999999946, 
    0.99999999289347, 0.99999876940486, 0.46930769326427, 0.98837353639905, 
    0.99994447154714, 0.16313586712094, 0.93500824170148, 0.99999999989744, 
    0.99999999999789, 0.99999999999946, 0.99999999289347, 0.99999876940486, 
    0.46930769326427, 0.98837353639905, 0.99994447154714, 0.16330039178981, 
    0.93500824170148, 0.99999999989803, 0.99999999999781, 0.99999999999948, 
    0.99999999316541, 0.99994254156311, 0.46794586553266, 0.93382613917348, 
    0.99994594904099, 0.9303627789484, 0.93569767251247, 0.99999999989778, 
    0.9999999999978, 0.99999999999948, 0.99999999311433, 0.99999878195152, 
    0.47101897739483, 0.93368891853679, 0.99994556595217, 0.7571113417265, 
    0.93553999975802, 0.99999999998191, 0.99999999999784, 0.99999999999971, 
    0.99999891129658, 0.99994309267792, 0.46510628979591, 0.93442584181035, 
    0.99894450514543, 0.99890078483692, 0.76933812306423), receivedPower_dbm = c(-93.023492290586, 
    -92.388378035287, -92.205716340607, -93.816400586752, -95.023489422885, 
    -100.86308557253, -98.464763536915, -96.175707680373, -102.06189538385, 
    -99.716653422746, -93.023492290586, -92.384760627397, -92.205716340607, 
    -93.816400586752, -95.023489422885, -100.86308557253, -98.464201120719, 
    -96.175707680373, -102.06189538385, -99.717150021506, -93.022927803442, 
    -92.404017215549, -92.204561341714, -93.814319484729, -95.016990717792, 
    -102.01669022332, -98.558088145955, -96.173817001483, -102.07406915124, 
    -99.71517574876, -93.021813165972, -92.409586309743, -92.20229160243, 
    -93.805335867418, -96.184419849593, -102.01709540787, -99.728735187547, 
    -96.163233028048, -99.772547164798, -99.706399753853, -93.024204617071, 
    -92.745813384859, -92.206884754512, -93.818508150122, -95.027018807793, 
    -100.87000577258, -98.467607232407, -95.005311380324, -102.04157607608, 
    -99.724619517, -93.022927803442, -92.404017215549, -92.204561341714, 
    -93.813803344588, -95.015606885523, -102.0157405687, -98.556982278361, 
    -96.172566862738, -103.21871579865, -99.714687230796, -93.022787428238, 
    -92.404017215549, -92.204274688493, -93.813803344588, -95.015606885523, 
    -102.0157405687, -98.556982278361, -96.172566862738, -103.21784988098, 
    -99.714687230796, -93.021813165972, -92.409950613665, -92.20229160243, 
    -93.805838770576, -96.184419849593, -102.02042267497, -99.728735187547, 
    -96.163233028048, -99.768774335378, -99.706399753853, -93.022228914406, 
    -92.411048503835, -92.203136463155, -93.807357409082, -95.012865008237, 
    -102.00985717796, -99.730352912911, -96.165675535906, -100.92744056572, 
    -99.708301333236, -92.735781110993, -92.408137395049, -92.119533319039, 
    -94.982938427575, -96.181073124017, -102.03018610927, -99.721633629806, 
    -97.32940323644, -97.347613268692, -100.87007386786), snr = c(49.848348091678, 
    57.698190927109, 60.17669971462, 41.529809724535, 31.452202106925, 
    8.1976890851341, 14.240447804094, 24.122884195464, 6.2202875499406, 
    10.674183333671, 49.848348091678, 57.746270018264, 60.17669971462, 
    41.529809724535, 31.452202106925, 8.1976890851341, 14.242292077376, 
    24.122884195464, 6.2202875499406, 10.672962852322, 49.854827699773, 
    57.49079026127, 60.192705735317, 41.549715223147, 31.499301851462, 
    6.2853718719014, 13.937702343688, 24.133388256416, 6.2028757927148, 
    10.677815810561, 49.867624820879, 57.417115267867, 60.224172277442, 
    41.635752021705, 24.074540962859, 6.2847854917092, 10.644529778044, 
    24.19227425387, 10.537686730745, 10.699414795917, 49.84017267426, 
    53.139646558768, 60.160512118809, 41.509660845114, 31.42665220053, 
    8.1846370024428, 14.231126423354, 31.584125885363, 6.2494585568733, 
    10.654622041348, 49.854827699773, 57.49079026127, 60.192705735317, 
    41.55465351989, 31.509340361646, 6.2867464196657, 13.941251828322, 
    24.140336174865, 4.765718874642, 10.679016976694, 49.856439162736, 
    57.49079026127, 60.196678846453, 41.55465351989, 31.509340361646, 
    6.2867464196657, 13.941251828322, 24.140336174865, 4.7666691818074, 
    10.679016976694, 49.867624820879, 57.412299088098, 60.224172277442, 
    41.630930975211, 24.074540962859, 6.279972363168, 10.644529778044, 
    24.19227425387, 10.546845071479, 10.699414795917, 49.862851240855, 
    57.397787176282, 60.212457625018, 41.61637603957, 31.529239767749, 
    6.2952688513108, 10.640565481982, 24.178672145334, 8.0771089950663, 
    10.694731030907, 53.262541905639, 57.43627424514, 61.382796189332, 
    31.747253311549, 24.093100244121, 6.2658701281075, 10.661949889074, 
    18.495227442305, 18.417839037171, 8.1845086722809), frameId = c(15051, 
    15106, 15165, 15220, 15279, 15330, 15385, 15452, 15511, 15566, 
    15019, 15074, 15129, 15184, 15239, 15298, 15353, 15412, 15471, 
    15526, 14947, 14994, 15057, 15112, 15171, 15226, 15281, 15332, 
    15391, 15442, 14971, 15030, 15085, 15144, 15203, 15262, 15321, 
    15380, 15435, 15490, 14915, 14978, 15033, 15092, 15147, 15198, 
    15257, 15312, 15371, 15430, 14975, 15034, 15089, 15140, 15195, 
    15254, 15313, 15368, 15427, 15478, 14987, 15046, 15105, 15160, 
    15215, 15274, 15329, 15384, 15447, 15506, 14943, 15002, 15061, 
    15116, 15171, 15230, 15285, 15344, 15399, 15454, 14971, 15026, 
    15081, 15136, 15195, 15258, 15313, 15368, 15423, 15478, 15039, 
    15094, 15149, 15204, 15263, 15314, 15369, 15428, 15487, 15546
    ), packetOkSinr = c(0.99999999314881, 0.9999999998736, 0.99999999996428, 
    0.99999952114066, 0.99991568416005, 3.00628034688444e-08, 
    0.51497487795954, 0.99627877136019, 0, 0.011303253101957, 
    0.99999999314881, 0.99999999987726, 0.99999999996428, 0.99999952114066, 
    0.99991568416005, 3.00628034688444e-08, 0.51530974419663, 
    0.99627877136019, 0, 0.011269851265775, 0.9999999931708, 
    0.99999999985986, 0.99999999996428, 0.99999952599145, 0.99991770469509, 
    0, 0.45861812482641, 0.99629897628155, 0, 0.011403119534097, 
    0.99999999321568, 0.99999999985437, 0.99999999996519, 0.99999954639936, 
    0.99618434878558, 0, 0.010513119213425, 0.99641022914441, 
    0.00801687746446111, 0.012011103529927, 0.9999999931195, 
    0.99999999871861, 0.99999999996428, 0.99999951617905, 0.99991456738049, 
    2.6525298291169e-08, 0.51328066587104, 0.9999212220316, 0, 
    0.010777054258914, 0.9999999931708, 0.99999999985986, 0.99999999996428, 
    0.99999952718674, 0.99991812902805, 0, 0.45929307038653, 
    0.99631228046814, 0, 0.011436292559188, 0.99999999317629, 
    0.99999999985986, 0.99999999996428, 0.99999952718674, 0.99991812902805, 
    0, 0.45929307038653, 0.99631228046814, 0, 0.011436292559188, 
    0.99999999321568, 0.99999999985437, 0.99999999996519, 0.99999954527918, 
    0.99618434878558, 0, 0.010513119213425, 0.99641022914441, 
    0.00821047996950475, 0.012011103529927, 0.99999999319919, 
    0.99999999985345, 0.99999999996519, 0.99999954188106, 0.99991896371849, 
    0, 0.010410830482692, 0.996384831822, 9.12484388049251e-09, 
    0.011877185067536, 0.99999999879646, 0.9999999998562, 0.99999999998077, 
    0.99992756868677, 0.9962208785486, 0, 0.010971897073662, 
    0.93214999078663, 0.92943956665979, 2.64925478221656e-08), 
    snir = c(49.848348091678, 57.698190927109, 60.17669971462, 
    41.529809724535, 31.452202106925, 8.1976890851341, 14.240447804094, 
    24.122884195464, 6.2202875499406, 10.674183333671, 49.848348091678, 
    57.746270018264, 60.17669971462, 41.529809724535, 31.452202106925, 
    8.1976890851341, 14.242292077376, 24.122884195464, 6.2202875499406, 
    10.672962852322, 49.854827699773, 57.49079026127, 60.192705735317, 
    41.549715223147, 31.499301851462, 6.2853718719014, 13.937702343688, 
    24.133388256416, 6.2028757927148, 10.677815810561, 49.867624820879, 
    57.417115267867, 60.224172277442, 41.635752021705, 24.074540962859, 
    6.2847854917092, 10.644529778044, 24.19227425387, 10.537686730745, 
    10.699414795917, 49.84017267426, 53.139646558768, 60.160512118809, 
    41.509660845114, 31.42665220053, 8.1846370024428, 14.231126423354, 
    31.584125885363, 6.2494585568733, 10.654622041348, 49.854827699773, 
    57.49079026127, 60.192705735317, 41.55465351989, 31.509340361646, 
    6.2867464196657, 13.941251828322, 24.140336174865, 4.765718874642, 
    10.679016976694, 49.856439162736, 57.49079026127, 60.196678846453, 
    41.55465351989, 31.509340361646, 6.2867464196657, 13.941251828322, 
    24.140336174865, 4.7666691818074, 10.679016976694, 49.867624820879, 
    57.412299088098, 60.224172277442, 41.630930975211, 24.074540962859, 
    6.279972363168, 10.644529778044, 24.19227425387, 10.546845071479, 
    10.699414795917, 49.862851240855, 57.397787176282, 60.212457625018, 
    41.61637603957, 31.529239767749, 6.2952688513108, 10.640565481982, 
    24.178672145334, 8.0771089950663, 10.694731030907, 53.262541905639, 
    57.43627424514, 61.382796189332, 31.747253311549, 24.093100244121, 
    6.2658701281075, 10.661949889074, 18.495227442305, 18.417839037171, 
    8.1845086722809), ookSnirBer = c(8.8808636558081e-24, 3.2219795637026e-27, 
    2.6468895519653e-28, 3.9807779074715e-20, 1.0849324265615e-15, 
    2.5705217057696e-05, 4.7313805615763e-08, 1.8800438086075e-12, 
    0.00021005320203921, 1.9147343768384e-06, 8.8808636558081e-24, 
    3.0694773489537e-27, 2.6468895519653e-28, 3.9807779074715e-20, 
    1.0849324265615e-15, 2.5705217057696e-05, 4.7223753038869e-08, 
    1.8800438086075e-12, 0.00021005320203921, 1.9171738578051e-06, 
    8.8229427230445e-24, 3.9715925056443e-27, 2.6045198111088e-28, 
    3.9014083702734e-20, 1.0342658440386e-15, 0.00019591630514278, 
    6.4692014108683e-08, 1.8600094209271e-12, 0.0002140067535655, 
    1.9074922485477e-06, 8.7096574467175e-24, 4.2779443633862e-27, 
    2.5231916788231e-28, 3.5761615214425e-20, 1.9750692814982e-12, 
    0.0001960392878411, 1.9748966344895e-06, 1.7515881895994e-12, 
    2.2078334799411e-06, 1.8649940680806e-06, 8.954486301678e-24, 
    3.2021085732779e-25, 2.690441113724e-28, 4.0627628846548e-20, 
    1.1134484878561e-15, 2.6061691733331e-05, 4.777159157954e-08, 
    9.4891388749738e-16, 0.00020359398491544, 1.9542110660398e-06, 
    8.8229427230445e-24, 3.9715925056443e-27, 2.6045198111088e-28, 
    3.8819641115984e-20, 1.0237769828158e-15, 0.00019562832342849, 
    6.4455095380046e-08, 1.8468752030971e-12, 0.0010099091367628, 
    1.9051035165106e-06, 8.8085966897635e-24, 3.9715925056443e-27, 
    2.594108048185e-28, 3.8819641115984e-20, 1.0237769828158e-15, 
    0.00019562832342849, 6.4455095380046e-08, 1.8468752030971e-12, 
    0.0010088638355194, 1.9051035165106e-06, 8.7096574467175e-24, 
    4.2987746909572e-27, 2.5231916788231e-28, 3.593647329558e-20, 
    1.9750692814982e-12, 0.00019705170257492, 1.9748966344895e-06, 
    1.7515881895994e-12, 2.1868296425817e-06, 1.8649940680806e-06, 
    8.7517439682173e-24, 4.3621551072316e-27, 2.553168170837e-28, 
    3.6469582463164e-20, 1.0032983660212e-15, 0.00019385229409318, 
    1.9830820164805e-06, 1.7760568361323e-12, 2.919419915209e-05, 
    1.8741284335866e-06, 2.8285944348148e-25, 4.1960751547207e-27, 
    7.8468215407139e-29, 8.0407329049747e-16, 1.9380328071065e-12, 
    0.00020004849911333, 1.9393279417733e-06, 5.9354475879597e-10, 
    6.4258355913627e-10, 2.6065221215415e-05), ookSnrBer = c(8.8808636558081e-24, 
    3.2219795637026e-27, 2.6468895519653e-28, 3.9807779074715e-20, 
    1.0849324265615e-15, 2.5705217057696e-05, 4.7313805615763e-08, 
    1.8800438086075e-12, 0.00021005320203921, 1.9147343768384e-06, 
    8.8808636558081e-24, 3.0694773489537e-27, 2.6468895519653e-28, 
    3.9807779074715e-20, 1.0849324265615e-15, 2.5705217057696e-05, 
    4.7223753038869e-08, 1.8800438086075e-12, 0.00021005320203921, 
    1.9171738578051e-06, 8.8229427230445e-24, 3.9715925056443e-27, 
    2.6045198111088e-28, 3.9014083702734e-20, 1.0342658440386e-15, 
    0.00019591630514278, 6.4692014108683e-08, 1.8600094209271e-12, 
    0.0002140067535655, 1.9074922485477e-06, 8.7096574467175e-24, 
    4.2779443633862e-27, 2.5231916788231e-28, 3.5761615214425e-20, 
    1.9750692814982e-12, 0.0001960392878411, 1.9748966344895e-06, 
    1.7515881895994e-12, 2.2078334799411e-06, 1.8649940680806e-06, 
    8.954486301678e-24, 3.2021085732779e-25, 2.690441113724e-28, 
    4.0627628846548e-20, 1.1134484878561e-15, 2.6061691733331e-05, 
    4.777159157954e-08, 9.4891388749738e-16, 0.00020359398491544, 
    1.9542110660398e-06, 8.8229427230445e-24, 3.9715925056443e-27, 
    2.6045198111088e-28, 3.8819641115984e-20, 1.0237769828158e-15, 
    0.00019562832342849, 6.4455095380046e-08, 1.8468752030971e-12, 
    0.0010099091367628, 1.9051035165106e-06, 8.8085966897635e-24, 
    3.9715925056443e-27, 2.594108048185e-28, 3.8819641115984e-20, 
    1.0237769828158e-15, 0.00019562832342849, 6.4455095380046e-08, 
    1.8468752030971e-12, 0.0010088638355194, 1.9051035165106e-06, 
    8.7096574467175e-24, 4.2987746909572e-27, 2.5231916788231e-28, 
    3.593647329558e-20, 1.9750692814982e-12, 0.00019705170257492, 
    1.9748966344895e-06, 1.7515881895994e-12, 2.1868296425817e-06, 
    1.8649940680806e-06, 8.7517439682173e-24, 4.3621551072316e-27, 
    2.553168170837e-28, 3.6469582463164e-20, 1.0032983660212e-15, 
    0.00019385229409318, 1.9830820164805e-06, 1.7760568361323e-12, 
    2.919419915209e-05, 1.8741284335866e-06, 2.8285944348148e-25, 
    4.1960751547207e-27, 7.8468215407139e-29, 8.0407329049747e-16, 
    1.9380328071065e-12, 0.00020004849911333, 1.9393279417733e-06, 
    5.9354475879597e-10, 6.4258355913627e-10, 2.6065221215415e-05
    )), class = "data.frame", row.names = c(NA, -100L), .Names = c("run", 
"repetition", "module", "configname", "packetByteLength", "numVehicles", 
"dDistance", "time", "distanceToTx", "headerNoError", "receivedPower_dbm", 
"snr", "frameId", "packetOkSinr", "snir", "ookSnirBer", "ookSnrBer"
))

การหาฟังก์ชั่นการแปลงรูป

  1. y1 -> y2 ฟังก์ชั่นนี้ใช้เพื่อแปลงข้อมูลของแกน y ที่สองให้เป็น "ปกติ" ตามแกน y แรก

ป้อนคำอธิบายรูปภาพที่นี่

ฟังก์ชั่นการเปลี่ยนแปลง: f(y1) = 0.025*x + 2.75


  1. y2 -> y1 ฟังก์ชั่นนี้ใช้เพื่อเปลี่ยนจุดพักของแกน y แรกให้เป็นค่าของแกน y ที่สอง โปรดทราบว่าแกนจะถูกสลับตอนนี้

ป้อนคำอธิบายรูปภาพที่นี่

ฟังก์ชั่นการเปลี่ยนแปลง: f(y1) = 40*x - 110


พล็อต

สังเกตวิธีการใช้ฟังก์ชั่นการแปลงในการggplotเรียกเพื่อแปลงข้อมูล "on-the-fly"

ggplot(data=combined_80_8192 %>% filter (time > 270, time < 280), aes(x=time) ) +
  stat_summary(aes(y=receivedPower_dbm ), fun.y=mean, geom="line", colour="black") +
  stat_summary(aes(y=packetOkSinr*40 - 110 ), fun.y=mean, geom="line", colour="black", position = position_dodge(width=10)) +
  scale_x_continuous() +
  scale_y_continuous(breaks = seq(-0,-110,-10), "y_first", sec.axis=sec_axis(~.*0.025+2.75, name="y_second") ) 

stat_summaryสายแรกคือสายที่ตั้งค่าฐานสำหรับแกน y แรก การstat_summaryเรียกที่สองเรียกว่าแปลงข้อมูล โปรดจำไว้ว่าข้อมูลทั้งหมดจะใช้เป็นฐานแกน y แรก ดังนั้นข้อมูลจะต้องถูกทำให้เป็นมาตรฐานสำหรับแกน y แรก ในการทำเช่นนั้นฉันใช้ฟังก์ชันการแปลงกับข้อมูล:y=packetOkSinr*40 - 110

ทีนี้เพื่อเปลี่ยนแกนที่สองฉันใช้ฟังก์ชั่นตรงข้ามภายในการscale_y_continuousโทร: sec.axis=sec_axis(~.*0.025+2.75, name="y_second").

ป้อนคำอธิบายรูปภาพที่นี่


2
R สามารถทำเรียงลำดับของสิ่งนี้และcoef(lm(c(-70, -110) ~ c(1,0))) coef(lm(c(1,0) ~ c(-70, -110)))คุณสามารถกำหนดฟังก์ชั่นตัวช่วยเช่น equationise <- function(range = c(-70, -110), target = c(1,0)){ c = coef(lm(target ~ range)) as.formula(substitute(~ a*. + b, list(a=c[[2]], b=c[[1]]))) }
baptiste

อ๋อฉันรู้ ... แค่คิดว่าเว็บไซต์จะใช้งานง่ายกว่าเดิม
user4786271

4

แน่นอนเราสามารถสร้างพล็อตที่มีคู่ Y-axises โดยใช้ฐาน R plotfuntion

# pseudo dataset
df <- data.frame(x = seq(1, 1000, 1), y1 = sample.int(100, 1000, replace=T), y2 = sample(50, 1000, replace = T))

# plot first plot 
with(df, plot(y1 ~ x, col = "red"))

# set new plot
par(new = T) 

# plot second plot, but without axis
with(df, plot(y2 ~ x, type = "l", xaxt = "n", yaxt = "n", xlab = "", ylab = ""))

# define y-axis and put y-labs
axis(4)
with(df, mtext("y2", side = 4))

1

คุณสามารถใช้facet_wrap(~ variable, ncol= )กับตัวแปรเพื่อสร้างการเปรียบเทียบใหม่ มันไม่ได้อยู่บนแกนเดียวกัน แต่มันก็คล้ายกัน


1

ฉันรับทราบและเห็นด้วยกับhadley (และอื่น ๆ ) ว่าเครื่องชั่งน้ำหนัก y แยกเป็น "ข้อบกพร่องพื้นฐาน" ต้องบอกว่า - ฉันมักจะต้องการggplot2ให้มีคุณสมบัติ - โดยเฉพาะเมื่อข้อมูลอยู่ในรูปแบบกว้างและฉันต้องการเห็นภาพหรือตรวจสอบข้อมูลอย่างรวดเร็ว (เช่นสำหรับใช้ส่วนตัวเท่านั้น)

ในขณะที่tidyverseห้องสมุดทำให้การแปลงข้อมูลเป็นรูปแบบยาวค่อนข้างง่าย (เช่นใช้facet_grid()งานได้) แต่กระบวนการดังกล่าวยังไม่น่าสนใจเท่าที่เห็นด้านล่าง:

library(tidyverse)
df.wide %>%
    # Select only the columns you need for the plot.
    select(date, column1, column2, column3) %>%
    # Create an id column – needed in the `gather()` function.
    mutate(id = n()) %>%
    # The `gather()` function converts to long-format. 
    # In which the `type` column will contain three factors (column1, column2, column3),
    # and the `value` column will contain the respective values.
    # All the while we retain the `id` and `date` columns.
    gather(type, value, -id, -date) %>%
    # Create the plot according to your specifications
    ggplot(aes(x = date, y = value)) +
        geom_line() +
        # Create a panel for each `type` (ie. column1, column2, column3).
        # If the types have different scales, you can use the `scales="free"` option.
        facet_grid(type~., scales = "free")

ในช่วงเวลาของการเขียน ggplot2 ได้รับการสนับสนุนผ่านทางนี้sec_axisแล้ว
Konrad Rudolph

0

คำตอบของ Hadleyให้การอ้างอิงที่น่าสนใจกับรายงานของ Stephen Few แกน Dual-Scaled Axe ในกราฟพวกเขาเคยเป็นทางออกที่ดีที่สุดหรือไม่? .

ฉันไม่ทราบว่า OP หมายถึง "จำนวน" และ "อัตรา" แต่การค้นหาอย่างรวดเร็วทำให้ฉันมีจำนวนและอัตราดังนั้นฉันได้รับข้อมูลบางอย่างเกี่ยวกับอุบัติเหตุในการปีนเขาอเมริกาเหนือ1 :

Years<-c("1998","1999","2000","2001","2002","2003","2004")
Persons.Involved<-c(281,248,301,276,295,231,311)
Fatalities<-c(20,17,24,16,34,18,35)
rate=100*Fatalities/Persons.Involved
df<-data.frame(Years=Years,Persons.Involved=Persons.Involved,Fatalities=Fatalities,rate=rate)
print(df,row.names = FALSE)

 Years Persons.Involved Fatalities      rate
  1998              281         20  7.117438
  1999              248         17  6.854839
  2000              301         24  7.973422
  2001              276         16  5.797101
  2002              295         34 11.525424
  2003              231         18  7.792208
  2004              311         35 11.254019

จากนั้นฉันพยายามทำกราฟตามที่แนะนำไว้ไม่กี่หน้า 7 ของรายงานข้างต้น (และทำตามคำขอของ OP เพื่อทำกราฟจำนวนที่นับเป็นแผนภูมิแท่งและอัตราเป็นแผนภูมิเส้น):

โซลูชันที่เห็นได้ชัดน้อยกว่าอื่น ๆ ซึ่งใช้งานได้เฉพาะกับอนุกรมเวลาคือการแปลงชุดของค่าทั้งหมดให้เป็นมาตราส่วนเชิงปริมาณโดยทั่วไปโดยแสดงความแตกต่างเปอร์เซ็นต์ระหว่างแต่ละค่าและค่าอ้างอิง (หรือดัชนี) ตัวอย่างเช่นเลือกจุดเฉพาะเวลาเช่นช่วงเวลาแรกที่ปรากฏในกราฟและแสดงแต่ละค่าที่ตามมาเป็นความแตกต่างร้อยละระหว่างมันและค่าเริ่มต้น สิ่งนี้ทำได้โดยการหารค่าในแต่ละจุดในเวลาด้วยค่าสำหรับจุดเริ่มต้นในเวลาและจากนั้นคูณด้วย 100 เพื่อแปลงอัตราเป็นเปอร์เซ็นต์ตามที่แสดงด้านล่าง

df2<-df
df2$Persons.Involved <- 100*df$Persons.Involved/df$Persons.Involved[1]
df2$rate <- 100*df$rate/df$rate[1]
plot(ggplot(df2)+
  geom_bar(aes(x=Years,weight=Persons.Involved))+
  geom_line(aes(x=Years,y=rate,group=1))+
  theme(text = element_text(size=30))
  )

และนี่คือผลลัพธ์ที่ได้: ป้อนคำอธิบายรูปภาพที่นี่

แต่ฉันไม่ชอบมันมากและฉันไม่สามารถใส่ตำนานได้อย่างง่ายดาย ...

1 วิล เลียมสัน, เจดและคณะ อุบัติเหตุในการปีนเขาอเมริกาเหนือ.นักไต่เขา, 2005


0

ดูเหมือนว่าจะเป็นคำถามง่าย ๆ แต่มันรบกวนประมาณ 2 คำถามพื้นฐาน A) วิธีจัดการกับข้อมูลที่มีหลายสเกลาร์ในขณะที่นำเสนอในแผนภูมิเปรียบเทียบและประการที่สอง B) สิ่งนี้สามารถทำได้โดยไม่ต้องใช้กฎง่ายๆของการเขียนโปรแกรม R เช่น i) ข้อมูลละลาย ii) การเผชิญหน้า, iii) การเพิ่ม อีกชั้นหนึ่งที่มีอยู่ วิธีการแก้ปัญหาที่ระบุด้านล่างเป็นไปตามเงื่อนไขทั้งสองข้างต้นเนื่องจากสามารถจัดการข้อมูลได้โดยไม่ต้องขายใหม่และอย่างที่สองไม่ได้ใช้เทคนิคที่กล่าวถึง

นี่คือผลลัพธ์ ดีขึ้นและปรับปรุง

สำหรับผู้ที่สนใจรู้เพิ่มเติมเกี่ยวกับวิธีนี้โปรดไปที่ลิงค์ด้านล่าง วิธีการพล็อตแผนภูมิแกน 2-y พร้อมแถบด้านข้างโดยไม่ต้องปรับขนาดข้อมูลอีกครั้ง


0

ฉันพบว่าคำตอบนี้ช่วยฉันได้มากที่สุด แต่พบว่ามีบางกรณีที่ไม่สามารถจัดการได้อย่างถูกต้องโดยเฉพาะอย่างยิ่งในแง่ลบและกรณีที่ขีด จำกัด ของฉันมีระยะทาง 0 (ซึ่งอาจเกิดขึ้นได้หากเรากำลังคว้า ขีด จำกัด ของเราจากข้อมูลสูงสุด / นาที) การทดสอบดูเหมือนจะบ่งบอกว่ามันใช้งานได้อย่างสม่ำเสมอ

ฉันใช้รหัสต่อไปนี้ ที่นี่ฉันคิดว่าเรามี [x1, x2] ที่เราต้องการเปลี่ยนเป็น [y1, y2] วิธีที่ฉันจัดการสิ่งนี้คือเปลี่ยน [x1, x2] เป็น [0,1] (การแปลงที่ง่ายพอ) จากนั้น [0,1] ถึง [y1, y2]

climate <- tibble(
  Month = 1:12,
  Temp = c(-4,-4,0,5,11,15,16,15,11,6,1,-3),
  Precip = c(49,36,47,41,53,65,81,89,90,84,73,55)
)
#Set the limits of each axis manually:

  ylim.prim <- c(0, 180)   # in this example, precipitation
ylim.sec <- c(-4, 18)    # in this example, temperature



  b <- diff(ylim.sec)/diff(ylim.prim)

#If all values are the same this messes up the transformation, so we need to modify it here
if(b==0){
  ylim.sec <- c(ylim.sec[1]-1, ylim.sec[2]+1)
  b <- diff(ylim.sec)/diff(ylim.prim)
}
if (is.na(b)){
  ylim.prim <- c(ylim.prim[1]-1, ylim.prim[2]+1)
  b <- diff(ylim.sec)/diff(ylim.prim)
}


ggplot(climate, aes(Month, Precip)) +
  geom_col() +
  geom_line(aes(y = ylim.prim[1]+(Temp-ylim.sec[1])/b), color = "red") +
  scale_y_continuous("Precipitation", sec.axis = sec_axis(~((.-ylim.prim[1]) *b  + ylim.sec[1]), name = "Temperature"), limits = ylim.prim) +
  scale_x_continuous("Month", breaks = 1:12) +
  ggtitle("Climatogram for Oslo (1961-1990)")  

ชิ้นส่วนที่สำคัญที่นี่มีที่เราเปลี่ยนแกน Y รองแล้วใช้ผกผันกับค่าที่เกิดขึ้นจริง~((.-ylim.prim[1]) *b + ylim.sec[1]) นอกจากนี้เรายังควรให้แน่ใจว่าy = ylim.prim[1]+(Temp-ylim.sec[1])/b)limits = ylim.prim

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.