блискучі 4 невеликих поля для введення тексту поруч


79

У мене є блискучий сервер версії 0.4.0, і я хочу мати 4 невеликих поля вводу тексту, щоб виглядати так:

x-min x-max y-min y-max
[...] [...] [...] [...]

Вони тепер виглядають так:

x-min 
[...................]
x-max
[...................]
y-min 
[...................]
y-max 
[...................]

За допомогою цього коду:

textInput(inputId="xlimitsmin", label="x-min", value = 0.0),
textInput(inputId="xlimitsmax", label="x-max", value = 0.5),
textInput(inputId="ylimitsmin", label="y-min", value = 0.5),
textInput(inputId="ylimitsmax", label="y-max", value = 1.0),

Будь-які ідеї, як цього досягти?

ВИДАЛЕНО: Я успішно змінив подібні речі в іншому місці коду:

<style type="text/css">select#yaxis4 { height: 280px; width: 500px; }</style>
[... which links to this later on in the page...]
          <label class="control-label" for="yaxis4">Y-Axis</label>
          <select id="yaxis4" multiple="multiple">

І ось як це виглядає для тих, хто не працює:

<style type="text/css">select#xlimitsmax { display: inline-block; max-width: 50px; }</style>
[... which links to...]
          <label>x-max</label>
          <input id="xlimitsmax" type="text" value="0.5"/>

ВИДАЛЕНО:

Ось самостійний приклад ui.R, який не працює:

library(shiny)
shinyUI(
pageWithSidebar(
  # application title
  headerPanel("test01"),
  sidebarPanel(
    tags$head(
      tags$style(type="text/css", "select { max-width: 360px; }"),
      tags$style(type="text/css", ".span4 { max-width: 360px; }"),
      tags$style(type="text/css",  ".well { max-width: 360px; }")
              ),
    wellPanel(
      p(strong("Side Panel:"))
             )
   ),
  mainPanel(
    textInput(inputId="xlimitsmin", label="x-min", value = 0.0),
    tags$head(tags$style(type="text/css", "select#xlimitsmin { max-width: 50px }")),
    textInput(inputId="xlimitsmax", label="x-max", value = 0.5),
    tags$head(tags$style(type="text/css", "select#xlimitsmax { display: inline-block; max-width: 50px; }"))
    )
))

Підсумкова сторінка:

введіть тут опис зображення


Де в коді ваші <style>твердження? Якщо ви просто робите щось на зразок зміни кольору вибору, це працює?
Джон Павло

оператори стилю розподіляються у блискучому файлі ui.R і поміщаються в html head ( tags$head(tags$style(type="text/css", "select#something { height: 200px; width: 300px; }"))). Якщо я роблю щось подібне, все одно не працює:tags$head(tags$style(type="text/css", "select#xlimitsmin { max-width: 50px }"))
719016

Пінг! Щедрість за 6 годин - чи можете ви призначити когось?
Alex Brown,

1
У мене залишилось 16 годин? Я спробую відповіді завтра в офісі через 12 годин.
719016

Відповіді:


123

перефразовуючи (і спростивши випадок з 2 входами), ваша проблема полягає в тому, що:

runApp(list(
    ui = bootstrapPage(
        textInput(inputId="xlimitsmin", label="x-min", value = 0.0),
        textInput(inputId="xlimitsmax", label="x-max", value = 0.5)
    ),
    server = function(input, output) {}
))

показує

введіть тут опис зображення

Але вам потрібні паралельні невеликі входи, наприклад:

маленький ряд

Коротка відповідь

textInputRow<-function (inputId, label, value = "") 
{
    div(style="display:inline-block",
        tags$label(label, `for` = inputId), 
        tags$input(id = inputId, type = "text", value = value,class="input-small"))
}
runApp(list(
    ui = bootstrapPage(
        textInputRow(inputId="xlimitsmin", label="x-min", value = 0.0),
        textInputRow(inputId="xlimitsmax", label="x-max", value = 0.5)
    ),
    server = function(input, output) {}
))

дає:

введіть тут опис зображення

Довга відповідь

Паралельні входи

Давайте спочатку зробимо пліч-о-пліч:

