Giter VIP home page Giter VIP logo

fxl's Introduction

fxl (/ˈfɪk.səl/ or "pixel" with an f) is a Clojure library for manipulating spreadsheets.

Continuous Integration Code Coverage Clojars Project

WARNING! This library is still unstable. Some information here may be outdated. Do not use it in production just yet!

See docjure and excel-clj for more mature alternatives.

Introduction

The goal of the project is to provide a composable data-oriented spreadsheet interface for Clojure. The library is written with simplicity in mind - particularly as discussed in Rich Hickey's talk Simplicity Matters on the list-and-order problem.

If order matters, complexity has been introduced to the system

Rich Hickey, Simplicity Matters

What fxl attempts to do differently to docjure and excel-clj is to represent spreadsheets as an unordered collection of maps, instead of relying on tabular formats. This makes it easier to deal with independent, smaller components of the spreadsheet and simply apply concat to put together different components of a spreadsheet.

cljdoc slack zulip

Examples

Map Representation of Cells

A fxl cell is represented by a map that tells us its value, location and style. For instance:

{:value -2.2
 :coord {:row 4 :col 3 :sheet "Growth"}
 :style {:data-format "0.00%" :background-colour :yellow}}

is rendered as a highlighted cell with a value of "-2.2%" on the fifth row and fourth column of a sheet called "Growth".

By knowing cells, you know almost all of fxl! The rest of the library is composed of IO functions such as read-xlsx! and write-xlsx! and helper functions to transform Clojure data structures into cell maps.

To find out more about the available styles, see their specs.

Creating Simple Spreadsheets with Builtin Clojure

Suppose we would like to create a spreadsheet such as the following:

| Item     | Cost     |
| -------- | -------- |
| Rent     | 1000     |
| Gas      | 100      |
| Food     | 300      |
| Gym      | 50       |
|          |          |
| Total    | 1450     |

Assume that we have the cost data in the following form:

(def costs
  [{:item "Rent" :cost 1000}
   {:item "Gas"  :cost 100}
   {:item "Food" :cost 300}
   {:item "Gym"  :cost 50}])

We would break the spreadsheet down into three components, namely the header, the body and the total:

