Skip to content

Commit

Permalink
updates for v0.1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
bruceyyu authored Oct 4, 2023
2 parents 9693870 + 56ff805 commit 4e06d3b
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 28 deletions.
6 changes: 3 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Package: GWalkR
Title: Interactive Exploratory Data Analysis Tool
Version: 0.1.2
Version: 0.1.3
Authors@R: c(
person("Yue", "Yu", , "yyubv@connect.ust.hk", role = c("aut", "cre"),
person("Yue", "Yu", , "yue.yu@connect.ust.hk", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-9302-0793")),
person("Kanaries Data Inc.", role = c("cph", "fnd")))
Maintainer: Yue Yu <yyubv@connect.ust.hk>
Maintainer: Yue Yu <yue.yu@connect.ust.hk>
Description: Simplify your R data analysis and data visualization workflow by turning your data frame into an interactive 'Tableau'-like interface, leveraging the 'graphic-walker' JavaScript library and the 'htmlwidgets' package.
License: Apache License (>= 2)
Encoding: UTF-8
Expand Down
12 changes: 10 additions & 2 deletions R/gwalkr.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#'
#' @param data A data frame to be visualized in the GWalkR. The data frame should not be empty.
#' @param lang A character string specifying the language for the widget. Possible values are "en" (default), "ja", "zh".
#' @param dark A character string specifying the dark mode preference. Possible values are "light" (default), "dark", "media".
#' @param columnSpecs An optional list of lists to manually specify the types of some columns in the data frame.
#' Each top level element in the list corresponds to a column, and the list assigned to each column should have
#' two elements: `analyticalType` and `semanticType`. `analyticalType` can
Expand All @@ -17,6 +18,7 @@
#' "age" = list(analyticalType = "measure", semanticType = "quantitative")
#' )}
#' @param visConfig An optional config string to reproduce your chart. You can copy the string by clicking "export config" button on the GWalkR interface.
#' @param visConfigFile An optional config file path to reproduce your chart. You can download the file by clicking "export config" button then "download" button on the GWalkR interface.
#'
#' @return An \code{htmlwidget} object that can be rendered in R environments
#'
Expand All @@ -25,19 +27,25 @@
#' gwalkr(mtcars)
#'
#' @export
gwalkr <- function(data, lang = "en", columnSpecs = list(), visConfig = NULL) {
gwalkr <- function(data, lang = "en", dark = "light", columnSpecs = list(), visConfig = NULL, visConfigFile = NULL) {
if (!is.data.frame(data)) stop("data must be a data frame")
if (!is.null(visConfig) && !is.null(visConfigFile)) stop("visConfig and visConfigFile are mutually exclusive")
lang <- match.arg(lang, choices = c("en", "ja", "zh"))

rawFields <- raw_fields(data, columnSpecs)
colnames(data) <- sapply(colnames(data), fname_encode)

if (!is.null(visConfigFile)) {
visConfig <- readLines(visConfigFile, warn=FALSE)
}
# forward options using x
x = list(
dataSource = jsonlite::toJSON(data),
rawFields = rawFields,
i18nLang = lang,
hideDataSourceConfig = TRUE,
visSpec = visConfig
visSpec = visConfig,
dark = dark
)

# create widget
Expand Down
13 changes: 12 additions & 1 deletion man/gwalkr.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion web_app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"@kanaries/graphic-walker": "^0.4.3",
"@kanaries/graphic-walker": "^0.4.13",
"@rollup/plugin-commonjs": "^25.0.2",
"@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-terser": "^0.4.3",
Expand Down
33 changes: 27 additions & 6 deletions web_app/src/components/codeExportModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react";
import Modal from "../modal";
import { observer } from "mobx-react-lite";
import DefaultButton from "../button/default";
import PrimaryButton from "../button/primary";

import type { IGlobalStore } from "@kanaries/graphic-walker/dist/store";

Expand All @@ -11,6 +12,20 @@ interface ICodeExport {
setOpen: (open: boolean) => void;
}

const downloadFile = (data: string) => {
const fileName = "config";
const json = data;
const blob = new Blob([json], { type: "application/json" });
const href = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = href;
link.download = fileName + ".json";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(href);
};

const CodeExport: React.FC<ICodeExport> = observer((props) => {
const [code, setCode] = useState<string>("");

Expand All @@ -31,11 +46,7 @@ const CodeExport: React.FC<ICodeExport> = observer((props) => {
<div className="dark:text-white">
<h1 className="mb-4 font-bold text-base">Config Export</h1>
<div className="text-sm max-h-64 overflow-auto w-full">
<code className="font-mono text-xs whitespace-nowrap w-full">
visConfig &lt;- '{code}'
<br />
gwalkr(data="name of your data frame", visConfig=visConfig)
</code>
<code className="font-mono text-xs whitespace-nowrap w-full">{code}</code>
</div>
<div className="mt-4 flex justify-start">
<DefaultButton
Expand All @@ -45,8 +56,18 @@ const CodeExport: React.FC<ICodeExport> = observer((props) => {
props.setOpen(false);
}}
/>
<PrimaryButton
text="Download"
className="mr-2 px-6"
onClick={() => {
downloadFile(code);
}}
/>{" "}
</div>
<div className="text-sm max-h-56 mt-4 text-left">
<div>Option 1: paste the config in your R code as a string and pass it to `visConfig` parameter.</div>
<div>Option 2: download the config file and pass the file path to `visConfigFile` parameter.</div>
</div>
<div className="text-sm max-h-56 mt-4 text-right">Please copy the R code above and paste it into your script.</div>
</div>
</Modal>
);
Expand Down
16 changes: 8 additions & 8 deletions web_app/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import type { IDataSetInfo, IMutField, IRow, IVisSpec } from "@kanaries/graphic-
import type { IStoInfo } from "@kanaries/graphic-walker/dist/utils/save";
import { getExportTool } from "./tools/exportTool";
import CodeExportModal from "./components/codeExportModal";
import { StyleSheetManager } from 'styled-components';
import tailwindStyle from 'tailwindcss/tailwind.css?inline'
import { StyleSheetManager } from "styled-components";
import tailwindStyle from "tailwindcss/tailwind.css?inline";

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const App: React.FC<IAppProps> = observer((propsIn) => {
Expand Down Expand Up @@ -39,7 +39,7 @@ const App: React.FC<IAppProps> = observer((propsIn) => {
},
],
specList,
} as IStoInfo)
} as IStoInfo);
}, 1);
} else {
storeRef?.current?.commonStore?.updateTempSTDDS({
Expand All @@ -49,10 +49,10 @@ const App: React.FC<IAppProps> = observer((propsIn) => {
} as IDataSetInfo);
storeRef?.current?.commonStore?.commitTempDS();
}
}
};

React.useEffect(() => {
setData(dataSource, props.rawFields)
setData(dataSource, props.rawFields);
}, []);

const exportTool = getExportTool(setExportOpen);
Expand All @@ -66,7 +66,7 @@ const App: React.FC<IAppProps> = observer((propsIn) => {
return (
<React.StrictMode>
<div className="h-full w-full overflow-y-scroll font-sans">
{/* <div style={{ height: "100%", width: "100%", overflowY: "scroll" }}> */}
{/* <div style={{ height: "100%", width: "100%", overflowY: "scroll" }}> */}
<CodeExportModal open={exportOpen} setOpen={setExportOpen} globalStore={storeRef} />
<GraphicWalker {...props} storeRef={storeRef} toolbar={toolbarConfig} />
</div>
Expand All @@ -77,10 +77,10 @@ const App: React.FC<IAppProps> = observer((propsIn) => {
const GWalker = (props: IAppProps, id: string) => {
const container = document.getElementById(id);
if (container) {
const shadowRoot = container.attachShadow({ mode: 'open' });
const shadowRoot = container.attachShadow({ mode: "open" });

// Add Tailwind CSS to the shadow root
const styleElement = document.createElement('style');
const styleElement = document.createElement("style");
styleElement.textContent = tailwindStyle;
shadowRoot.appendChild(styleElement);

Expand Down
4 changes: 2 additions & 2 deletions web_app/src/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IGWProps } from '@kanaries/graphic-walker/dist/App'
import type { IGWProps } from "@kanaries/graphic-walker/dist/App";

export interface IAppProps extends IGWProps {
id: string;
Expand All @@ -8,4 +8,4 @@ export interface IAppProps extends IGWProps {
env?: string;
needLoadDatas?: boolean;
specType?: string;
}
}
63 changes: 58 additions & 5 deletions web_app/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"

"@babel/runtime@^7.12.5":
version "7.22.15"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8"
integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==
dependencies:
regenerator-runtime "^0.14.0"

"@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.2", "@babel/runtime@^7.19.0", "@babel/runtime@^7.9.2":
version "7.22.6"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438"
Expand Down Expand Up @@ -481,17 +488,18 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"

"@kanaries/graphic-walker@^0.4.3":
version "0.4.3"
resolved "https://registry.npmmirror.com/@kanaries/graphic-walker/-/graphic-walker-0.4.3.tgz#e30e8a5ef85781433acadeada828726acf68fb27"
integrity sha512-r+c2bipTqlzPGckrYYNDbYmYi8DxBRJrjA4J1uNsckeb0d047ZT9cmQwqawtJPdxDpuxWnkFK7+oFYX6LcSRew==
"@kanaries/graphic-walker@^0.4.13":
version "0.4.13"
resolved "https://registry.npmmirror.com/@kanaries/graphic-walker/-/graphic-walker-0.4.13.tgz#a03d400f4774974454e1525a2e3a3d879e31eac6"
integrity sha512-8Mn8rQjAuGgnEDN60VgxAlV1aVMqjJ/UdbRdtQkaxwPKdSOQ+DTMoFu/uccFQUaotT77eWJMLIvc06l+R+mpRw==
dependencies:
"@headlessui/react" "^1.7.12"
"@heroicons/react" "^2.0.8"
"@kanaries/react-beautiful-dnd" "^0.0.3"
"@kanaries/web-data-loader" "^0.1.7"
"@tailwindcss/forms" "^0.5.4"
autoprefixer "^10.3.5"
canvas-size "^1.2.6"
d3-format "^3.1.0"
d3-scale "^4.0.2"
d3-time-format "^4.1.0"
Expand All @@ -505,6 +513,8 @@
postcss "^8.3.7"
postinstall-postinstall "^2.1.0"
re-resizable "^6.9.8"
react-dropzone "^14.2.3"
react-error-boundary "^4.0.11"
react-i18next "^11.18.6"
react-leaflet "^4.2.1"
react-shadow "^20.0.0"
Expand Down Expand Up @@ -872,6 +882,11 @@ array-union@^2.1.0:
resolved "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==

attr-accept@^2.2.2:
version "2.2.2"
resolved "https://registry.npmmirror.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b"
integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==

autoprefixer@^10.3.5, autoprefixer@^10.4.14:
version "10.4.14"
resolved "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d"
Expand Down Expand Up @@ -962,6 +977,11 @@ caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001503:
resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001514.tgz#e2a7e184a23affc9367b7c8d734e7ec4628c1309"
integrity sha512-ENcIpYBmwAAOm/V2cXgM7rZUrKKaqisZl4ZAI520FIkqGXUxJjmaIssbRW5HVVR5tyV6ygTLIm15aU8LUmQSaQ==

canvas-size@^1.2.6:
version "1.2.6"
resolved "https://registry.npmmirror.com/canvas-size/-/canvas-size-1.2.6.tgz#1eaa6b56167cf2a70fa4021680829d2073b45706"
integrity sha512-x2iVHOrZ5x9V0Hwx6kBz+Yxf/VCAII+jrD6WLjJbytJLozHq/oDJjEva432Os0eHxWMFR0vYlLJwTr6QxyxQqw==

chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
Expand Down Expand Up @@ -1496,6 +1516,13 @@ file-entry-cache@^6.0.1:
dependencies:
flat-cache "^3.0.4"

file-selector@^0.6.0:
version "0.6.0"
resolved "https://registry.npmmirror.com/file-selector/-/file-selector-0.6.0.tgz#fa0a8d9007b829504db4d07dd4de0310b65287dc"
integrity sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==
dependencies:
tslib "^2.4.0"

fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
Expand Down Expand Up @@ -2168,7 +2195,7 @@ prelude-ls@^1.2.1:
resolved "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==

prop-types@^15.7.2:
prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
Expand Down Expand Up @@ -2212,6 +2239,22 @@ react-dom@^18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"

react-dropzone@^14.2.3:
version "14.2.3"
resolved "https://registry.npmmirror.com/react-dropzone/-/react-dropzone-14.2.3.tgz#0acab68308fda2d54d1273a1e626264e13d4e84b"
integrity sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==
dependencies:
attr-accept "^2.2.2"
file-selector "^0.6.0"
prop-types "^15.8.1"

react-error-boundary@^4.0.11:
version "4.0.11"
resolved "https://registry.npmmirror.com/react-error-boundary/-/react-error-boundary-4.0.11.tgz#36bf44de7746714725a814630282fee83a7c9a1c"
integrity sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==
dependencies:
"@babel/runtime" "^7.12.5"

react-i18next@^11.18.6:
version "11.18.6"
resolved "https://registry.npmmirror.com/react-i18next/-/react-i18next-11.18.6.tgz#e159c2960c718c1314f1e8fcaa282d1c8b167887"
Expand Down Expand Up @@ -2294,6 +2337,11 @@ regenerator-runtime@^0.13.11:
resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==

regenerator-runtime@^0.14.0:
version "0.14.0"
resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==

require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
Expand Down Expand Up @@ -2638,6 +2686,11 @@ tslib@^2.1.0, tslib@^2.5.0:
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3"
integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==

tslib@^2.4.0:
version "2.6.2"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==

tslib@~2.5.0:
version "2.5.3"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913"
Expand Down

0 comments on commit 4e06d3b

Please sign in to comment.