В даний час textInput генерує два окремі теги - label, і input, кожен з яких налаштований CSS як display:block, що означає, що це прямокутник, який розіб'ється на лівій стороні контейнера. Нам потрібно обернути кожне textInputполе в новий контейнер (div) і повідомити цьому контейнеру, що контейнер, який слідує за ним (наступний textInput), може знаходитися в одному горизонтальному рядку на сторінці, використовуючи CSS display:inline-block.

Отже, ми додаємо div зі стилем навколо кожного textInput:

runApp(list(
    ui = bootstrapPage(
        div(style="display:inline-block",textInput(inputId="xlimitsmin", label="x-min", value = 0.0)),
        div(style="display:inline-block",textInput(inputId="xlimitsmax", label="x-max", value = 0.5))
    ),
    server = function(input, output) {}
))

рядок

Невеликі входи

Тепер давайте розберемося з дрібним. Є кілька способів зробити маленькі,

  1. зменшити шрифт,
  2. зробити так, щоб поле введення мало менше символів.
  3. скажіть css або (тут) bootstrap намалювати менший квадрат

Оскільки bootstrap.jsнасправді контролює макет, коли ми використовуємо блискучий, лише 3 надійно працюватимуть, тож давайте використаємо це.

Розміри вводу задокументовані в документації CSS Forms Bootstrap 2.3.2 у розділі "Керування розмірами" . Він включає різноманітні розміри від міні, малого, середнього, великого, великого та великого, і за замовчуванням, мабуть, середній. Давайте спробуємо маленький, замість цього.

Щоб встановити розмір, нам потрібно змінити клас inputтегу, згенерованого textInput.

Тепер textInputє лише функція зручності навколо більш потужних tagsфункцій, таких як tags$labelі tags$input. Ми можемо створити більш потужну версію, textInputяка дозволяє нам налаштовувати елементи, зокрема клас inputвузла:

textInput2<-function (inputId, label, value = "",...) 
{
    tagList(tags$label(label, `for` = inputId), tags$input(id = inputId, 
                                                           type = "text", value = value,...))
}
runApp(list(
    ui = bootstrapPage(
        div(style="display:inline-block",textInput2(inputId="xlimitsmin", label="x-min", value = 0.0, class="input-small")),
        div(style="display:inline-block",textInput2(inputId="xlimitsmax", label="x-max", value = 0.5, class="input-small"))
    ),
    server = function(input, output) {}
))

маленький ряд

І ми закінчили - але ми можемо згорнути частину цієї функціональності, створивши textInput3тег div. Це також може встановити клас самостійно, але я залишу це для вас.

Загортаючи його

textInput3<-function (inputId, label, value = "",...) 
{
    div(style="display:inline-block",
        tags$label(label, `for` = inputId), 
        tags$input(id = inputId, type = "text", value = value,...))
}
runApp(list(
    ui = bootstrapPage(
        textInput3(inputId="xlimitsmin", label="x-min", value = 0.0, class="input-small"),
        textInput3(inputId="xlimitsmax", label="x-max", value = 0.5, class="input-small")
    ),
    server = function(input, output) {}
))

Для інтересу, ось версія, що використовує клас input-mini:

введіть тут опис зображення


91

Використовуючи Shiny (> = 0,11), ви можете досягти цього, помістивши вхідні дзвінки в splitLayout () . Це розділить рядок рідини, коробку тощо на необхідні стовпці, необхідні для відображення полів вводу поруч.

У наведеному нижче прикладі ви отримаєте три введення тексту у полі, яке відображатиметься поруч у fluidRow.

fluidRow(
  box(width = 12, title = "A Box in a Fluid Row I want to Split", 
      splitLayout(
        textInput("inputA", "The first input"),
        textInput("inputB", "The second input"),
        textInput("inputC", "The third input")
      )
  )
)

17
+1, splitLayout також дозволяє налаштувати ширину кожної окремої комірки; splitLayout (cellWidths = c ("25%", "75%"), plotOutput ("plot1"), plotOutput ("plot2"))
ZN13

6
Це має бути прийнятою відповіддю зараз, це саме те, що було після ОП.
Джоріс Мейс,