(require '[zero-one.fxl.core :as fxl])

(def header-cells
  [{:value "Item" :coord {:row 0 :col 0} :style {}}
   {:value "Cost" :coord {:row 0 :col 1} :style {}}])

(def body-cells
  (flatten
    (for [[row cost] (map vector (range) costs)]
      (list
        {:value (:item cost) :coord {:row (inc row) :col 0} :style {}}
        {:value (:cost cost) :coord {:row (inc row) :col 1} :style {}}))))

(def total-cells
  (let [row        (count costs)
        total-cost (apply + (map :cost costs))]
    [{:value "Total"    :coord {:row (+ row 2) :col 0} :style {}}
     {:value total-cost :coord {:row (+ row 2) :col 1} :style {}}]))

(fxl/write-xlsx!
  (concat header-cells body-cells total-cells)
  "examples/spreadsheets/write_to_plain_excel.xlsx")

In fact, style is optional, so we can actually remove :style {} from all the maps.

While both these methods work, dealing with the coordinates can be fiddly. We can make the intent clearer using fxl helper functions.

Creating Simple Spreadsheets with Helper Functions

Here we use row->cells, table->cells, pad-below and concat-below to help us initialise and navigate relative coordinates.

(def header-cells (fxl/row->cells ["Item" "Cost"]))

(def body-cells
  (fxl/records->cells [:item :cost] costs))

(def total-cells
  (let [total-cost (apply + (map :cost costs))]
    (fxl/row->cells ["Total" total-cost])))

(fxl/write-xlsx!
  (fxl/concat-below header-cells
                    (fxl/pad-below body-cells)
                    total-cells)
  "examples/spreadsheets/write_to_plain_excel_with_helpers.xlsx")

More helper functions are available - see here.

Modular Styling

With a Clojure-map representation for cells, manipulating the spreadsheet is easy using built-in functions. Suppose we would like to:

  1. highlight the header row and make it bold
  2. make the total row bold
  3. horizontally align all cells to the center

We can achieve this by composing simple styling functions:

(defn bold [cell]
  (assoc-in cell [:style :bold] true))

(defn highlight [cell]
  (assoc-in cell [:style :background-colour] :grey_25_percent))

(defn align-center [cell]
  (assoc-in cell [:style :horizontal] :center))

(def all-cells
  (map align-center
    (fxl/concat-below
      (map (comp bold highlight) header-cells)
      (fxl/pad-below body-cells)
      (map bold total-cells))))

Installation

Add the following to your project.clj dependency:

Clojars Project

Future Work

Features:

  • Core:
    • Column width and row heights.
    • Freezing panes.
    • Excel coords -> index coords.
    • Support merged cells.
    • Support data-val cells.
  • Support to Google Sheet API.
  • Error handling with failjure.
  • Property-based testing.

License

Copyright 2020 Zero One Group.

fxl is licensed under Apache License v2.0.

fxl's People

Contributors

anthony-khong avatar burinc avatar ivokun avatar zackteo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

fxl's Issues

Undetected background-colour (support xslx created outside of fxl)

;; TODO: background-colour seems to be undetected!

Based on some tests, it seems that the colours in the test/resources/dummy-spreadsheet.xslx are incompatible with .getFillForegroundColor. Colours are however read correctly from files generated with fxl.

This might be a limitation of org.apache.poi.xssf.usermodel? Have to see how dummy-spreadsheet.xslx was created. Proprietary excel issues?

Support more data formats?

This was another data format from reading the previous dummy-spreadsheet.xslx but seems like 0.00 does exactly this already. Not sure what is different per se

"0.00_ ;\\-0.00\\ "

tmd dataset to fxl->cells

I see an opportunity to shape a dataset into fxl cells. Would the project take on tech.ml.dataset as a dependency? Perhaps it's best as a utility namespace or other library.

New dummy-spreadsheet.xslx for testing (particularly for colour)

Due to #15, a good current solution is to produce a new test/resources/dummy-spreadsheet.xslx from within fxl. This allows the colours to be read in and tested.

Based on the specifications to support formula cells in #18. I have done a tracer bullet to create a replica of the dummy-spreadsheet.xslx.

The only part which I am unable to replicate as of now is cell decimal place formatting - such that 2.4247 only appears with 2 d.p. 2.42. This however, does not seem to be supported in fxl as of now anyway, so it seems like it could be ignored for now

Create test for prune-cell-style

Previous was implied by (fact "Font style should be preserved") by removal of font-size 11 since it was a default
but have since changed it as the default font size was changed in 3979812 .

And I think a separate test would reflect better clarity

Font size not being preserved for :font-size 12

If you read and write and read a file, the font size will be converted from 12 to 11 (Microsoft Office Excel 2007 uses the Calibri font in font size 11 - https://poi.apache.org/apidocs/dev/org/apache/poi/xssf/usermodel/XSSFFont.html#getFontHeightInPoints--)

Because of prune-cell-style and the :font-size 12 doesn't get added in the read-xlsx!. Thus, when you do a read then write, the lack of font-size will change to the apache poi default of 11.

In this case since the true default is 11, should we just change fxl's font-size default from 12 to 11 - if we are keeping prune-cell-style?

Support Formula cells

I propose we change the spec of a cell to

(s/def ::cell
  (s/keys :req-un [::value ::coord ::style ::formula]))

this seems like it would be inline with the underlining Apache POI (Java API)
https://poi.apache.org/apidocs/4.1/org/apache/poi/ss/usermodel/CellBase.html#setCellFormula-java.lang.String-
as setCellFormula and setCellValue are on the same level

This seems to be the simpler implementation, as the underlying logic of the code does not really change. It will just be an inclusion of :formula nil in the hashmap

We will however need to make changes to

  • core.clj (helper functions

  • spec.clj (include ::formula definition and add to ::cell)

  • defaults.clj (add :formula to be included in defaults

  • read_xlsx.clj

  • write_xlsx.clj

  • many tests

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.