5
А функція boxз shinydashboardпакету
needRhelp

Це набагато простіше прийнятої відповіді, дякую Надіре.
bob

40

Можливо, цього рішення не було в 2013 році, але якщо ви хочете зробити це без написання HTML або CSS, ви можете просто використовувати columnфункцію приблизно fluidRowтак:

  fluidRow(
    column(3,
    selectInput('pcat', 'Primary Category', c("ALL", "Some"))),
    column(3,
    selectInput('smodel', 'Statistical Model', c("NONE", "LINEAR REGRESSION", "LOWESS")))
  )

І це буде розміщувати речі поруч.

EDIT: Зараз є ще один дуже простий спосіб зробити це за допомогою splitLayout()функції. Докладніше див. У відповіді Надіра Сіді.


6
Дякую! Це врятувало мені великий головний біль, на щастя, я прокрутив відповіді вниз, це, швидше за все, найкращий спосіб зробити це.
Ніко

Мені це рішення теж подобається. splitLayout вводить смуги прокрутки, якщо у вас є меню, що випадає, що робить його для цього типу входів зовсім недостатнім. Але з колонкою це чудово працює!
JReddig

8

Я видалив стару відповідь - ось одна, яка працює:

ui.r:

library(shiny)
shinyUI(
  pageWithSidebar(
  # application title
  headerPanel("test01"),
  sidebarPanel(
     tags$head(
        tags$style(type="text/css", "select { max-width: 360px; }"),
        tags$style(type="text/css", ".span4 { max-width: 360px; }"),
        tags$style(type="text/css",  ".well { max-width: 360px; }")
      ),
     wellPanel(
        p(strong("Side Panel:"))
     )
  ),

 mainPanel(

    div(id="XXmin",textInput(inputId="xlimitsmin", label="x-min", value = 0.0)),
    tags$head(tags$style(type="text/css", "#XXmin {display: inline-block}")),
    tags$head(tags$style(type="text/css", "#xlimitsmin {max-width: 50px}")),

    div(id="XXmax",textInput(inputId="xlimitsmax", label="x-max", value = 0.5)),
    tags$head(tags$style(type="text/css", "#XXmax {display: inline-block}"),
    tags$head(tags$style(type="text/css", "#xlimitsmax {max-width: 50px}"))

  ))
))

Ось зміни, які я вніс:

1) Я виключив selectз select#xlimitsmaxі select#xlimitsminу ваших .cssзаявах

2) Я поставив ваші два елементи керування кожен у свій div()і дав їм імена XXminта XXmax. Потім я додав .cssтвердження, щоб зробити їх вбудованими.

Якщо у вас є кілька таких, ви можете використати classтвердження - наприклад:

div(class="MyClass",textInput(inputId="xlimitsmin", label="x-min", value = 0.0)),
tags$head(tags$style(type="text/css", ".MyClass {display: inline-block}")),
tags$head(tags$style(type="text/css", "#xlimitsmin {max-width: 50px}")),

тоді ви можете позначити кожен елемент керування div()як class="MyClass"і використовувати лише одне .cssтвердження.

Відредаговано, щоб додати: Дякуємо за розміщення прикладу коду - це значно полегшило.

2-е редагування: Просто для уточнення. Сенс введення textInputкоманд всередину a div()полягає у об’єднанні поля введення та його мітки в єдиний об’єкт, щоб displayможна було застосовувати стилі (в даному випадку стиль). Якщо ви цього не зробите, ярлик та поле виступають як дві окремі сутності, і в таких випадках важче маніпулювати ними.


8

Як альтернатива розміщенню детальних оголошень стилю в класі, здається, ви можете легко розширити функції блискучих тегів на свій смак. Цього конкретно було б зручно мати за замовчуванням. (це з блискучим блискучим_0.14.1). Думав, мені потрібно буде написати закриття, але це, здається, працює.

inline = function (x) {
tags$div(style="display:inline-block;", x)
}

inline(textInput(inputId="xlimitsmin", label="x-min", value = 0.0)),
inline(textInput(inputId="xlimitsmax", label="x-max", value = 0.5)),
inline(textInput(inputId="ylimitsmin", label="y-min", value = 0.5)),
inline(textInput(inputId="ylimitsmax", label="y-max", value = 1.0)),

Мені подобається ця відповідь, це може бути корисним для вирішення інших питань. Дякую
Йохан Роза

Насправді це був єдиний спосіб для мене позбутися небажаної горизонтальної смуги прокрутки. Дякую!
Brunox13

3

Я не був задоволений, splitLayout()оскільки він вводить смуги прокрутки, коли простір обмежений.

Я виявив, що, принаймні для віджетів введення, таких як кнопки або текстові поля, досить простим рішенням з кращою чутливою поведінкою є використання flex-box: (див. Цей чудовий посібник: https://css-tricks.com/snippets/css/a -guide-to-flexbox / )

div(
  style = "display: flex; flex-wrap: wrap;",
  div(
    style = "flex: 1;",
    textInput("inputA", "The first input")
  ),
  div(
    style = "flex: 1;",
    textInput("inputB", "The second input")
  ),
  div(
    style = "flex: 1;",
    textInput("inputC", "The third input")
  )
)

Є можливість регулювання відносної ширини. Відповідає splitLayout(cellWidths = c("25%", "75%"), ...):

div(
  style = "display: flex; flex-wrap: wrap;",
  div(
    style = "flex: 1;",
    textInput("inputA", "The first input")
  ),
  div(
    style = "flex: 3;", # second item 3 times as wide as first one
    textInput("inputB", "The second input")
  )
)

2

Якщо ви хочете вводити дані в mainPanel, ви можете використовувати наступне:

div(class="row-fluid",
  div(class="span1",textInput("xlimitsmin", label = "x-min", value = 0.0)), 
  div(class="span1",textInput("xlimitsmax", label = "x-max", value = 0.5)),
  div(class="span1",textInput("ylimitsmin", label = "y-min", value = 0.5)),
  div(class="span1",textInput("ylimitsmax", label = "y-max", value = 1.0))
)

Додати:

#xlimitsmin, #xlimitsmax, #ylimitsmin, #ylimitsmax { 
    max-width: 25px; 
}

у файлі css (наприклад, style.css у каталозі www /) у вашому додатку та завантажте його з ui.R за допомогою:

includeCSS ('www / style.R')

Я не впевнений, навіщо вам потрібен textInput, а не numericInput, оскільки введення, яке ви, здається, шукаєте, є числовим. Якщо ви вибрали numericInput, ви можете просто замінити textInput на numericInput у наведеному вище. Якщо ви хочете вводити дані у бічній панелі, ви можете скористатися наведеним нижче кодом. Потрібен буде той самий файл css, про який згадувалося вище.

div(class="row-fluid",
    div(class="span3",numericInput("xlimitsmin", label = "x-min", value = 0.0)), 
    div(class="span3",numericInput("xlimitsmax", label = "x-max", value = 0.5)),
    div(class="span3",numericInput("ylimitsmin", label = "y-min", value = 0.5)),
    div(class="span3",numericInput("ylimitsmax", label = "y-max", value = 1.0))
)

1

Підхід Сгрубсьйома був для мене майже ідеальним, проте я зіткнувся з новою проблемою підходу flex-box, оскільки між входами не було відступів. Очевидно, це має щось спільне з "display: flex", що є обгорткою для "flex-grow 1", яка використовує весь доступний простір. Я занурився в кролячу нору і не міг змусити це працювати, але дізнався про подібний підхід, який використовує "CSS - Grid" і є ще простішим (відповідне SO-питання, звідки я це дізнався) :

div(
  style = "display: grid; 
          grid-template-columns: 20% repeat(3, 20%); ## same as repeat(4, 20%)
          grid-gap: 10px;",

    textInput("inputA", "The first input"),

    textInput("inputB", "The second input"),

    textInput("inputC", "The third input"),

    textInput("inputD", "The fourth input")

)

Подібний чудовий посібник існує для підходу CSS - Grid, що знаходиться тут, де ви можете дізнатись про всі різні аргументи та настроюваність, які ви можете використовувати. Зверніть увагу, що я ніколи не торкався CSS за 2 години до написання цієї відповіді, тому будь-які виправлення вітаються =)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.